aboutsummaryrefslogtreecommitdiff
path: root/site/udo/sequencing.udo
blob: ac4fd409c5bd9d3be544c968edf959750d134fce (plain)
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#ifndef UDO_SEQUENCING
#define UDO_SEQUENCING ##
/*
	Sequencing base

	This file is part of the SONICS UDO collection by Richard Knight 2021
		License: GPL-2.0-or-later
		http://1bpm.net
*/

gkseq_tempo init 120		; tempo BPM
gkseq_beat init 0			; trigger fired on each beat
gkseq_beattime init 0		; time in seconds of one beat (read only; set by BPM)
gkseq_quartertime init 0	; time in seconds of one quarter beat (read only; set by BPM)
gkseq_beathz init 0			; Hz of one beat (read only; set by BPM)
gkseq_swing init 0.2		; swing amount
gkseq_on init 1

/*
	Instrument to control the main beat metronome and beat time globals
*/
instr _seq_manager
	kseq_beat metro gkseq_tempo / 60
	if (gkseq_on == 1) then
		gkseq_beat = kseq_beat
	endif
	gkseq_beattime = 60 / gkseq_tempo
	gkseq_quartertime = gkseq_beattime / 4
	gkseq_beathz = (1 / 60) * gkseq_tempo
endin
;alwayson "_seq_manager" ; not available in web api
schedule("_seq_manager", 0, -1)



/*
	Get the swung time for a given time, if appropriate. If the index given is a second 16th, time will be swung
	
	kresult seq_swingtime ktime, kindex, kswing

	kresult		resulting time
	ktime		the time to consider
	kindex		beat index, beginning with 0
	kswing		the swing amount (0 to 1)
*/
opcode seq_swingtime, k, kkJ
	ktime, kindex, kswing xin
	kswing = (kswing == -1) ? gkseq_swing : kswing
	if ((kindex+1) % 2 == 0) then
		ktime = ktime + (gkseq_quartertime*kswing)
	endif
	xout ktime
endop


/*
	Get the swung time for a given time, if appropriate. If the index given is a second 16th, time will be swung
	
	iresult seq_swingtime itime, iindex, iswing

	iresult		resulting time
	itime		the time to consider
	iindex		beat index, beginning with 0
	iswing		the swing amount (0 to 1)
*/
opcode seq_swingtime, i, iij
	itime, index, iswing xin
	iswing = (iswing == -1) ? i(gkseq_swing) : iswing
	if ((index+1) % 2 == 0) then
		itime = itime + (i(gkseq_quartertime)*iswing)
	endif
	xout itime
endop


/*
	Set the tempo in BPM
	DEPRECATED: just use init or direct assignment to gkseq_tempo

	seq_settempo ktempo

	ktempo	the tempo in BPM
*/
opcode seq_settempo, 0, k
	ktempo xin
	gkseq_tempo = ktempo
endop


/*
	Set the tempo in BPM; typically for host control

	p4		the tempo in BPM
*/
instr seq_settempo
	itempo = p4
	gkseq_tempo = itempo
	turnoff
endin




/*
	Basic sequencer: trigger an instrument on each beat

	seq_basic SdespatchI

	SdespatchI	name of the instrument to trigger
*/
opcode seq_basic, 0, S
	SdespatchI xin
	schedkwhen gkseq_beat, 0, 0, SdespatchI, 0, 1
endop



/*
	Basic swung sequencer: trigger an instrument on each 16th beat with
		p4 as the cyclical index between 0 and 3
		p5 as the total number of beats beginning at one (eg so modulus can be used to determine position etc)

	seq_swing SdespatchI, kswing

	SdespatchI	name of the instrument to trigger
	kswing		swing amount (0 to 1)
*/
opcode seq_swing, 0, SJ
	SdespatchI, kswing xin
	kswing = (kswing == -1) ? gkseq_swing : kswing
	kbeatnum init 1
	if (gkseq_beat == 1) then
		kswingamount = gkseq_quartertime*kswing
		event "i", SdespatchI, 0, 1, 0, kbeatnum
		event "i", SdespatchI, gkseq_quartertime+kswingamount, 1, 1, kbeatnum
		event "i", SdespatchI, gkseq_quartertime*2, 1, 2, kbeatnum
		event "i", SdespatchI, (gkseq_quartertime*3)+kswingamount, 1, 3, kbeatnum
		kbeatnum += 1
	endif
endop



/*
	Basic array sequencer. Treat each index as a 16th, and if it is 1, trigger the despatch instrument
	
	seq_array SdespatchI, karray[], kswing

	SdespatchI	name of the instrument to trigger
	karray[]	array of sequence information
	kswing		swing amount (0 to 1)
*/
opcode seq_array, 0, Sk[]k
	SdespatchI, karray[], kswing xin
	kindex init 0	
	if (gkseq_beat == 1) then
		ktime = 0
		kcount = 0
		while (kcount < 4) do
			if (karray[kindex] == 1) then
				event "i", SdespatchI, seq_swingtime(ktime, kcount, kswing), 0.1
			endif

			if (kindex + 1 >= lenarray(karray)) then
				kindex = 0
			else
				kindex += 1
			endif
			kcount += 1
			ktime += gkseq_quartertime
		od
	endif
endop


