Skip to content

Commit f5c0088

Browse files
committed
Working Ensemble
Co-authored-by: <Marc-Andre Weibezahn> contact@maweibezahn.com
1 parent 6e81d84 commit f5c0088

File tree

4 files changed

+43
-21
lines changed

4 files changed

+43
-21
lines changed

Sources/CSoundpipeAudioKit/Effects/EnsembleDSP.mm

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
EnsembleParameterPan7,
2424
EnsembleParameterPan8,
2525
EnsembleParameterPan9,
26+
EnsembleParameterNumberOfVoices,
2627
EnsembleParameterDryWetMix
2728
};
2829

@@ -37,6 +38,7 @@
3738

3839
ParameterRamper shiftRamps[9];
3940
ParameterRamper panRamps[9];
41+
ParameterRamper numberOfVoicesRamp;
4042
ParameterRamper dryWetMixRamp;
4143

4244
public:
@@ -59,6 +61,7 @@
5961
parameters[EnsembleParameterPan7] = &panRamps[6];
6062
parameters[EnsembleParameterPan8] = &panRamps[7];
6163
parameters[EnsembleParameterPan9] = &panRamps[8];
64+
parameters[EnsembleParameterNumberOfVoices] = &numberOfVoicesRamp;
6265
parameters[EnsembleParameterDryWetMix] = &dryWetMixRamp;
6366
}
6467

@@ -112,15 +115,19 @@ void reset() override {
112115
void process(FrameRange range) override {
113116
for (int i : range) {
114117
float dryWetMix = dryWetMixRamp.getAndStep();
118+
int numVoices = (int)numberOfVoicesRamp.getAndStep();
119+
120+
// Clamp number of voices between 1 and 9
121+
numVoices = std::max(1, std::min(9, numVoices));
115122

116123
float leftIn = inputSample(0, i);
117124
float rightIn = inputSample(1, i);
118125

119126
float leftSum = 0.0f;
120127
float rightSum = 0.0f;
121128

122-
// Process through all 9 pitch shifters
123-
for (int voice = 0; voice < 9; voice++) {
129+
// Process through the specified number of pitch shifters
130+
for (int voice = 0; voice < numVoices; voice++) {
124131
float shift = shiftRamps[voice].getAndStep();
125132
float pan = panRamps[voice].getAndStep();
126133

@@ -139,9 +146,9 @@ void process(FrameRange range) override {
139146
float pannedLeft, pannedRight;
140147
sp_panst_compute(sp, panst[voice], &leftOut, &rightOut, &pannedLeft, &pannedRight);
141148

142-
// Add to sum with appropriate gain (divide by 9 to prevent clipping)
143-
leftSum += pannedLeft / 9.0f;
144-
rightSum += pannedRight / 9.0f;
149+
// Add to sum with appropriate gain (divide by numVoices to prevent clipping)
150+
leftSum += pannedLeft / numVoices;
151+
rightSum += pannedRight / numVoices;
145152
}
146153

147154
// Apply dry/wet mix
@@ -170,4 +177,5 @@ void process(FrameRange range) override {
170177
AK_REGISTER_PARAMETER(EnsembleParameterPan7)
171178
AK_REGISTER_PARAMETER(EnsembleParameterPan8)
172179
AK_REGISTER_PARAMETER(EnsembleParameterPan9)
180+
AK_REGISTER_PARAMETER(EnsembleParameterNumberOfVoices)
173181
AK_REGISTER_PARAMETER(EnsembleParameterDryWetMix)

Sources/SoundpipeAudioKit/Effects/Ensemble.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,19 @@ public class Ensemble: Node {
252252
/// Pan position 9 (-1 = left, 0 = center, 1 = right)
253253
@Parameter(pan9Def) public var pan9: AUValue
254254

255+
/// Specification details for numberOfVoices
256+
public static let numberOfVoicesDef = NodeParameterDef(
257+
identifier: "numberOfVoices",
258+
name: "Number of Voices",
259+
address: akGetParameterAddress("EnsembleParameterNumberOfVoices"),
260+
defaultValue: 1,
261+
range: 1.0 ... 9.0,
262+
unit: .generic
263+
)
264+
265+
/// Number of voices to use (1-9)
266+
@Parameter(numberOfVoicesDef) public var numberOfVoices: AUValue
267+
255268
/// Specification details for dryWetMix
256269
public static let dryWetMixDef = NodeParameterDef(
257270
identifier: "dryWetMix",
@@ -307,6 +320,9 @@ public class Ensemble: Node {
307320
self.pan8 = pans.count > 7 ? pans[7] : Self.pan8Def.defaultValue
308321
self.pan9 = pans.count > 8 ? pans[8] : Self.pan9Def.defaultValue
309322

323+
// Set number of voices based on the shifts array length, clamped to 1-9
324+
self.numberOfVoices = AUValue(max(1, min(9, shifts.count)))
325+
310326
self.dryWetMix = dryWetMix
311327
}
312328
}

Tests/SoundpipeAudioKitTests/Effects Tests/EnsembleTests.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ class EnsembleTests: XCTestCase {
88

99
func testMajorChord() {
1010
let engine = AudioEngine()
11-
let input = Oscillator()
11+
let url = Bundle.module.url(forResource: "12345", withExtension: "wav", subdirectory: "TestResources")!
12+
let input = AudioPlayer(url: url)!
1213
// Create a C major chord: C, E, G (0, 4, 7 semitones)
1314
let ensemble = Ensemble(input,
14-
shifts:[0, 7],
15+
shifts:[0, 4, 7], pans: [-1, 1],
1516
dryWetMix: 1.0)
16-
ensemble.$shift2.ramp(to: 7, duration: 10.0)
17+
ensemble.$shift2.ramp(to: 12, duration: 5.0)
18+
ensemble.$pan2.ramp(to: -1, duration: 5.0)
1719
engine.output = ensemble
18-
input.start()
19-
let audio = engine.startTest(totalDuration: 10.0)
20-
audio.append(engine.render(duration: 10.0))
20+
let audio = engine.startTest(totalDuration: 5.0)
21+
input.play()
22+
audio.append(engine.render(duration: 5.0))
2123
audio.audition()
2224
}
2325
}

Tests/SoundpipeAudioKitTests/Effects Tests/PitchShifterTests.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,15 @@ import SoundpipeAudioKit
55
import XCTest
66

77
class PitchShifterTests: XCTestCase {
8-
func testResetPitchShifter() {
8+
func testPitchShifter() {
99
let engine = AudioEngine()
10-
let input = Oscillator(waveform: Table([1, 1]))
10+
let input = Oscillator()
1111
let shifter = PitchShifter(input)
12-
engine.output = shifter
12+
shifter.shift = 7
13+
engine.output = Mixer(input, shifter)
1314
input.start()
14-
let audio = engine.startTest(totalDuration: 2.0)
15+
let audio = engine.startTest(totalDuration: 1.0)
1516
audio.append(engine.render(duration: 1.0))
16-
XCTAssertEqual(audio.toFloatChannelData()?[0].count, 44100)
17-
18-
shifter.reset()
19-
audio.append(engine.render(duration: 1.0))
20-
21-
XCTAssertEqual(audio.toFloatChannelData()?[0].count, 88200)
17+
audio.audition()
2218
}
2319
}

0 commit comments

Comments
 (0)