Hi,
I am trying to pan a synth at a set of channels and be able to set the Out bus argument differently at each iteration of the synth. The problem is when the panning starts e.g. at channel 1 and I want a concrete set of [0,1,2,3] output buses, expansion happens at [1,2,3,4].
How can I keep the expansion on a concrete array of output channels?
I don’t quite understand what your trying to do/what the issue is. Could you post a minimal code example that demonstrates the behaviour you don’t want?
Out
behaves somewhat differently with expansion than other SynthDefs - to get the result you want, it’s probably easiest to just specify several single-channel Out
’s by hand:
SynthDef(\out, {
var sig, out;
sig = WhiteNoise.ar([1, 1, 1, 1])
out = \out.kr(0);
sig.do {
|subSig, index|
Out.ar(out + index, subSig);
}
}).add
Thank you for the reply,
I am using already a panned signal with Pan4 which has no orientation argument like other panning objects e.g. PanAz. The synth is controlled by MIDI (keyboard) and the sound characteristics (reverb) are created quadraphonicly in the .do additive synthesis (code below).
The thing I want to achieve is to be able to trigger a random argument for the bus of Out without expanding on the rest of the channels as mentioned above (previous entry). The behavior right now is that if I set 8 output channels (0,1,2,3,4,5,6,7) the possible starting positions are (0,1,2,3). I would like to be able to do that inside the quadraphony without going overboard with the channels i.g. (1,0,2,3).
(
s.options.numWireBufs = 1024*16;
s.options.numOutputBusChannels=8;
s.options.numInputBusChannels=0;
s.options.memSize = 8192*8;
s.waitForBoot;
s.scope;
s.meter;
(
SynthDef.new(\oa, {
arg rotation1=1,rotation2=1,rotation3=1,rotation4=1,rotation5=1,rotation6=1,rotation7=1,rotation8=1, n=1, cutt=496, out=0;
var frequency=8,detune1,detune2,detune3;
var osc1,osc2,osc3,osc4;
var freq1,freq2,env;
var bank, angle1,angle2;
var pitch,m=0,over=1;
frequency=1;
bank=4;
angle1=0;
angle2=90;
pitch=2.pow(n/12);
freq1 =(((4*8)-1)*((4*8)/2));
freq1=freq1/3;
freq2 =(((4*8)-1)*((4*8)/2));
freq2=freq2/2;
rotation1=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation2=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation3=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation4=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation5=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation6=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation7=TExpRand.ar(0.1,10,Dust.ar(0.1));
rotation8=TExpRand.ar(0.1,10,Dust.ar(0.1));
env=EnvGen.ar(Env.perc(0.01,3,pitch.reciprocal*0.5),doneAction:2);
bank.do{
angle1=(angle1+(360-(360/1.61803398874989484820458683436563811772030917980576))).wrap(0,360);
detune1=exp(Complex(0,1)*angle1);
angle2=(angle2+(360-(360/1.61803398874989484820458683436563811772030917980576))).wrap(0,360);
detune2=exp(Complex(0,1)*angle2);
osc1=Pan4.ar(SinOsc.ar((freq1*over)*pitch,mul:over.reciprocal,phase:detune1.theta),SinOsc.ar(rotation1*detune1.real,phase:detune1.theta),SinOsc.ar(rotation3*detune1.imag,phase:detune1.theta));
osc2=Pan4.ar(SinOsc.ar((freq1*over)*pitch,mul:over.reciprocal,phase:detune2.theta),SinOsc.ar(rotation2*detune2.real,phase:detune2.theta),SinOsc.ar(rotation4*detune2.imag,phase:detune2.theta));
osc3=Pan4.ar(SinOsc.ar((freq2*over)*pitch,mul:over.reciprocal,phase:detune1.theta),SinOsc.ar(rotation5*detune1.real,phase:detune1.theta),SinOsc.ar(rotation6*detune1.imag,phase:detune1.theta));
osc4=Pan4.ar(SinOsc.ar((freq2*over)*pitch,mul:over.reciprocal,phase:detune2.theta),SinOsc.ar(rotation7*detune2.real,phase:detune2.theta),SinOsc.ar(rotation8*detune2.imag,phase:detune2.theta));
Out.ar(out,LeakDC.ar(LPF.ar(osc1*env*(2/3),cutt)));
Out.ar(out,LeakDC.ar(LPF.ar(osc2*env*(2/3),cutt)));
Out.ar(out,LeakDC.ar(LPF.ar(osc3*env*(1/2),cutt)));
Out.ar(out,LeakDC.ar(LPF.ar(osc4*env*(1/2),cutt)));
m = m+1;
over = over + (m+1)/1;
};
}).add;
);
MIDIClient.init;
MIDIIn.connectAll;
MIDIdef.noteOn(\synhtone,{|val,num,chan,src|[val,num,chan,src].postln;
if( num==36,{Synth.new(\oa,[\n,13.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==37,{Synth.new(\oa,[\n,12.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==38,{Synth.new(\oa,[\n,11.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==39,{Synth.new(\oa,[\n,10.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==40,{Synth.new(\oa,[\n,9.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==41,{Synth.new(\oa,[\n,8.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==42,{Synth.new(\oa,[\n,7.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==43,{Synth.new(\oa,[\n,6.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==44,{Synth.new(\oa,[\n,5.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==45,{Synth.new(\oa,[\n,4.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==46,{Synth.new(\oa,[\n,3.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==47,{Synth.new(\oa,[\n,2.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==48,{Synth.new(\oa,[\n,1.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==49,{Synth.new(\oa,[\n,1,\out,Array.rand(4, 0, 3).choose])});
if( num==50,{Synth.new(\oa,[\n,2,\out,Array.rand(4, 0, 3).choose])});
if( num==51,{Synth.new(\oa,[\n,3,\out,Array.rand(4, 0, 3).choose])});
if( num==52,{Synth.new(\oa,[\n,4,\out,Array.rand(4, 0, 3).choose])});
if( num==53,{Synth.new(\oa,[\n,5,\out,Array.rand(4, 0, 3).choose])});
if( num==54,{Synth.new(\oa,[\n,6,\out,Array.rand(4, 0, 3).choose])});
if( num==55,{Synth.new(\oa,[\n,7,\out,Array.rand(4, 0, 3).choose])});
if( num==56,{Synth.new(\oa,[\n,8,\out,Array.rand(4, 0, 3).choose])});
if( num==57,{Synth.new(\oa,[\n,9,\out,Array.rand(4, 0, 3).choose])});
if( num==58,{Synth.new(\oa,[\n,10,\out,Array.rand(4, 0, 3).choose])});
if( num==59,{Synth.new(\oa,[\n,11,\out,Array.rand(4, 0, 3).choose])});
if( num==60,{Synth.new(\oa,[\n,12,\out,Array.rand(4, 0, 3).choose])});
if( num==61,{Synth.new(\oa,[\n,13,\out,Array.rand(4, 0, 3).choose])});
if( num==62,{Synth.new(\oa,[\n,14,\out,Array.rand(4, 0, 3).choose])});
if( num==63,{Synth.new(\oa,[\n,15,\out,Array.rand(4, 0, 3).choose])});
if( num==64,{Synth.new(\oa,[\n,16,\out,Array.rand(4, 0, 3).choose])});
if( num==65,{Synth.new(\oa,[\n,17,\out,Array.rand(4, 0, 3).choose])});
if( num==66,{Synth.new(\oa,[\n,18,\out,Array.rand(4, 0, 3).choose])});
if( num==67,{Synth.new(\oa,[\n,19,\out,Array.rand(4, 0, 3).choose])});
if( num==68,{Synth.new(\oa,[\n,20,\out,Array.rand(4, 0, 3).choose])});
if( num==69,{Synth.new(\oa,[\n,21,\out,Array.rand(4, 0, 3).choose])});
if( num==70,{Synth.new(\oa,[\n,22,\out,Array.rand(4, 0, 3).choose])});
if( num==71,{Synth.new(\oa,[\n,23,\out,Array.rand(4, 0, 3).choose])});
if( num==72,{Synth.new(\oa,[\n,24,\out,Array.rand(4, 0, 3).choose])});
if( num==73,{Synth.new(\oa,[\n,25,\out,Array.rand(4, 0, 3).choose])});
if( num==74,{Synth.new(\oa,[\n,26,\out,Array.rand(4, 0, 3).choose])});
if( num==75,{Synth.new(\oa,[\n,27,\out,Array.rand(4, 0, 3).choose])});
if( num==76,{Synth.new(\oa,[\n,28,\out,Array.rand(4, 0, 3).choose])});
if( num==77,{Synth.new(\oa,[\n,29,\out,Array.rand(4, 0, 3).choose])});
if( num==78,{Synth.new(\oa,[\n,30,\out,Array.rand(4, 0, 3).choose])});
if( num==79,{Synth.new(\oa,[\n,31,\out,Array.rand(4, 0, 3).choose])});
if( num==80,{Synth.new(\oa,[\n,32,\out,Array.rand(4, 0, 3).choose])});
if( num==81,{Synth.new(\oa,[\n,33,\out,Array.rand(4, 0, 3).choose])});
if( num==82,{Synth.new(\oa,[\n,34,\out,Array.rand(4, 0, 3).choose])});
if( num==83,{Synth.new(\oa,[\n,35,\out,Array.rand(4, 0, 3).choose])});
if( num==84,{Synth.new(\oa,[\n,36,\out,Array.rand(4, 0, 3).choose])});
if( num==85,{Synth.new(\oa,[\n,37,\out,Array.rand(4, 0, 3).choose])});
if( num==86,{Synth.new(\oa,[\n,38,\out,Array.rand(4, 0, 3).choose])});
if( num==87,{Synth.new(\oa,[\n,39,\out,Array.rand(4, 0, 3).choose])});
if( num==88,{Synth.new(\oa,[\n,40,\out,Array.rand(4, 0, 3).choose])});
if( num==89,{Synth.new(\oa,[\n,41,\out,Array.rand(4, 0, 3).choose])});
if( num==90,{Synth.new(\oa,[\n,42,\out,Array.rand(4, 0, 3).choose])});
if( num==91,{Synth.new(\oa,[\n,43,\out,Array.rand(4, 0, 3).choose])});
if( num==92,{Synth.new(\oa,[\n,44,\out,Array.rand(4, 0, 3).choose])});
if( num==93,{Synth.new(\oa,[\n,45,\out,Array.rand(4, 0, 3).choose])});
if( num==94,{Synth.new(\oa,[\n,46,\out,Array.rand(4, 0, 3).choose])});
if( num==95,{Synth.new(\oa,[\n,47,\out,Array.rand(4, 0, 3).choose])});
if( num==96,{Synth.new(\oa,[\n,48,\out,Array.rand(4, 0, 3).choose])});
})
)
Sorry, that’s not a minimal example.
If I understand what you’re after, can just specify the channels you want out as an argument.
\\ in the synth
\out.kr([0,1,2,3])
\\ creation
Synth(..., [\out, 4,3,0,1])
I’d suggest
Synth(\oa,[\n, num - 49, \out, 3.rand])
in place of
if( num==36,{Synth.new(\oa,[\n,13.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==37,{Synth.new(\oa,[\n,12.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==38,{Synth.new(\oa,[\n,11.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==39,{Synth.new(\oa,[\n,10.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==40,{Synth.new(\oa,[\n,9.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==41,{Synth.new(\oa,[\n,8.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==42,{Synth.new(\oa,[\n,7.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==43,{Synth.new(\oa,[\n,6.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==44,{Synth.new(\oa,[\n,5.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==45,{Synth.new(\oa,[\n,4.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==46,{Synth.new(\oa,[\n,3.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==47,{Synth.new(\oa,[\n,2.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==48,{Synth.new(\oa,[\n,1.neg,\out,Array.rand(4, 0, 3).choose])});
if( num==49,{Synth.new(\oa,[\n,1,\out,Array.rand(4, 0, 3).choose])});
if( num==50,{Synth.new(\oa,[\n,2,\out,Array.rand(4, 0, 3).choose])});
if( num==51,{Synth.new(\oa,[\n,3,\out,Array.rand(4, 0, 3).choose])});
if( num==52,{Synth.new(\oa,[\n,4,\out,Array.rand(4, 0, 3).choose])});
if( num==53,{Synth.new(\oa,[\n,5,\out,Array.rand(4, 0, 3).choose])});
if( num==54,{Synth.new(\oa,[\n,6,\out,Array.rand(4, 0, 3).choose])});
if( num==55,{Synth.new(\oa,[\n,7,\out,Array.rand(4, 0, 3).choose])});
if( num==56,{Synth.new(\oa,[\n,8,\out,Array.rand(4, 0, 3).choose])});
if( num==57,{Synth.new(\oa,[\n,9,\out,Array.rand(4, 0, 3).choose])});
if( num==58,{Synth.new(\oa,[\n,10,\out,Array.rand(4, 0, 3).choose])});
if( num==59,{Synth.new(\oa,[\n,11,\out,Array.rand(4, 0, 3).choose])});
if( num==60,{Synth.new(\oa,[\n,12,\out,Array.rand(4, 0, 3).choose])});
if( num==61,{Synth.new(\oa,[\n,13,\out,Array.rand(4, 0, 3).choose])});
if( num==62,{Synth.new(\oa,[\n,14,\out,Array.rand(4, 0, 3).choose])});
if( num==63,{Synth.new(\oa,[\n,15,\out,Array.rand(4, 0, 3).choose])});
if( num==64,{Synth.new(\oa,[\n,16,\out,Array.rand(4, 0, 3).choose])});
if( num==65,{Synth.new(\oa,[\n,17,\out,Array.rand(4, 0, 3).choose])});
if( num==66,{Synth.new(\oa,[\n,18,\out,Array.rand(4, 0, 3).choose])});
if( num==67,{Synth.new(\oa,[\n,19,\out,Array.rand(4, 0, 3).choose])});
if( num==68,{Synth.new(\oa,[\n,20,\out,Array.rand(4, 0, 3).choose])});
if( num==69,{Synth.new(\oa,[\n,21,\out,Array.rand(4, 0, 3).choose])});
if( num==70,{Synth.new(\oa,[\n,22,\out,Array.rand(4, 0, 3).choose])});
if( num==71,{Synth.new(\oa,[\n,23,\out,Array.rand(4, 0, 3).choose])});
if( num==72,{Synth.new(\oa,[\n,24,\out,Array.rand(4, 0, 3).choose])});
if( num==73,{Synth.new(\oa,[\n,25,\out,Array.rand(4, 0, 3).choose])});
if( num==74,{Synth.new(\oa,[\n,26,\out,Array.rand(4, 0, 3).choose])});
if( num==75,{Synth.new(\oa,[\n,27,\out,Array.rand(4, 0, 3).choose])});
if( num==76,{Synth.new(\oa,[\n,28,\out,Array.rand(4, 0, 3).choose])});
if( num==77,{Synth.new(\oa,[\n,29,\out,Array.rand(4, 0, 3).choose])});
if( num==78,{Synth.new(\oa,[\n,30,\out,Array.rand(4, 0, 3).choose])});
if( num==79,{Synth.new(\oa,[\n,31,\out,Array.rand(4, 0, 3).choose])});
if( num==80,{Synth.new(\oa,[\n,32,\out,Array.rand(4, 0, 3).choose])});
if( num==81,{Synth.new(\oa,[\n,33,\out,Array.rand(4, 0, 3).choose])});
if( num==82,{Synth.new(\oa,[\n,34,\out,Array.rand(4, 0, 3).choose])});
if( num==83,{Synth.new(\oa,[\n,35,\out,Array.rand(4, 0, 3).choose])});
if( num==84,{Synth.new(\oa,[\n,36,\out,Array.rand(4, 0, 3).choose])});
if( num==85,{Synth.new(\oa,[\n,37,\out,Array.rand(4, 0, 3).choose])});
if( num==86,{Synth.new(\oa,[\n,38,\out,Array.rand(4, 0, 3).choose])});
if( num==87,{Synth.new(\oa,[\n,39,\out,Array.rand(4, 0, 3).choose])});
if( num==88,{Synth.new(\oa,[\n,40,\out,Array.rand(4, 0, 3).choose])});
if( num==89,{Synth.new(\oa,[\n,41,\out,Array.rand(4, 0, 3).choose])});
if( num==90,{Synth.new(\oa,[\n,42,\out,Array.rand(4, 0, 3).choose])});
if( num==91,{Synth.new(\oa,[\n,43,\out,Array.rand(4, 0, 3).choose])});
if( num==92,{Synth.new(\oa,[\n,44,\out,Array.rand(4, 0, 3).choose])});
if( num==93,{Synth.new(\oa,[\n,45,\out,Array.rand(4, 0, 3).choose])});
if( num==94,{Synth.new(\oa,[\n,46,\out,Array.rand(4, 0, 3).choose])});
if( num==95,{Synth.new(\oa,[\n,47,\out,Array.rand(4, 0, 3).choose])});
if( num==96,{Synth.new(\oa,[\n,48,\out,Array.rand(4, 0, 3).choose])});
})
To be honest, it’s still not clear what you’re after. Jordan is correct about the minimal example. If you want to get faster, more accurate help, it’s very useful to reduce your example to the minimum possible that demonstrates the issue. For example, if you are working with multiple 4-channel signals, we do not need the entire logic – you could just create e.g. SinOsc.ar([200, 300, 400, 500], 0, 0.1)
and then explain that you want 200 Hz on this bus, 300 Hz on that bus etc.
Now… the quote, “trigger a random argument for the bus of Out without expanding on the rest of the channels.”
Let’s do this kind of like a truth table in logic. There are two parameters: bus number(s), and signal(s). These may be either single or multiple (arrays).
- Mono signal, one bus number: self-explanatory. This is a normal case.
- Mono signal, multiple buses: as you would expect, the signal is copied to each bus. This isn’t done very often, but is easy to understand.
- Multichannel signal, one bus number: The channels are assigned to consecutive buses. With four channels, channel 1 → bus; channel 2 → bus+1; channel 3 → bus+2; channel 4 → bus+3. This is a normal case.
- Multichannel signal, multiple buses: The entire multichannel signal is copied to every bus number. This is normally not what users want.
Mono signal | Multichannel | |
---|---|---|
One bus number |
![]() |
![]() |
Many bus numbers |
![]() |
![]() |
“Normally not what users want” but if it isn’t this way, then, every time a user wants to play a stereo signal onto the hardware, they would have to write Out.ar([0, 1], stereo)
instead of Out.ar(0, stereo)
.
The current design makes the most common scenario easy (multichannel signal → consecutive buses), and an unusual scenario harder (splitting up a multichannel signal onto nonconsecutive buses). That makes your specific case a little harder, but it is a logical design decision.
So you will have to split up the multichannel signals by yourself. The Out
UGen by itself doesn’t do what you want, period.
I thought about various ways to specify the buses that you want, and I think the easiest is exactly what Jordan suggested: declare an array argument for out
, and then in the Synth(), specify exactly the buses you want.
This operation of splitting up the channels needs to be done multiple times. For convenience, you could write a function for it:
var wrappedOut = { |busArray, signalArray|
// magic trick to expand to the larger of the two arrays
[busArray, signalArray].flop.do { |pair|
Out.ar(pair[0], pair[1])
}
};
Then:
SynthDef.new(\oa, {
arg rotation1 = 1, rotation2 = 1, rotation3 = 1, rotation4 = 1, rotation5 = 1, rotation6 = 1, rotation7 = 1, rotation8 = 1, n=1, cutt = 496;
var out = NamedControl.kr(\out, [0, 1, 2, 3]); // multiple buses!
... the rest as is, until...
wrappedOut.value(out, LeakDC.ar(LPF.ar(osc1 * env * (2/3), cutt)));
...
})
So it looks almost exactly like what you wrote initially, just substituting a different operation in place of Out.ar
.
Then:
Synth.new(\oa, [\n, 13.neg, \out, (0..3).rotate(4.rand)])
Last… semiquaver is right that 61 lines of copy-paste num == xx
is rather excessive, especially when there’s a clear pattern. Just one minor modification to his suggestion, below, to avoid n == 0. Also, you could use the noteNum
filter to remove all of the if
statements.
// also I need to fix your spacing and indentation
// your code is hard to read!
MIDIdef.noteOn(\synhtone, { |val, num, chan, src|
[val, num, chan, src].postln;
if(num < 49) {
num = num - 1
};
Synth(\oa, [n: num - 48, out: (0..3).rotate(4.rand)]);
}, noteNum: (36..96))
hjh
wow, thank you very much, that works perfectly. I’ll have to study your code in the example a bit to understand it better. I will try also to give more specified examples of code in the future.
and thanks for the MIDI code!
just one question why does,
var wrappedOut = { |busArray, signalArray|
// magic trick to expand to the larger of the two arrays
[busArray, signalArray].flop.do { |pair|
Out.ar(pair[0], pair[1])
}
};
have two pairs?
a, because of the two arrays?
It doesn’t.
First, make sure you understand what flop does. I’ll use arrays of words to make it clearer:
[
[ \bus0, \bus1, \bus2, \bus3 ],
[ \sig0, \sig1, \sig2, \sig3 ]
].flop;
-> [ [ \bus0, \sig0 ], [ \bus1, \sig1 ], [ \bus2, \sig2 ], [ \bus3, \sig3 ] ]
flop
here is associating the buses with the corresponding signals.
Now… What is do
going to do to that?
The members of the array are the [ \bus0, \sig0 ]
pairs, so, each time through the loop, the pair
argument inside the loop body will point to one of these.
Next, make sure you understand what the bracket notation is doing. This is a shorter, C-like syntax for the at
method: “Return the item at index.” So pair[0]
returns the item at index 0. In [ \bus0, \sig0 ]
, what is the item at index 0? It’s \bus0
… and coincidentally, it’s being used in the bus input of an Out UGen. (Of course in the real scenario, it’s not the symbol bus0 – it’s a control input representing a bus number.) So then maybe you can guess why pair[1] would be written into the signal input of the Out.
Arrays, indexing and loops are all very important concepts that can free your code from pages of copy-paste hell. It’s really worth your while to study them.
hjh
o, it’s much clearer now. Will do, and thank you again for the crash course.
Hi,
I tried to expand the above method with a synth controlled by a pattern, not via midi, but as soon as I set the pattern to give an array of values for the \out NamedControl the server gradually crashes. A look at the node tree shows that the synth instances do not go away as the doneAction 2 of the envelope would command. Do you know what is wrong?
This is the synth with its wavetable above:
(
var angle1=0,detune1;
~amps = [1] ++ ({[0,exprand(0.01,1)].choose}!100);
~ph=100.collect{
angle1=(angle1+(360-(360/1.61803398874989484820458683436563811772030917980576))).wrap(0,360);
detune1=exp(Complex(0,1)*angle1.degrad).theta;
};
b= Buffer.alloc(s,2048);
~sig = Signal.sineFill(1024, ~amps,
~ph
);
~sig.plot;
~wt= ~sig.asWavetable;
b.loadCollection(~wt);
);
(
SynthDef.new(\oa, {
arg n=1, cutt=200,decay=3,harm=6,attack=0.01;
var detune1, osc1;
var freq1, env;
var bank, angle1, pitch;
var fund=(((4*2)-1)*((4*2)/2));
var wrappedOut = { |busArray, signalArray|
// magic trick to expand to the larger of the two arrays
[busArray, signalArray].flop.do { |pair|
Out.ar(pair[0], pair[1])
}
};
var out = NamedControl.kr(\out, [0, 1, 2, 3]); // multiple buses!
bank=18;
angle1=0;
pitch=2.pow(n/(2*6));
fund=fund/2;
freq1 = fund*harm;
freq1=freq1*(1/1);
env=EnvGen.ar(Env.perc(attack,decay,pitch.reciprocal),doneAction:2);
bank.do{
//env=EnvGen.ar(Env.sine(decay,pitch.reciprocal),doneAction:2);
angle1=(angle1+(360-(360/1.61803398874989484820458683436563811772030917980576))).wrap(0,360);
detune1=exp(Complex(0,1)*angle1.degrad);
osc1=Pan4.ar(Osc.ar(b,(freq1)*pitch,
mul:1,
phase:detune1.theta),
detune1.real.round(0.001),detune1.imag.round(0.001));
wrappedOut.value(out, LPF.ar(LeakDC.ar((osc1 )* env*1),cutt));
};
}).add;
)
and these are the pattern variations I applied:
(
Pdef(\1, Pbind(\instrument, \oa,
\dur,Pbrown(1/4,1,1/4,inf),
\harm,Prand([6,8,9,12],inf),
\n,Prand([8,20,23,11,25,15,23,22,8,20,23,11,22,15,18,20],inf),
\cutt,Pbrown(440,5000,100,inf),
\out,(0..3).rotate(4.rand),
\attack,Pbrown(0.01,1,0.1,inf),
\decay,Pbrown(4,8,1,inf);
)).play;
)
(
Pdef(\1, Pbind(\instrument, \oa,
\dur,Pbrown(1/4,1,1/4,inf),
\harm,Prand([6,8,9,12],inf),
\n,Prand([8,20,23,11,25,15,23,22,8,20,23,11,22,15,18,20],inf),
\cutt,Pbrown(440,5000,100,inf),
\out,Pxrand([[0,1,2,3],[1,0,3,2]],inf),
\attack,Pbrown(0.01,1,0.1,inf),
\decay,Pbrown(4,8,1,inf);
)).play;
)
If you have, for instance, [200, 300, 400]
for freq in an event, it means to produce 3 synths, one at 200 Hz, the second at 300, the third at 400.
So if you have a flat \out array, it will expand to 4 synths.
To produce one synth, you need an \out array with one item inside… one item → one synth.
This single item inside the array can be an array – then this array will fill up the 4-element NamedControl for out.
-
\out, [0, 1, 2, 3]
– 4 synths, 1 value per synth. -
\out, [ [0, 1, 2, 3] ]
– 1 synth, 4 out values.
\out, [(0..3).rotate(4.rand)]
– because this isn’t a pattern, you can just wrap it in brackets.
If it is a pattern, you can .collect
over the pattern’s results and wrap each result: Pxrand(...).collect { |row| [row] }
or the shorter version .collect([_])
(convenient, but read the Partial Application help file).
As for not releasing: I see a minimum dur of 1/4 and a maximum decay of 8 – so there could be up to 32 events playing simultaneously (or more, if the tempo is faster than 1 beat per second), times 4 because of the \out usage = up to 128 synths. Large synths. It may be that they would release on their own if there aren’t so many. Fixing \out will give you 1/4 of the synths you have now. I’d try that first. Another test would be to reduce the decay time – if they release with a shorter decay, then the envelope can’t be the problem.
hjh
(0..3).rotate(4.rand)
sets random, each time, every part of the array but in the case of the pattern
such as
(
a=Pxrand([0,1,2,3],inf).collect([0,1,2,_]);
x=a.asStream;
9.do({x.next.postln;});
)
only the last part of the array becomes random, through the pattern.
Is there a way to collect every part as random?
I think I found a solution but the array does not always contain channels [0,1,2,3], since one number is collected out of these each time.
(
a=Pxrand([0,1,2,3],inf).collect([0,1,2,_].rotate(4.rand));
x=a.asStream;
9.do({x.next.postln;});
)
Maybe like this?:
(
a = Pfunc{ [0, 1, 2, 3].scramble };
x = a.asStream;
9.do({x.next.postln;});
)
Yes, this, or: Pn(Pshuf([0, 1, 2, 3], 1), inf).clump(4).collect([_])
(the collect bit is needed for event usage).
hjh
Perfect, thank you very very much, now the synth automation behaves exactly as I intended