«Singing discrete but continuously» by gilFuser

on 18 Apr'17 17:06 in vocalpluckedpolyphoniclong or shortheterodox

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.

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
*/
raw 8577 chars (focus & ctrl+a+c to copy)
reception
comments