«Singing discrete but continuously» by gilFuser
on 18 Apr'17 17:06 inThis 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
// 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 */
reception
comments