// title: Singing discrete but continuously // author: gilFuser // description: // This is a way of having both discrete and continuous control over a sound that is meant to be played trough patterns. One also have the possibility to have it polyphonic like is generally possible when one uses a SynthDef as an instrument in a Pbind. // The code is rather long, but just because is repetitive. // One Ndef produces eight channels of sound. // A SynthDef take the sounds from the Ndef as input sounds, and modulate their amplitude with envelopes. It also frees itself with doneAction, as needed to be used in patterns. // Pdef have Pbinds inside to play both the SynthDef and the Ndef. Some parameters are left to continuous setting that can be done in a gui or even more fun, with an actual controller, e.g. using Modality. // code: // this will be needed to have an environment for the scale pattern proxies. See below q = q ? (); //////////////// this produces the sounds //////////////// Ndef(\sayA, { arg freq0=44,dist0=0.05,fold0=2,slide0=0.1,pan0=0,amp0=1, freq1=88,dist1=0.1,fold1=2,slide1=0.1,pan1=0,amp1=0.75, freq2=176,dist2=0.2,fold2=2,slide2=0.1,pan2=0,amp2=0.5, freq3=352,dist3=0.4,fold3=2,slide3=0.1,pan3=0,amp3=0.25, amp=0.5; var lfmod, freqDev, aaa0, form0, bal0, ruin0, sig0, aaa1, form1, bal1, ruin1, sig1, aaa2, form2, bal2, ruin2, sig2, aaa3, form3, bal3, ruin3, sig3; lfmod = {LFNoise2.ar(XLine.kr(1, 6, 1.5), XLine.kr( 0.001, 1, 0.66, 4), 0.501 )}; freqDev = {LFNoise2.kr(0.1, 0.01, 1)}; // sig 0 aaa0 = Vowel(\a, \bass) * dist0.lag(0.2); form0 = Formants.ar( [ freq0.lag(slide0) * freqDev.reciprocal, freq0.lag(slide0) * freqDev ] + lfmod!2, aaa0, ampMods: 0.25 ) * amp0; bal0 = Balance2.ar(form0[0][0], form0[1][1], pan0); ruin0 = Fold.ar(bal0, (-1 * fold0).lag(0.2), fold0.lag(0.2)); sig0 = ruin0 * AmpComp.kr(freq0, 44); // sig 1 aaa1 = Vowel(\a, \bass) * dist1.lag(0.2); form1 = Formants.ar( [ freq1.lag(slide1) * freqDev.reciprocal, freq1.lag(slide1) * freqDev ] + lfmod!2, aaa1, ampMods: 0.25 ) * amp1; bal1 = Balance2.ar(form1[0][0], form1[1][1], pan1); ruin1 = Fold.ar(bal1, (-1 * fold1).lag(0.2), fold1.lag(0.2)); sig1 = ruin1 * AmpComp.kr(freq1, 44); // sig 2 aaa2 = Vowel(\a, \bass) * dist2.lag(0.2); form2 = Formants.ar( [ freq2.lag(slide2) * freqDev.reciprocal, freq2.lag(slide2) * freqDev ] + lfmod!2, aaa2, ampMods: 0.25 ) * amp2; bal2 = Balance2.ar(form2[0][0], form2[1][1], pan2); ruin2 = Fold.ar(bal2, (-1 * fold2).lag(0.2), fold2.lag(0.2)); sig2 = ruin2 * AmpComp.kr(freq2, 44); // sig 3 aaa3 = Vowel(\a, \bass) * dist3.lag(0.2); form3 = Formants.ar( [ freq3.lag(slide3) * freqDev.reciprocal, freq3.lag(slide3) * freqDev ] + lfmod!2, aaa3, ampMods: 0.25 ) * amp3; bal3 = Balance2.ar(form3[0][0], form3[1][1], pan3); ruin3 = Fold.ar(bal3, (-1 * fold3).lag(0.2), fold3.lag(0.2)); sig3 = ruin3 * AmpComp.kr(freq3, 44); [sig0, sig1, sig2, sig3 ] * amp } ); //////////////// for later control of the sounds: //////////////// Ndef(\sayA).addSpec(\dist0, [0.02, 2]); Ndef(\sayA).addSpec(\fold0, [0.1, 2]); Ndef(\sayA).addSpec(\freq0, \freq.asSpec); Ndef(\sayA).addSpec(\slide0, [0.01, 1]); Ndef(\sayA).addSpec(\dist1, [0.02, 2]); Ndef(\sayA).addSpec(\fold1, [0.1, 2 ]); Ndef(\sayA).addSpec(\freq1, \freq.asSpec); Ndef(\sayA).addSpec(\slide1, [0.01, 1]); Ndef(\sayA).addSpec(\dist2, [0.02, 2]); Ndef(\sayA).addSpec(\fold2, [0.1, 2 ]); Ndef(\sayA).addSpec(\freq2, \freq.asSpec); Ndef(\sayA).addSpec(\slide2, [0.01, 1]); Ndef(\sayA).addSpec(\dist3, [0.02, 2 ]); Ndef(\sayA).addSpec(\fold3, [0.1, 2 ]); Ndef(\sayA).addSpec(\freq3, \freq.asSpec); Ndef(\sayA).addSpec(\slide3, [0.01, 1]); Ndef(\sayA).set(\dist0, 0.1, \fold0, 2, \dist1, 0.1, \fold1, 2, \dist2, 0.2, \fold2, 2, \dist3, 0.4, \fold3, 2); Ndef(\sayA).gui; //////////////// prepare the sounds to be 'patterned' //////////////// ( SynthDef(\sayA, { arg atkT0= 0.002, decT0= 0.1, susL0 = 0.0, relT0= 0.5, relCurve0= -4, amp0 = 0.4, atkT1= 0.002, decT1= 0.1, susL1 = 0.0, relT1= 0.5, relCurve1= -4, amp1 = 0.4, atkT2= 0.002, decT2= 0.1, susL2 = 0.0, relT2= 0.5, relCurve2= -4, amp2 = 0.4, atkT3= 0.002, decT3= 0.1, susL3 = 0.0, relT3= 0.5, relCurve3= -4, amp3 = 0.4, pluck0= 0.0, pluck1= 0.1, pluck2= 0.2, pluck3= 0.3, atkCurve= \sin, gate= 1, dur = 1, legato = 0.5, amp= 1, sustain = 1, pan; var in0, sig0, in1, sig1, in2, sig2, in3, sig3, env1, env, gen, dummygen, sound, out; env1 = Env.dadsr( [pluck0, pluck1, pluck2, pluck3], [atkT0, atkT1, atkT2, atkT3], [decT0, decT1, decT2, decT3], [susL0, susL1, susL2, susL3], [relT0, relT1, relT2, relT3], 1, [ [atkCurve, 0, relCurve0], [ atkCurve, -4, relCurve1 ], [ atkCurve, -4, relCurve2 ], [ atkCurve, -4, relCurve3 ]] ); gen = EnvGen.ar( env1, gate, timeScale: dur * legato + ( pluck0 + pluck1 + pluck2 + pluck3 ), doneAction:0); env = EnvGen.ar( Env.step(1!2, sustain*0.5!2), gate:gate, timeScale: dur*2, doneAction:2); in0 = Ndef(\sayA).ar[0]; in1 = Ndef(\sayA).ar[2]; in2 = Ndef(\sayA).ar[4]; in3 = Ndef(\sayA).ar[6]; sig0 = in0 * gen[0] * amp0; sig1 = in1 * gen[1] * amp1; sig2 = in2 * gen[2] * amp2; sig3 = in3 * gen[3] * amp3; sound = Splay.ar([sig2, sig0, sig1, sig3], 0.5) * amp; out = OffsetOut.ar(0, sound) }).add; ); //////////////// here is the patterns part: //////////////// // this is optional, to use scales. // If you wouldn't like to use, change the key-value pair \scale in the Pbind // and erase the Pkeys that reference to it. ( q.scaleA = PatternProxy.new; q.scaleB = PatternProxy.new; q.scaleA.source = Scale.majorPentatonic; q.scaleB.source = Scale.minorPentatonic; ); //////////////// The almighty Pdef //////////////// // first lets set things and prepare it for further control: Pdef(\sayA).addSpec(\legato, [ 0.2, 4 ]); Pdef(\sayA).addSpec(\atkT0, [ 0.001, 0.5 ]); Pdef(\sayA).addSpec(\decT0, [ 0.1, 0.5 ]); Pdef(\sayA).addSpec(\susL0, [ 0.001, 1, \exp ]); Pdef(\sayA).addSpec(\relT0, [ 0.1, 1 ]); Pdef(\sayA).addSpec(\relCurve0, [-6, 6 ]); Pdef(\sayA).addSpec(\atkT1, [ 0.001, 0.5 ]); Pdef(\sayA).addSpec(\decT1, [ 0.1, 0.5 ]); Pdef(\sayA).addSpec(\susL1, [ 0.001, 1 ]); Pdef(\sayA).addSpec(\relT1, [ 0.1, 1 ]); Pdef(\sayA).addSpec(\relCurve1, [-6, 6 ]); Pdef(\sayA).addSpec(\atkT2, [ 0.001, 0.5 ]); Pdef(\sayA).addSpec(\decT2, [ 0.1, 0.5 ]); Pdef(\sayA).addSpec(\susL2, [ 0.001, 1, \exp ]); Pdef(\sayA).addSpec(\relT2, [ 0.1, 1 ]); Pdef(\sayA).addSpec(\relCurve2, [ -6, 6 ]); Pdef(\sayA).addSpec(\atkT3, [ 0.001, 0.5 ]); Pdef(\sayA).addSpec(\decT3, [ 0.1, 0.5 ]); Pdef(\sayA).addSpec(\susL3, [ 0.001, 1, \exp ]); Pdef(\sayA).addSpec(\relT3, [ 0.1, 1 ]); Pdef(\sayA).addSpec(\relCurve3, [ -6, 6 ]); Pdef(\sayA).addSpec(\loose, [ 0, 2 ]); Pdef(\sayA).set(\legato, 0.25, \loose, 0, \atkT0, 0.01, \decT0, 0.2, \susL0, 0.05, \relT0, 0.2, \relCurve0, -4, \atkT1, 0.01, \decT1, 0.2, \susL1, 0.05, \relT1, 0.2, \relCurve1, -4, \atkT2, 0.01, \decT2, 0.2, \susL2, 0.05, \relT2, 0.2, \relCurve2, -4, \atkT3, 0.01, \decT3, 0.2, \susL3, 0.05, \relT3, 0.2, \relCurve3, -4, ); ( Pdef(\sayAll, Ppar([ Pbindef(\sayA, \instrument, \sayA, \dur, 1, \onOff, Pwrand([0, 1], [2, 1].normalizeSum, inf), \type, Pswitch( [ \rest, \note ], Pkey( \onOff ) ), \pluck0, 0, \pluck1, Pn(Pbrown(0.04, 0.2, 0.008)) * Pkey(\loose), \pluck2, Pn(Pbrown(0, 0.2, 0.01)) * Pkey(\loose), \pluck3, Pn(Pbrown(0, 0.2, 0.012)) * Pkey(\loose), ), Pbindef( \sayAn, \type, \set, \id, Ndef(\sayA).group, \args, #[ \amp0, \amp1, \amp2, \amp3, \freq0, \freq1, \freq2, \freq3 ], // if you won't use the q.scale thing, you can you this in the Pkeys from freq0..3 // \freq, Pfunc{ ([100, 200].choose + [100, 200].choose + [10, 20].choose) }, \scale, Pfunc{ q.scaleA.source }, \degree, Pseq([ 0, -1, -3, -4, -7 ], inf) + 5, // \octave, -3, // this doen't seems to work. I don't know why // \root, 9, // neither this. If someone out there knows why, please tell me \mtranspose, -11, \freq0, Pfunc({|ev| ev[\scale].degreeToFreq(ev[\degree] + ev[\mtranspose], 60.midicps, 1)}), \freq1, Pfunc({|ev| ev[\scale].degreeToFreq(ev[\degree] + ev[\mtranspose] + 3, 60.midicps, 1)}), \freq2, Pfunc({|ev| ev[\scale].degreeToFreq(ev[\degree] + ev[\mtranspose] + 5, 60.midicps, 1)}), \freq3, Pfunc({|ev| ev[\scale].degreeToFreq(ev[\degree] + ev[\mtranspose] + 8, 60.midicps, 1)}), \amp0, 1, \amp1, Pwhite(0.5, 1.75), \amp2, Pwhite(0.5, 1.5), \amp3, Pwhite(0.5, 1.25), \dur, Pwhite(0.2, 1), \amp, 1 ), ]); ); Pdef(\sayAll).play; Pdef(\sayA).gui; Pdef(\sayAn).gui; /* that's it. Have fun. There's plenty of room for exploration. It's nice to change what you want to be controlled by the patters and by yourself. Like dur, amps, freqs and so on. It's not working perfectly, specially regarding the way that the time scale works in the SynthDef. The delay from the envelopes makes the latter notes disappear when they are bigger and the legato is short. I may find a solution for that and update all of this. Any obs. Q & A, email me at gil at gilfuser.net */