aboutsummaryrefslogtreecommitdiff
path: root/site/udo/sequencing.udo
diff options
context:
space:
mode:
authorRichard <q@1bpm.net>2025-04-13 18:48:02 +0100
committerRichard <q@1bpm.net>2025-04-13 18:48:02 +0100
commit9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 (patch)
tree291bd79ce340e67affa755a8a6b4f6a83cce93ea /site/udo/sequencing.udo
downloadapps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.gz
apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.tar.bz2
apps.csound.1bpm.net-9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22.zip
initial
Diffstat (limited to 'site/udo/sequencing.udo')
-rwxr-xr-xsite/udo/sequencing.udo329
1 files changed, 329 insertions, 0 deletions
diff --git a/site/udo/sequencing.udo b/site/udo/sequencing.udo
new file mode 100755
index 0000000..ac4fd40
--- /dev/null
+++ b/site/udo/sequencing.udo
@@ -0,0 +1,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