/*
	Parametric array sequencer. Treat each index of the first dimension as a 16th. The second dimension is as follows:
		0	trigger (1 is active)
		1	duration in seconds
		2	p4 onwards (can be as many p-fields as required to be passed to the despatch instrument)

	seq_array2d SdespatchI, karray[][], kswing

	SdespatchI	name of the instrument to trigger
	karray[][]	2D array of sequence information
	kswing		swing amount (0 to 1)
*/
opcode seq_array2d, 0, Sk[][]k
	SdespatchI, karray[][], kswing xin
	kindex init 0	
	if (gkseq_beat == 1) then
		ktime = 0
		kcount = 0
		while (kcount < 4) do
			if (karray[kindex][0] == 1) then
				krow[] getrow karray, kindex
				Scoreline sprintfk "i\"%s\" %f %f ", SdespatchI, seq_swingtime(ktime, kcount, kswing), krow[1]
				if (lenarray(krow) > 2) then
					kdx = 2
					while (kdx < lenarray(krow)) do
						Scoreline strcatk Scoreline, sprintfk("%f ", krow[kdx])
						kdx += 1
					od
				endif
				scoreline Scoreline, 1
			endif

			if (kindex + 1 >= lenarray(karray)) then
				kindex = 0
			else
				kindex += 1
			endif
			kcount += 1
			ktime += gkseq_quartertime
		od
	endif
endop



/*
	Freak sequencer. Three iterations of generative triggers sent to despatch instruments

	seq_freak SdespatchI1, SdespatchI2, SdespatchI3, kbeatdensity[], kbeatstrength[]

	SdespatchI1	name of the primary instrument to trigger
	SdespatchI2	name of the secondary instrument to trigger
	SdespatchI3	name of the tertiary instrument to trigger
*/
opcode seq_freak, 0, SSSk[]k[]
	SdespatchI1, SdespatchI2, SdespatchI3, kbeatdensity[], kbeatstrength[] xin
	
	kbeat init 0
	ktrig init 0
	if (gkseq_beat == 1) then ; only on every 1st of 4 beats
		if (kbeat == 0) then
			ktrig = 1
			kbeat += 1
		elseif (kbeat == 3) then
			kbeat = 0
		else
			kbeat += 1
		endif

	endif

	if (ktrig == 1 && random:k(0, 1) < kbeatdensity[0]) then
		ktrig = 0
		ktime = 0
		event "i", SdespatchI1, ktime, 1, random:k(kbeatstrength[0]*0.2, kbeatstrength[0])
		kindex1 = 0
		kitems1 random 0, 8
		while (kindex1 < kitems1) do
			if (random:k(0, 1) < kbeatdensity[1]) then
				event "i", SdespatchI2, ktime, 1, random:k(kbeatstrength[1]*0.2, kbeatstrength[1])
			endif
			ktime2 = ktime + (gkseq_beattime/8/8)
			kindex2 = 0
			kitems2 random 0, 32
			while (kindex2 < kitems2) do
				if (random:k(0, 1) < kbeatdensity[2]) then
					event "i", SdespatchI3, ktime2, 1, random:k(kbeatstrength[2]*0.2, kbeatstrength[2])	
				endif
				ktime2 += gkseq_beattime/8/8
				kindex2 += 1
			od

			ktime += gkseq_beattime/8
			kindex1 += 1
		od
	endif
endop


/*
	Bar and bargroup management
	
	Each beat is counted upon a gkseq_beat trigger.
	When the number of beats implies a bar has completed, the trigger gkseq_bar_trig is fired.
	The position in the bar (beat number (0 to giseq_barlength - 1)) is available in gkseq_barbeat.

	When the number of bars implies a bargroup has completed, the trigger gkseq_bargroup_trig is fired.
	The position in the bargroup (bar number (0 to giseq_bargrouplength - 1)) is available in gkseq_bargroup.
*/
gkseq_bar_trig init 0 ; trigger
gkseq_barbeat init -1 ; number
giseq_barlength = 4

gkseq_bargroup_trig init 0 ; trigger
gkseq_bargroup init -1 ; number
giseq_bargrouplength = 4

instr _barmanager
	kbarbeat init 0
	gkseq_bar_trig = 0
	gkseq_bargroup_trig = 0

	if (gkseq_beat == 1) then
		gkseq_barbeat = (gkseq_barbeat < (giseq_barlength-1) ? gkseq_barbeat + 1 : 0)
		if (gkseq_barbeat == 0) then
			gkseq_bar_trig = 1
			gkseq_bargroup = (gkseq_bargroup < (giseq_bargrouplength-1) ? gkseq_bargroup + 1 : 0) 
			if (gkseq_bargroup == 0) then
				gkseq_bargroup_trig = 1
			endif
		endif
	endif
endin
;alwayson "_barmanager" ; not available in web api
schedule("_barmanager", 0, -1)


/*
	metronome; first beat has a higher pitch
	
	aout metronome [iamp=1]

	aout		metronome output
	iamp		optional amplitude
*/
opcode metronome, a, p
	iamp xin
	kamp loopseg gkseq_tempo/60, gkseq_beat, 0, 1, 0.2, 0, 0.8, 0, 0
	aout oscil 0.1, (gkseq_barbeat == 0 ? 2000 : 1000)
	xout aout * kamp * iamp
endop


#end