Here is my synthdef:
(
// Create a global audio bus for mixing all synths together
~mainBus = Bus.audio(s, 2); // Stereo bus (2 channels)
SynthDef(\squareSynthWithResonantFilter, {
|outBus, freq = 440, filterStartFreq = 1000, filterEndFreq = 200, filterResonance = 0.1, amp = 0.2, sustain = 0.5, attack = 0.01, release = 0.5, gate = 1|
var squareWave, ampEnv, filterEnv, filteredSignal, ampEnvGen, filterEnvGen;
squareWave = Pulse.ar(freq, 0.5);
ampEnv = Env.adsr(attack, 0.1, sustain, release);
ampEnvGen = EnvGen.kr(ampEnv, gate, doneAction: 2);
filterEnv = Env.adsr(attack, 0.1, sustain, release);
filterEnvGen = EnvGen.kr(filterEnv, gate);
filteredSignal = RLPF.ar(squareWave, filterEnvGen.linexp(0, 1, filterStartFreq, filterEndFreq), filterResonance);
Out.ar(outBus, [filteredSignal, filteredSignal] * ampEnvGen * amp);
}).add;
)
I expected my code to play a chord and then release the notes after 2 seconds.
// Routine to play the composition with simultaneous press and release
(
{
var melody = [
[440, 2000, 300, 0.9], // freq, filterStartFreq, filterEndFreq, filterResonance
[523.25, 1500, 500, 0.6],
[392, 2500, 400, 0.8],
[349.23, 1000, 300, 0.5],
[659.25, 2200, 200, 0.9],
[447, 1800, 300, 0.4]
];
var synths = [];
// here array.do works as expected
melody.do { |note|
var synth = Synth(\squareSynthWithResonantFilter, [
\outBus, ~mainBus, // Send to global bus
\freq, note[0],
\filterStartFreq, note[1],
\filterEndFreq, note[2],
\filterResonance, note[3],
\amp, 0.3, // fixed amplitude
\sustain, 1.2,
\attack, 0.02,
\release, 1.0,
\gate, 1 // Start with gate open
]);
synths.add(synth); // Store the synths for later release
"Created synth with ID: %".format(synth.nodeID).postln; // Debugging
};
2.wait; // Hold all notes for 2 seconds
// Release all notes together
synths.do { |synth|
synth.set(\gate, 0); // This only works on one of the notes
"Setting gate to 0 for synth: %".format(synth.nodeID).postln;
};
}.fork;
)
I wonder if this issue has something to do with the bus or limiter? Probably not.
// Apply global limiter to the mixed signal on the bus and send to main audio output
(
{
var busSignal = In.ar(~mainBus, 2); // Read from the global bus
var limitedSignal = Limiter.ar(busSignal, 0.9); // Apply limiter to the combined signal
Out.ar(0, limitedSignal); // Output the limited signal to speakers (stereo out)
}.play;
)
The console output is this:
Created synth with ID: 1013
Created synth with ID: 1014
Created synth with ID: 1015
Created synth with ID: 1016
Created synth with ID: 1017
Created synth with ID: 1018
Setting gate to 0 for synth: 1013
indicating that only the first synth has its gate set to 0.
the issue is not with the iteration, but with the population of the synths
array.
the line
var synths = [];
creates a new object of class Array
, as can be verified by inspecting synths.class
. Array
is a fixed-capacity collection, and its .add
method has some unusual behavior; from the helpfile:
Adds an item to an ArrayedCollection if there is space. This method may return a new ArrayedCollection. For this reason, you should always assign the result of add to a variable - never depend on add changing the receiver.
so your code can be made to work as expected by changing this line:
synths.add(synth); // this returns a new array with the new item added;
// but the result is discarded
to:
synths = synths.add(synth);
Alternatively, you could initialize synths
as a List
rather than an Array
, the former being extensible by design.