From 5f084737a2899d2765432d672c6ef608e6203e14 Mon Sep 17 00:00:00 2001 From: Richard Knight Date: Wed, 25 Aug 2021 22:18:18 +0100 Subject: examples update --- examples/0-fltk_gui.csd | 145 +++++++++++++++++++++++------------------- examples/1-chord_sequence.csd | 73 +++++++++++++++++---- examples/2-random_params.csd | 36 +++++------ examples/3-controlchanges.csd | 31 ++++++--- 4 files changed, 177 insertions(+), 108 deletions(-) diff --git a/examples/0-fltk_gui.csd b/examples/0-fltk_gui.csd index d81a48a..558d73f 100644 --- a/examples/0-fltk_gui.csd +++ b/examples/0-fltk_gui.csd @@ -2,23 +2,37 @@ -odac -+rtmidi=virtual -M0 +-m0 -; ============================================== +/* + csound-opl example 0 + FLTK gui for instrument editing + + Richard Knight 2021 : examples are licensed as public domain equivalent : http://unlicense.org/ -sr = 44100 +*/ + +sr = 44100 kr = 4410 -nchnls = 2 -0dbfs = 1 +nchnls = 2 +0dbfs = 1 seed 0 +; operator parameters and handles gkop[][] init 4, 12 giop[][] init 4, 12 + +; global instrument parameters and handles gkinstr[] init 8 giinstr[] init 8 + +; GUI spacing variables giopwidth = 200 gidiv = 60 + +; FLTK GUI objects for an operator opcode operator, 0, i iop xin ix = giopwidth * iop @@ -39,33 +53,18 @@ opcode operator, 0, i endop -opcode randomise, 0, 0 - iop = 0 - while (iop < 4) do - FLsetVal_i random(30, 63), giop[iop][0] - FLsetVal_i random(0, 3), giop[iop][1] - FLsetVal_i random(0, 15), giop[iop][2] - FLsetVal_i random(0, 15), giop[iop][3] - FLsetVal_i random(0, 15), giop[iop][4] - FLsetVal_i random(0, 15), giop[iop][5] - FLsetVal_i random(0, 7), giop[iop][6] - FLsetVal_i random(0, 15), giop[iop][7] - FLsetVal_i random(0, 1), giop[iop][8] - FLsetVal_i random(0, 1), giop[iop][9] - FLsetVal_i random(0, 1), giop[iop][10] - FLsetVal_i random(0, 1), giop[iop][11] - iop += 1 - od - FLsetVal_i random(0, 7), giinstr[2] - FLsetVal_i random(0, 7), giinstr[3] -endop +; run the GUI instr gui FLpanel "OPL3", 1000, 768 + + ; operator columns operator 0 operator 1 operator 2 operator 3 + + ; global column ix = 800 iy = 0 ihl FLbox "Globals", 1, 2, 14, giopwidth, 30, ix, iy @@ -81,12 +80,48 @@ instr gui knull1, inull1 FLbutton "Panic", 1, 0, 1, giopwidth, 30, ix, iy+(gidiv*6), 0, nstrnum("panic"), 0, 1 FLpanelEnd FLrun + + ; initially, hide the last two operators (ie non four-operator mode) event_i "i", "fouropset", 0, 1, 0 endin +; audio processing +instr main + + ; the synthesiser + giopl, aL, aR opl + outs aL, aR + + ; get operator handles and set the global instrument parameters from the FLTK widgets + iop1, iop2, iop3, iop4 oplinstrument giopl, gkinstr[0], gkinstr[1], gkinstr[2], gkinstr[3], gkinstr[4], gkinstr[5], gkinstr[6], gkinstr[7] + + ; set the operator parameters from the FLTK widgets + oploperator iop1, gkop[0][0], gkop[0][1], gkop[0][2], gkop[0][3], gkop[0][4], gkop[0][5], gkop[0][6], gkop[0][7], gkop[0][8], gkop[0][9], gkop[0][10], gkop[0][11] + oploperator iop2, gkop[1][0], gkop[1][1], gkop[1][2], gkop[1][3], gkop[1][4], gkop[1][5], gkop[1][6], gkop[1][7], gkop[1][8], gkop[1][9], gkop[1][10], gkop[1][11] + oploperator iop3, gkop[2][0], gkop[2][1], gkop[2][2], gkop[2][3], gkop[2][4], gkop[2][5], gkop[2][6], gkop[2][7], gkop[2][8], gkop[2][9], gkop[2][10], gkop[2][11] + oploperator iop4, gkop[3][0], gkop[3][1], gkop[3][2], gkop[3][3], gkop[3][4], gkop[3][5], gkop[3][6], gkop[3][7], gkop[3][8], gkop[3][9], gkop[3][10], gkop[3][11] + +endin + + +; respond to realtime MIDI input accordingly +instr 1 + inote notnum + iveloc veloc + oplnote giopl, 0, inote, iveloc +endin + + +; panic: reset the opl instance +instr panic + oplpanic giopl +endin + +; to be called when the '4OP' or 'Pseudo 4OP' buttons are pressed instr fouroptrig + ; elicit the state and call the set instrument kstate = 0 if (gkinstr[4] == 1 || gkinstr[5] == 1) then kstate = 1 @@ -95,6 +130,8 @@ instr fouroptrig turnoff endin + +; show/hide the last two operators depending on the value of p4 instr fouropset istate = p4 iop = 2 @@ -113,50 +150,30 @@ instr fouropset od endin + +; randomise slider values. NB does not actually work for the check boxes but they are still in here instr randomiser - randomise + iop = 0 + while (iop < 4) do + FLsetVal_i random(30, 63), giop[iop][0] + FLsetVal_i random(0, 3), giop[iop][1] + FLsetVal_i random(0, 15), giop[iop][2] + FLsetVal_i random(0, 15), giop[iop][3] + FLsetVal_i random(0, 15), giop[iop][4] + FLsetVal_i random(0, 15), giop[iop][5] + FLsetVal_i random(0, 7), giop[iop][6] + FLsetVal_i random(0, 15), giop[iop][7] + FLsetVal_i random(0, 1), giop[iop][8] + FLsetVal_i random(0, 1), giop[iop][9] + FLsetVal_i random(0, 1), giop[iop][10] + FLsetVal_i random(0, 1), giop[iop][11] + iop += 1 + od + FLsetVal_i random(0, 7), giinstr[2] + FLsetVal_i random(0, 7), giinstr[3] turnoff endin -instr main - giopl, aL, aR opl 5 - outs aL, aR - - - iop1, iop2, iop3, iop4 oplinstrument giopl, gkinstr[0], gkinstr[1], gkinstr[2], gkinstr[3], gkinstr[4], gkinstr[5], gkinstr[6], gkinstr[7] - - - ; level, keyscale, attack, decay - kattack init 2 - kdecay init 13 - - oploperator iop1, gkop[0][0], gkop[0][1], gkop[0][2], gkop[0][3], gkop[0][4], gkop[0][5], gkop[0][6], gkop[0][7], gkop[0][8], gkop[0][9], gkop[0][10], gkop[0][11] - oploperator iop2, gkop[1][0], gkop[1][1], gkop[1][2], gkop[1][3], gkop[1][4], gkop[1][5], gkop[1][6], gkop[1][7], gkop[1][8], gkop[1][9], gkop[1][10], gkop[1][11] - oploperator iop3, gkop[2][0], gkop[2][1], gkop[2][2], gkop[2][3], gkop[2][4], gkop[2][5], gkop[2][6], gkop[2][7], gkop[2][8], gkop[2][9], gkop[2][10], gkop[2][11] - oploperator iop4, gkop[3][0], gkop[3][1], gkop[3][2], gkop[3][3], gkop[3][4], gkop[3][5], gkop[3][6], gkop[3][7], gkop[3][8], gkop[3][9], gkop[3][10], gkop[3][11] - -endin - - -instr 2 - ;inotes[] fillarray 48, 52, 53, 57, 60, 64, 65, 69 - ;inote = 56;inotes[int(random(0, lenarray(inotes)-1))]-36 - oplnote giopl, 0, 60, 120 - oplnote giopl, 0, 64, 120 - oplnote giopl, 0, 65, 120 - oplnote giopl, 0, 69, 120 - -endin - -instr 1 - inote notnum - iveloc veloc - oplnote giopl, 0, inote, iveloc -endin - -instr panic - oplpanic giopl -endin diff --git a/examples/1-chord_sequence.csd b/examples/1-chord_sequence.csd index 38e0ed6..b45ee0f 100644 --- a/examples/1-chord_sequence.csd +++ b/examples/1-chord_sequence.csd @@ -3,6 +3,12 @@ -odac +/* + csound-opl example 1 + Multiple channel chord sequence + + Richard Knight 2021 : examples are licensed as public domain equivalent : http://unlicense.org/ +*/ sr = 44100 kr = 4410 @@ -11,19 +17,17 @@ nchnls = 2 giopl init 0 -instr main - giopl, aL, aR opl - outs aL, aR - - oplpatchchange giopl, 0, 89 - oplpatchchange giopl, 1, 12 - oplpatchchange giopl, 2, 72 - oplpatchchange giopl, 3, 96 - - event_i "i", "sequencer", 0, p3 -endin +/* + Play notes with certain parameters: + kinstr : the instrument number to play + kduration : play duration + kbase : base MIDI note number + kintervals : intervals to form a chord with from kbase + ktimeinc : how much time to step with each interval + kreadmode : read intervals 0=forward, 1=reverse +*/ opcode playchord, 0, kkkk[]kk kinstr, kduration, kbase, kintervals[], ktimeinc, kreadmode xin ktime = 0 @@ -45,15 +49,40 @@ opcode playchord, 0, kkkk[]kk endif endop + +; audio output, voice setting and sequencer invocation +instr main + ; the synthesiser + giopl, aL, aR opl + outs aL, aR + + ; set the voices for four channels + oplpatchchange giopl, 0, 89 + oplpatchchange giopl, 1, 12 + oplpatchchange giopl, 2, 72 + oplpatchchange giopl, 3, 96 + oplpatchchange giopl, 4, 39 + + ; start the sequencer + event_i "i", "sequencer", 0, p3 +endin + + +; basic chord triggering pseudo-sequencer instr sequencer itempo = 120 ibeatduration = 60/itempo - kintervals[] fillarray 0, 4, 5, 9 - knotes[] fillarray 50, 54, 56, 48 + + ; intervals for chords, and notes for progression + kintervalsall[][] init 4, 4 + kintervalsall fillarray 0, 4, 5, 9, 4, 5, 7, 9, 0, 5, 7, 14, 0, 5, 7, 8 + knotes[] fillarray 50, 54, 56, 54 + knotedx init 0 kbeat metro itempo/60 kbar0 init 0 if (kbeat == 1) then + kintervals[] getrow kintervalsall, knotedx if (kbar0 == 0) then playchord 3, ibeatduration*4, knotes[knotedx], kintervals, 0, 0 elseif (kbar0 == 1) then @@ -64,6 +93,11 @@ instr sequencer playchord 4, ibeatduration, knotes[knotedx]+12, kintervals, ibeatduration/4, 1 endif + kbassnote = knotes[knotedx] + event "i", 5, 0, ibeatduration*0.2, kbassnote-24 + event "i", 5, ibeatduration*0.5, ibeatduration*0.16, kbassnote-12 + + if (kbar0 < 3) then kbar0 += 1 else @@ -78,24 +112,35 @@ instr sequencer endin +; play note on channel 0 instr 1 oplnote giopl, 0, p4, 120 endin + +; play note on channel 1 instr 2 oplnote giopl, 1, p4, 100 endin + +; play note on channel 2 instr 3 oplnote giopl, 2, p4, 100 endin + +; play note on channel 3 instr 4 oplnote giopl, 3, p4, 100 endin +; play note on channel 4 +instr 5 + oplnote giopl, 4, p4, 80 +endin + -; ============================================== i"main" 0 3600 diff --git a/examples/2-random_params.csd b/examples/2-random_params.csd index 37b951d..266406e 100644 --- a/examples/2-random_params.csd +++ b/examples/2-random_params.csd @@ -2,30 +2,35 @@ -odac -; ============================================== +/* + csound-opl example 2 + Parametric instrument modification with randomisation -sr = 44100 + Richard Knight 2021 : examples are licensed as public domain equivalent : http://unlicense.org/ + +*/ + +sr = 44100 kr = 4410 -nchnls = 2 -0dbfs = 1 +nchnls = 2 +0dbfs = 1 seed 0 instr main - giopl, aL, aR opl 0 + ; synthesiser + giopl, aL, aR opl outs aL, aR + ; play a note each second kmetro metro 1 schedkwhen kmetro, 0, 0, 2, 0, 1 + ; randomise instrument parameters, but always set as four operator iop1, iop2, iop3, iop4 oplinstrument giopl, int:k(random:k(0, 2)), int:k(random:k(0, 2)), random:k(0, 7), random:k(0, 7), 1, 1, int:k(random:k(0, 2)), int:k(random:k(0, 2)) - - ; level, keyscale, attack, decay - kattack init 2 - kdecay init 13 -;0 -15 freq mult + ; randomise all of the operators oploperator iop1, random:k(60, 63), random:k(0, 3), random:k(0, 15), random:k(0, 15), random:k(0, 15), random:k(0, 1), random:k(0, 7), 0, random:k(0, 2), random:k(0, 2), random:k(0, 2), random:k(0, 2) oploperator iop2, random:k(60, 63), random:k(0, 3), random:k(0, 15), random:k(0, 15), random:k(0, 15), random:k(0, 1), random:k(0, 7), 0, random:k(0, 2), random:k(0, 2), random:k(0, 2), random:k(0, 2) oploperator iop3, random:k(60, 63), random:k(0, 3), random:k(0, 15), random:k(0, 15), random:k(0, 15), random:k(0, 1), random:k(0, 7), 0, random:k(0, 2), random:k(0, 2), random:k(0, 2), random:k(0, 2) @@ -33,24 +38,15 @@ instr main endin +; play a random note from the array instr 2 inotes[] fillarray 48, 52, 53, 57 inote = inotes[int(random(0, lenarray(inotes)-1))]+24 oplnote giopl, 0, inote, 120 endin -instr 3 - inote = 48+24 - oplnote giopl, 1, inote, 120 - oplnote giopl, 1, inote+4, 120 - oplnote giopl, 1, inote+5, 120 - oplnote giopl, 1, inote+9, 120 -endin - - -; ============================================== i"main" 0 3600 diff --git a/examples/3-controlchanges.csd b/examples/3-controlchanges.csd index 93749b1..f2ae31d 100644 --- a/examples/3-controlchanges.csd +++ b/examples/3-controlchanges.csd @@ -3,6 +3,12 @@ -odac -m0 +/* + csound-opl example 3 + Control change, pitch bend, bank change and patch change with randomly selected patches + + Richard Knight 2021 : examples are licensed as public domain equivalent : http://unlicense.org/ +*/ sr = 44100 kr = 4410 @@ -10,40 +16,45 @@ nchnls = 2 0dbfs = 1 seed 0 +; do bank changes: causes device reset which will stop current notes/possibly cause clicks but demonstrates nonetheless +gichangebank = 0 +gistartbank = 0 + +; loop through each bank and play a note or two for each instr main giopl, aL, aR opl outs aL, aR gSbanks[] oplbanknames giopl - index = 0 itime = 0 inote = 0 inotes[] fillarray 50, 52, 64, 56, 53, 59, 62 - while (index < lenarray(gSbanks)) do - event_i "i", "play", itime, 2, index, inotes[inote], 0 + while (gistartbank < lenarray(gSbanks)) do + event_i "i", "play", itime, 2, gistartbank, inotes[inote], 0 if (inote < lenarray(inotes)-1) then inote += 1 else inote = 0 endif if (random(0, 1) > 0.5) then - event_i "i", "play", itime+0.5, 0.5, index, inotes[inote], 1 + event_i "i", "play", itime+0.5, 0.5, gistartbank, inotes[inote], 1 endif itime += 1 - index += 1 + gistartbank += 1 od p3 = itime endin +; set the patch, play the note, optionally set the bank and call the control change instrument instr play ibank = p4 inote = p5 ichannel = p6 ipatch random 0, 127 - prints sprintf("%d-%d (%s)\n", ibank, ipatch, gSbanks[ibank]) - if (ichannel == 0) then + if (ichannel == 0 && gichangebank = 1) then + prints sprintf("%d-%d (%s)\n", ibank, ipatch, gSbanks[ibank]) oplsetbank giopl, ibank endif oplpatchchange giopl, ichannel, ipatch @@ -52,6 +63,7 @@ instr play endin +; conditionally add a pitch bend and control change instr cc ichannel = p4 if (random(0, 1) > 0.6) then @@ -60,8 +72,8 @@ instr cc oplpitchbend giopl, ichannel, kbend endif - - if (random(0, 1) > 0.6) then + ; control change for type 1 (modulation) + if (random(0, 1) > 0.4) then kmod linseg 0, p3*0.7, 255, p3*0.3, 0 oplcontrolchange giopl, ichannel, 1, kmod endif @@ -69,7 +81,6 @@ endin -; ============================================== i"main" 0 3600 -- cgit v1.2.3