// title: Bjorklund Toy // author: rinalka1227 // description: // Toy built to facilitate experimenting with Bjourklund to step through two different 'chords'. // The "onChord" is used in some way for each Bjorklund hit, and the "offChord" for all other times. // The chords can be played as a chord or sequenced in some way. // Chords can be generated with white notes only or all notes. // In addition, there are controls to play with various related patterns // All of the sounds are generated with the Pluck ugen, played through JPverb // code: //Bjorklund Pluck Toy //Step1: ( s.options.memSize_(65536 * 4); s.reboot; s.freeAll; Pdef.removeAll; ) //Step2: ( ~bpm = 110; t = ~bpm/60; t = TempoClock.new(~bpm/60).permanent_(false); ~whiteNotes = [// white notes index 0 to 28 36,38,40,41,43,45,47, 48,50,52,53,55,57,59, 60,62,64,65,67,69,71, 72,74,76,77,79,81,83, 84]; ~revBus = Bus.audio(s,2); ~makeSynths.value; ~onChordType = 2; ~onChordStartIndex = 14; ~onChordNumNotes = 4; ~onChord = ~newChordByType.value(~onChordType,~onChordStartIndex,~onChordNumNotes); ~onPattern = 0; //a chord ~switchPattern.value("on"); ~offChordType = 3; ~offChordStartIndex = 6; ~offChordNumNotes = 4; ~offChord = ~newChordByType.value(~offChordType,~offChordStartIndex,~offChordNumNotes); ~offPattern = 1; //seq up ~switchPattern.value("off"); ~makePBjorklundControlPanel.value; //and wait till the button gets pressed // functions ~makeSynths = { SynthDef("plucking", { arg outbus = 0, amp = 0.2, sAmp=0.5, freq = 440, pluckDecay = 5, coef = 0.1, pan = 0, atk = 0.01, sus = 0.05, rel = 0.5, trigger = 0, dynamic = 0.5; var env = EnvGen.kr(Env.linen(atk,sus,rel,level:1, curve:1),doneAction:2); var snd = Pluck.ar( in: BrownNoise.ar(amp), trig: Impulse.kr(trigger), maxdelaytime: 0.005, delaytime: freq.reciprocal, decaytime: pluckDecay, coef: coef ); snd = LeakDC.ar(snd).clip2; snd = Pan2.ar (snd, pan); Out.ar(0, snd * env * sAmp); Out.ar(outbus, snd * env * dynamic); }).add; SynthDef(\aJPverb, { arg inBus=0, outBus = 0, tailTime = 1, damp = 0.25, pan=0, size = 1.0, eDiff= 0.707, mDepth= 0.1, mFreq= 2.0, low= 1.0, mid= 1.0, high= 1.0, lowcut= 500.0, highcut= 2000.0, //jpVol = 0.5, straightOutVol = 0.75; var sig, rev; sig = In.ar(~revBus,2); rev = JPverb.ar( sig, t60: tailTime, damp: damp, size: size, earlyDiff: eDiff, modDepth: mDepth, modFreq: mFreq, low: low, mid: mid, high: high, lowcut: lowcut, highcut: highcut, ); Out.ar(outBus, rev * straightOutVol); }).add; //Pdefn's for riff1 Pdefn(\hits, 5); Pdefn(\beats, 8); Pdefn(\onPattern,~onPattern); Pdefn(\offPattern,~offPattern); PLbindef(\riff1, \instrument, \plucking, \outbus, ~revBus, \trigger, 0, \midinote, Pbjorklund( Pdefn(\hits),Pdefn(\beats)).linlin(0, 1, Pdefn(\offPattern), Pdefn(\onPattern)), \dur, 0.5, \coef, 0.75, \pluckDecay, 5, \atk, 0.01, \amp, 1, \sAmp, 0.5, \pan, Pbjorklund(Pdefn(\hits), Pdefn(\beats)).linlin(0, 1, -1,1), \dynamic, 0.25, \addAction, 0, ); }; //~makePBjorklundControlPanel.value ~makePBjorklundControlPanel = { var hits=5, hitsNumBox = hits, beats=8, beatsNumBox = beats, numNotesInOnChord=4,numNotesInOnChordBox=4, numNotesInOffChord=4,numNotesInOffChordBox=4, bpmNumBox, startOnI=14, startOffI=14,endOnI=28, endOffI=28, riffTone=0.1, panLeft= -1, panRight=1, blank, // a blank line used for spacing label, knob, button, numBox,popUpMenu,slider,rangeSlider, //standard gui objects startOnIBox,endOnIBox,startOffIBox,endOffIBox, //gui objects that get written to startOnNBox,endOnNBox,startOffNBox,endOffNBox, startOnN, startOffN,endOnN, endOffN; //window w = Window("Control Panel", Rect.new(470,300,502,235),resizable:true, border:true) .background_(Color.grey(0.05)).front .alwaysOnTop = true; w.view.decorator_(FlowLayout(w.bounds,4@4, 4@4)); ~topPanel = UserView(w, 494@45).background_(Color.rand(0.7,0.9)); ~topPanel.decorator_(FlowLayout(~topPanel.bounds, 4@4, 4@4)); ~subPanel= Array.fill(4, { arg view; view = UserView(w, 120@180).background_(Color.rand(0.7,0.9)); view.decorator_(FlowLayout(view.bounds, 4@4, 4@4)); }); //Start Stop Button button = Button(~topPanel, Rect(0,0, 100, 38)) .font_(Font("Monaco", 16)) .states_([ ["Press to Stop", Color.black, Color.green], ["Press to Run", Color.black, Color.red]]) .value_(1) .action_({ arg bu; if ( bu.value == 1, {~riff1.stop; ~jpRev.free; }, {~riff1.play(t).quant_(1.ceil); ~jpRev = Synth (\aJPverb,[\inbus, ~revBus, \outbus, 0, \damp, 0.05, \tailTime, 3,\straightOutVol, 0.75]).run; } ); }); blank = StaticText(~topPanel, Rect(0,0,20,5)).string_(" "); //Hits Beats and BPM knobs knob = Knob.new(~topPanel, Rect(0, 0, 30, 30)) .value_(hits.linlin(1,20,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; hitsNumBox.value_(val.value.linlin(0,1,1,32).asInteger); }) .mouseUpAction_({ arg val; hits = val.value.linlin(0,1,1,32).asInteger; if (hits > beats, {hits = beats; ("can't have more hits than beats! Hits and Beats now " + hits + " " +beats).postln; }); Pdefn(\hits, hits); }); label = StaticText(~topPanel, Rect(0,0,25,25)) .string_("Hits") .font_(Font("Monaco", 14)); hitsNumBox = NumberBox(~topPanel, Rect(0,0,25,25)) .value_(hits) .font_(Font("Monaco", 14)); blank = StaticText(~topPanel, Rect(0,0,20,5)).string_(" "); knob = Knob.new(~topPanel, Rect(0, 0, 30, 30)) .value_(beats.linlin(1,20,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; beatsNumBox.value_(val.value.linlin(0,1,2,32).asInteger) }) .mouseUpAction_({ arg val; beats = val.value.linlin(0,1,2,32).asInteger; Pdefn(\beats, beats); }); label = StaticText(~topPanel, Rect(0,0,35,25)) .string_("Beats") .font_(Font("Monaco", 14)); beatsNumBox = NumberBox(~topPanel, Rect(0,0,25,25)) .value_(beats) .font_(Font("Monaco", 14)); blank = StaticText(~topPanel, Rect(0,0,20,5)).string_(" "); //BPM knob knob = Knob.new(~topPanel, Rect(0, 0, 30, 30)) .value_(~bpm.linlin(30,140,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({arg val; ~bpm = val.value.linlin(0,1,30,140).asInteger; bpmNumBox.value_(~bpm);}) .mouseUpAction_({ arg val; ~bpm = val.value.linlin(0,1,30,140).asInteger; bpmNumBox.value_(~bpm); t.tempo = (~bpm/60); }); label = StaticText(~topPanel, Rect(0,0,30,25)) .string_("BPM") .font_(Font("Monaco", 14)); //beats per minute numberbox bpmNumBox = NumberBox(~topPanel, Rect(0,0,30,25)) .value_(~bpm) .font_(Font("Monaco", 14)) .decimals_(0); //On Pattern Type Selection blank = StaticText(~subPanel[0], Rect(0,0,200,3)).string_(" "); label = StaticText(~subPanel[0], Rect(0,0,245,14)) .string_("On Pattern").align_(\left) .font_(Font("Monaco", 12)); popUpMenu= PopUpMenu (~subPanel[0], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["play chord hit", "seq forward", "seq back", "random", "rest"]) .background_(Color.rand(0.6,0.9)) .value_(0) .action_({ arg obj; ~onPattern = obj.value; ~switchPattern.value("on"); }); //type of chord blank = StaticText(~subPanel[0], Rect(0,0,200,2)).string_(" "); label = StaticText(~subPanel[0], Rect(0,0,245,14)) .string_("Type of Chord").align_(\left) .font_(Font("Monaco", 12)); popUpMenu= PopUpMenu (~subPanel[0], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["random white notes", "step white notes", "every 2nd white note", "every 3rd white note", "random chromatic", "chromatic", "major seconds", "minor thirds"]) .font_(Font("Monaco", 10)) .background_(Color.rand(0.6,0.9)) .value_(2) .action_({ arg obj; ~onChordType = obj.value; ~onChord = ~newChordByType.value(~onChordType,~onChordStartIndex,~onChordNumNotes ); ~switchPattern.value("on"); }); // number of notes in the chord knob = Knob.new(~subPanel[0], Rect(0, 0, 25, 25)) .value_(numNotesInOnChord.linlin(1,8,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; numNotesInOnChordBox.value_(val.value.linlin(0,1,1,8).asInteger); }) .mouseUpAction_({ arg val; ~onChordNumNotes = val.value.linlin(0,1,1,8).asInteger; ~onChord = ~newChordByType.value(~onChordType,~onChordStartIndex ,~onChordNumNotes); ~switchPattern.value("on"); }); label = StaticText(~subPanel[0], Rect(0,0,25,25)) .string_("# notes in chord").align_(\topLeft) .font_(Font("Monaco", 10)); numNotesInOnChordBox = NumberBox(~subPanel[0], Rect(0,0,20,20)) .value_(numNotesInOnChord) .font_(Font("Monaco", 14)); blank = StaticText(~subPanel[0], Rect(0,0,2,30)).string_(" "); //start index for the notes in the chord knob = Knob.new(~subPanel[0], Rect(0, 0, 25, 25)) .value_(startOnI.linlin(0,28,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; startOnIBox.value_(val.value.linlin(0,1,0,28).asInteger); startOnNBox.string_(~whiteNotes[val.value.linlin(0,1,0,28).asInteger].midiname()) }) .mouseUpAction_({ arg val; ~onChordStartIndex = val.value.linlin(0,1,0,28).asInteger; ~onChord = ~newChordByType.value(~onChordType,~onChordStartIndex ,~onChordNumNotes); ~switchPattern.value("on"); }); label = StaticText(~subPanel[0], Rect(0,0,25,25)) .string_("start note").align_(\topLeft) .font_(Font("Monaco", 10)); startOnIBox = NumberBox(~subPanel[0], Rect(0,0,20,20)) .value_(startOnI) .font_(Font("Monaco", 14)); startOnNBox = StaticText(~subPanel[0], Rect(0,0,25,25)) .string_(~whiteNotes[startOnI].midiname()) .font_(Font("Monaco", 14)); //Off Pattern Type Selection blank = StaticText(~subPanel[1], Rect(0,0,200,3)).string_(" "); label = StaticText(~subPanel[1], Rect(0,0,245,14)) .string_("Off Pattern").align_(\left) .font_(Font("Monaco", 12)); popUpMenu= PopUpMenu (~subPanel[1], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["play chord hit", "seq forward", "seq back", "random", "rest"]) .background_(Color.rand(0.6,0.9)) .value_(1) .action_({ arg obj; ~offPattern = obj.value; ~switchPattern.value("off"); }); //type of chord blank = StaticText(~subPanel[1], Rect(0,0,200,2)).string_(" "); label = StaticText(~subPanel[1], Rect(0,0,245,14)) .string_("Type of Chord").align_(\left) .font_(Font("Monaco", 12)); popUpMenu= PopUpMenu (~subPanel[1], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["random white notes", "step white notes", "every 2nd white note", "every 3rd white note", "random chromatic", "chromatic", "major seconds", "minor thirds"]) .font_(Font("Monaco", 10)) .background_(Color.rand(0.6,0.9)) .value_(2) .action_({ arg obj; ~offChordType = obj.value; ~offChord = ~newChordByType.value(~offChordType,~offChordStartIndex,~offChordNumNotes ); ~switchPattern.value("off"); }); // number of notes in the off chord knob = Knob.new(~subPanel[1], Rect(0, 0, 25, 25)) .value_(numNotesInOffChord.linlin(1,8,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; numNotesInOffChordBox.value_(val.value.linlin(0,1,1,8).asInteger); }) .mouseUpAction_({ arg val; ~offChordNumNotes = val.value.linlin(0,1,1,8).asInteger; ~offChord = ~newChordByType.value(~offChordType,~offChordStartIndex ,~offChordNumNotes); ~switchPattern.value("off"); }); label = StaticText(~subPanel[1], Rect(0,0,25,25)) .string_("# notes in chord").align_(\topLeft) .font_(Font("Monaco", 10)); numNotesInOffChordBox = NumberBox(~subPanel[1], Rect(0,0,20,20)) .value_(numNotesInOnChord) .font_(Font("Monaco", 14)); blank = StaticText(~subPanel[1], Rect(0,0,2,30)).string_(" "); //start index for the notes in the off chord knob = Knob.new(~subPanel[1], Rect(0, 0, 25, 25)) .value_(startOnI.linlin(0,28,0,1)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .action_({ arg val; startOffIBox.value_(val.value.linlin(0,1,0,28).asInteger); startOffNBox.string_(~whiteNotes[val.value.linlin(0,1,0,28).asInteger].midiname()) }) .mouseUpAction_({ arg val; ~offChordStartIndex = val.value.linlin(0,1,0,28).asInteger; ~offChord = ~newChordByType.value(~offChordType,~offChordStartIndex ,~offChordNumNotes); ~switchPattern.value("off"); }); label = StaticText(~subPanel[1], Rect(0,0,25,25)) .string_("start note").align_(\topLeft) .font_(Font("Monaco", 10)); startOffIBox = NumberBox(~subPanel[1], Rect(0,0,20,20)) .value_(startOnI) .font_(Font("Monaco", 14)); startOffNBox = StaticText(~subPanel[1], Rect(0,0,25,25)) .string_(~whiteNotes[startOnI].midiname()) .font_(Font("Monaco", 14)); //Dynamics label = StaticText(~subPanel[2], Rect(0,0,120,12)) .string_("Dynamics").align_(\left) .font_(Font("Arial",12)); popUpMenu= PopUpMenu (~subPanel[2], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["loud, soft", "loud soft soft", "loud soft*3", "bjork(loud,soft)", "flat 0.5"," random"]) .background_(Color.rand(0.6,0.9)) .value_(4) .action_({ arg obj; switch (obj.value, 0, {~riff1.dynamic = Pseq([0.65,0.45], inf)}, 1, {~riff1.dynamic = Pseq([0.65,Pseq([0.45],2)], inf)}, 2, {~riff1.dynamic = Pseq([0.65,Pseq([0.45],3)], inf)}, 3, {~riff1.dynamic = Pbjorklund(hits,beats).linlin(0, 1, 0.65, 0.45)}, 4, {~riff1.dynamic = 0.4}, 5, {~riff1.dynamic = Prand([0.75,0.65,0.55,0.45,0.35],inf)}, ); }); // Tone blank = StaticText(~subPanel[2], Rect(0,0,200,5)).string_(" "); label = StaticText(~subPanel[2], Rect(0,0,120,12)) .string_("Tone pattern").align_(\left) .font_(Font("Arial",12)); popUpMenu= PopUpMenu (~subPanel[2], Rect(0,0,112,20)) .items_(["hard + knob", "soft + knob", "rand + knob", "just knob"]) .background_(Color.rand(0.6,0.9)) .value_(3) .action_({ arg obj; switch (obj.value, 0, {~riff1.coef = Prand([0, 0.05, 0.1, 0.15, 0.2], inf) +(riffTone/2) }, 1, {~riff1.coef = Prand([0.35, 0.4, 0.45, 0.5], inf) +(riffTone/2)}, 2, {~riff1.coef = Prand([0.5,0.4,0.3,0.1,0], inf)+(riffTone/2)}, 3, {~riff1.coef = Pseq([riffTone],inf)} ); }); knob = Knob.new(~subPanel[2], Rect(0, 0, 25, 25)) .color_([Color(0.8,0.4,0.4),Color(0.1,0.1,0.1),Color(1,1,1),Color(0,0,0)]) .value_(0.75) .action_({ arg val; riffTone = val.value; ~riff1.coef = val.value.linlin(0,1,0.01,0.99); }); label = StaticText(~subPanel[2], Rect(0,0,70,25)) .string_("Tone") .font_(Font("Monaco", 10)); //Duration blank = StaticText(~subPanel[2], Rect(0,0,200,5)).string_(" "); label = StaticText(~subPanel[2], Rect(0,0,120,12)) .string_("Duration pattern").align_(\left) .font_(Font("Arial",12)); popUpMenu= PopUpMenu (~subPanel[2], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["8th 16th 16th", "8th 16th 16th 16th", "bjork(8th,quarter)", "bjork(16th,8th)", "8th", "quarter", "quarter triplets", "triplets"]) .background_(Color.rand(0.6,0.9)) .value_(4) .action_({ arg obj; switch (obj.value, 0, {~riff1.dur = Pseq([0.5,0.25,0.25], inf)}, 1, {~riff1.dur = Pseq([0.5,Pseq([0.25],3)], inf)}, 2, {~riff1.dur = Pbjorklund(hits,beats).linlin(0, 1, 0.5, 1)}, 3, {~riff1.dur = Pbjorklund(hits,beats).linlin(0, 1, 0.25, 0.5)}, 4, {~riff1.dur = 0.5}, 5, {~riff1.dur = 1}, 6, {~riff1.dur = Pseq([2/3],inf)}, 7, {~riff1.dur = Pseq([1/3],inf)}, ); }); //Pan blank = StaticText(~subPanel[3], Rect(0,0,112,2)).string_(" "); label = StaticText(~subPanel[3], Rect(0,0,112,12)) .string_("Pan pattern").align_(\left) .font_(Font("Arial",12)); popUpMenu = PopUpMenu (~subPanel[3], Rect(0,0,112,20)) .allowsReselection_(true) .items_(["fixed", "bounce", "random", "bjork bounce"]) .background_(Color.rand(0.6,0.9)) .value_(3) .action_({ arg obj; ~panPattern = obj.value; switch (~panPattern, 0, {~riff1.pan = Pseq([(panLeft+panRight)/2],inf);}, 1, {~riff1.pan = Pseq([panLeft,panRight],inf);}, 2, {~riff1.pan = Prand([panLeft,(panLeft+panRight)/2,panRight],inf);}, 3, {~riff1.pan = Pbjorklund(Pdefn(\hits), Pdefn(\beats)).linlin(0, 1, panLeft,panRight);} ); }); rangeSlider = RangeSlider(~subPanel[3], Rect(0, 0, 112, 14)) .lo_(0) .hi_(1) .activeLo_(0.25) .activeHi_(0.75) .action_({ arg slider; panLeft = slider.lo.linlin(0,1,-1,1); panRight = slider.hi.linlin(0,1,-1,1); switch (~panPattern, 0, {~riff1.pan = Pseq([(panLeft+panRight)/2],inf);}, 1, {~riff1.pan = Pseq([panLeft,panRight],inf);}, 2, {~riff1.pan = Prand([panLeft,(panLeft+panRight)/2,panRight],inf);}, 3, {~riff1.pan = Pbjorklund(Pdefn(\hits), Pdefn(\beats)).linlin(0, 1, panLeft,panRight);} ); }); // jp reverb blank = StaticText(~subPanel[3], Rect(0,0,200,5)).string_(" "); label = StaticText(~subPanel[3], Rect(0,0,120,12)) .string_("JPVerb") .font_(Font("Arial",12)) .align_(\left); label= StaticText(~subPanel[3], Rect(0,0,40,10)) .string_("Damp") .font_(Font("Arial",10)) .align_(\left); slider = Slider(~subPanel[3], Rect.new(0,20,60,14)) .background_(Color.rand(0.7,0.8)) .valueAction_(0.25) .action_({ arg obj; ~jpRev.set(\damp, obj.value.linlin(0,1, 0.000,0.99)); }); label = StaticText(~subPanel[3], Rect(0,0,40,10)) .string_("Tail Time") .font_(Font("Arial",10)) .align_(\left); slider = Slider(~subPanel[3], Rect.new(0,20,60,14)) .background_(Color.rand(0.7,0.8)) .value_(0.25) .valueAction_(0.25) .action_({ arg obj; ~jpRev.set(\tailTime, obj.value.linlin(0,1, 0.1,20)); }); //volume label = StaticText(~subPanel[3], Rect(0,0,120,12)) .string_("Volumes").align_(\left) .font_(Font("Arial",12)) .align_(\left); slider = Slider(~subPanel[3], Rect.new(0,20,40,14)) .background_(Color.rand(0.7,0.8)) .valueAction_(0.5) .action_({ arg obj; obj.value; ~riff1.sAmp = obj.value.linlin(0,1, 0,1 ); }); label = StaticText(~subPanel[3], Rect(0,0,50,10)) .string_("Riff Straight" ) .font_(Font("Arial",10)) .align_(\left); slider = Slider(~subPanel[3], Rect.new(0,20,40,14)) .background_(Color.rand(0.7,0.8)) .valueAction_(0.85) .action_({ arg obj; ~jpRev.set(\straightOutVol, obj.value.linlin(0,1, 0,1 )); }); label = StaticText(~subPanel[3], Rect(0,0,50,10)) .string_("jpVerb riff") .font_(Font("Arial",10)) .align_(\left); }; ~newChordByType = { arg type, startIndex,numberOfNotes; var tempIndex,check,chord; chord = Array.fill(numberOfNotes, { Rest() }); numberOfNotes.do {arg index = 0; switch (type, 0, {tempIndex = rrand(startIndex,28); check=0}, //white note random 1, {tempIndex = startIndex + index; check=0}, //white note mode 2, {tempIndex = startIndex + (index*2); check=0}, //white note chord 3, {tempIndex = startIndex +( index*3); check=0}, //white note wide chord 4, {tempIndex = rrand(startIndex+36,48); check=1}, //chromatic random 5, {tempIndex = startIndex+36 + index; check=1}, //chromatic scale 6, {tempIndex = startIndex+36 + (index*2); check=1}, //chromatic whole note check 7, {tempIndex = startIndex+36 +( index*3); check=1}, //chromatic minor thirds scale ); if (check == 0, {if (tempIndex > 28, {tempIndex = 28; "WARNING INDEX TOO BIG".postln;}); chord[index] = ~whiteNotes[tempIndex]; }, {if (tempIndex > 84, {tempIndex = 28; "WARNING INDEX TOO BIG".postln;}); chord[index] = tempIndex; }); }; ("new chord is " + chord).postln; chord; }; ~switchPattern = {arg onOrOff; if (onOrOff == "on", {switch (~onPattern, 0, {Pdefn(\onPattern, ~onChord)}, 1, {Pdefn(\onPattern, Pseq(~onChord,inf))}, 2, {Pdefn(\onPattern, Pseq(~onChord.reverse,inf))}, 3, {Pdefn(\onPattern, Prand(~onChord,inf))}, 4, {Pdefn(\onPattern, Pseq([Rest()],inf))}, )}, {switch (~offPattern, 0, {Pdefn(\offPattern, ~offChord)}, 1, {Pdefn(\offPattern, Pseq(~offChord,inf))}, 2, {Pdefn(\offPattern, Pseq(~offChord.reverse,inf))}, 3, {Pdefn(\offPattern, Prand(~offChord,inf))}, 4, {Pdefn(\offPattern, Pseq([Rest()],inf))}, )} ) }; )