\ Interactive Control via midi guitar interface \ by Steev Hise, 1998 include hwork:roland_loops include hwork:CUTOFF include hwork:resonance ANEW TASK-LOOP_CONTROL \ OB.JOB JOB-AUTO 30000 constant MAXDUR ( in samples ) 000 constant MINDUR 221183 constant SAMPLELENGTH ( this will change, max=221183 ) 15000 constant SAMPLERATE 10000 constant DEFAULT-LOOPLENGTH ( default length of loop ) 52 constant MINNOTE 74 constant MAXNOTE \ these next 2 are randomness parameters for the autonomica word \ variable autorange \ 512 autorange ! \ variable autosub \ 385 autosub ! variable start 0 start ! variable loop variable end variable duration variable T 111 T ! variable note variable step ( this is the # of samples we increment at atime ) 100 step ! variable looplength DEFAULT-LOOPLENGTH looplength ! ( distance from start to end of loop ) looplength @ end ! 6 ARRAY starts ( one for each string - actually only need 4, but...) 0 1 starts ! 0 2 starts ! 0 3 starts ! 0 4 starts ! 6 ARRAY ends 0 1 ends ! 0 2 ends ! 0 3 ends ! 0 4 ends ! DEFER control16 DEFER control17 : CHANNEL2TONE ( midichannel --, tone ) CASE 1 of 111 endof 2 of 112 endof 3 of 211 endof 4 of 212 endof 6 of 248 endof ENDCASE ; : HOLD.STRING ( channel --, send hold command on channel ) dup channel2tone T ! ( switch tones ) \ midi-channel @ swap ( get old midi channel ) midi.channel! ( change to the one we want ) 64 127 midi.control ." holding on channel " midi-channel @ . ." tone " T @ . CR \ midi.channel! ( change back to old channel ) ; : KILL.STRING ( channel --, kill everything on a channel ) midi-channel @ swap midi.channel! ( change to the one we want ) 64 0 midi.control midi.kill ." killed channel " midi-channel @ . CR midi.channel! ; : PANIC ( --, kill every channel and normalize everything midi.panic ( turn off all notes ) midi.normalize ( reset everything to reasonable defaults ) midi.clear DEFAULT-LOOPLENGTH looplength ! 111 112 211 212 0 res 0 res 0 res 0 res 111 112 211 212 127 cutoff 127 cutoff 127 cutoff 127 cutoff ." PANIC!! everything shut off!" CR ; : STARTKNOB ( controllermsg --, fine tune startpoint ) \ scan around between the original startpoint and the endpoint dup \ first get the start and end for this channel midi-channel @ ends @ midi-channel @ starts @ - 128 / * ( multiply the controller data by 128th of the space available) midi-channel @ starts @ + ( then add it to the present value ) SAMPLELENGTH min ( make sure not way too big ) start ! midi-channel @ 1 midi.channel! T @ start @ startpt T @ start @ looppt midi.channel! ." s" . cr? ; : ENDKNOB ( controllermsg --, fine tune the endpoint ) \ scan the endpt all the way up to the next fret if desired dup looplength @ 128 / * midi-channel @ ends @ + SAMPLELENGTH min ( make sure no way too big ) end ! midi-channel @ 1 midi.channel! T @ end @ endpt midi.channel! ." e" . cr? ; : CUTOFFKNOB ( controller --, changes filter cutoff of current tone ) midi-channel @ swap 1 midi.channel! T @ swap cutoff midi.channel! ; : RESONKNOB ( controller --, changes resonance of current tone ) midi-channel @ swap 1 midi.channel! T @ swap res midi.channel! ; : PARSE.KEY ( uppercase key --, does stuff ) CASE ASCII 1 OF 1 hold.string endof ASCII 2 OF 2 hold.string endof ASCII 3 OF 3 hold.string endof ASCII 4 OF 4 hold.string endof ASCII ! OF 1 kill.string endof ASCII @ OF 2 kill.string endof ASCII # OF 3 kill.string endof ASCII $ OF 4 kill.string endof ASCII C OF midi.clear endof ASCII K OF panic endof ASCII F OF 'C cutoffknob IS control16 'C resonknob IS control17 ." switched to filtermode." CR endof ASCII L OF 'C startknob IS control16 'C endknob IS control17 ." switched to loopmode." CR endof ASCII 0 OF 0 1 starts ! 0 2 starts ! 0 3 starts ! 0 4 starts ! 0 1 ends ! 0 2 ends ! 0 3 ends ! 0 4 ends ! 0 start ! 0 end ! DEFAULT-LOOPLENGTH looplength ! CR ." loop points zeroed!!" CR endof \ default ." keys:" CR ." 1-4 holds that channel. shift 1-4 kills it." CR ." F/L for filter/loop modes." CR \." A/S to start/stop autonomica mode." CR \." [/] to decrease/increase autonomic density." CR ." K to panic." CR ." Q to quit." CR ." ----------------------------------" CR ENDCASE ; : PLAY.NOTE ( note velocity --, plays note ) swap MINNOTE MAXNOTE clipto ( constrain to note range) MINNOTE - SAMPLELENGTH MAXNOTE MINNOTE - / * start ! midi-channel @ dup dup dup start @ swap starts ! ( assign to array of start points ) start @ looplength @ + end ! end @ swap ends ! 4 min ( make sure midi channel isnt too big) channel2tone T ! ( assign tone to change and play) T @ 248 = if 2drop exit then ( if its the 6th string, we're done ) 1 midi.channel! ( sysex can only be on channel 1!) T @ start @ startpt T @ start @ looppt T @ end @ endpt 4 min ( make sure midi channel isnt too big) midi.channel! ( switch to the right midi channel) 72 swap midi.alloff ( turn off everything on that channel first) midi.noteon CR ." channel: " midi-channel @ . ." tone: " T @ . ." start: " start @ . ." end: " end @ . ." looplgth: " looplength @ . CR ; : MANUAL.NOTE ( note velocity --, runs play.note ) 7 mp.channel@ - midi.channel! ( munge the midi channel around ) play.note ; : STOP.NOTE ( note velocity --, stops note ) drop drop midi.lastoff ; : CONTROL.MESSAGE ( controller value --, processes message ) over CASE 7 of ( volume ) \ 7 swap midi.control \ alter the looplength! up to about 5 times normal 5 * DEFAULT-LOOPLENGTH * 128 / 100 max looplength ! ." looplength changed to " looplength @ . cr midi.clear endof 16 of control16 midi.clear endof 17 of control17 midi.clear endof drop ENDCASE ." channel: " midi-channel @ . ." start: " start @ . ." end: " end @ . ." controller: " . cr \ midi.clear ( clear out the glut of extra controller messages! ) ; : BENDER ( lo hi --, process bend message ) hex 7lo7hi->14 dup . midi.bend decimal \ midi.clear ; : LOOP.TERM ( -- ) \ freeall: scr-xy \ free: scr-xy panic ( reset all midi stuff and turn everything off ) mp.reset ; : LOOP_CONTROL ( -- ) \ dxy.init ." looplength= " looplength @ . cr HMSL-GRAPHICS OFF 5000 midi-recv-size ! midi.term midi.init ( reallocate input buffer ) 10 time-advance ! mp.reset 'C MANUAL.NOTE MP-ON-VECTOR ! 'C STOP.NOTE MP-OFF-VECTOR ! 'C CONTROL.MESSAGE MP-CONTROL-VECTOR ! \ 'C BENDER MP-BEND-VECTOR ! 'C PARSE.KEY KEY-PARSER ! 'C startknob IS control16 'C endknob IS control17 midi.parser.on \ stuff{ 'C autonomica }stuff: job-auto \ 0 put.duration: job-auto hmsl loop.term ; if.forgotten loop.term cr ." Enter: LOOP_CONTROL" cr