\ io \ \ io_input \ input parsing component of io. \ \ \ these input components send data and messages primarily to the hp_ objects \ (see the file io_hp) via the matrix (see the file io_matrix). An exception \ is that the players (see: io_output) derive their pulse value from the \ pulse.trackers defined in this file. The other exception is that the \ banalyzers may start and stop the performance via the global control \ procedures (IO.START and IO.STOP respectively) stated in the file io_glob, and \ defined in io_top. \ \ io_input ====> io_matrix io_hp io_output io_top \ ^^^^^^^^ ^^^^^^^^^ \ parser ----------------------> hp.noteon \ -----> hp.noteoff \ pTracker ----------------------------------> player \ \ banalyzer ================================================> io.start \ =====> io.stop \ \ input parameters that are analyzed (banalyzed?) are the following: \ \ parameter dim# selector description \ \ pulse - parser_time_dim# - time between sucessive ON events \ volume - parser_vol_dim# - volume level \ pitch - parser_pitch_dim# - midi pitch bend and note number \ density - n/a - see below \ \ additionally, three classes of input parsers are available: \ \ mono.parser - for monophonic input on a single midi channel \ poly.parser - polyphonic input on a single channel \ guitar.parser - six monophonic inputs on six consecutive channels \ \ the pulse, volume and pitch parameters are analyzed in a similarly across \ the various parser types. Density, however, is handled differently between \ the parsers. A mono.parser considers the sustain time of a note as the \ density; a poly.parser or guitar.parser will use the vertical polyphony \ (number of notes in a chord) as the density. \ \ \ see the file io_top for more information. \ \ \ constructor: Han-earl Park \ copyright 2008 buster & friends' C-ALTO Labs \ \ www.busterandfriends.com/io \ \ (Edinburgh, November 1996 - \ (London, August 1997 - \ (Den Haag, October 1997 - \ (Valencia, March 1999 - \ (Southampton, May 2000 - \ (Cork, April 2006 - \ \ (Cork, October 2008 - \ \ REV: 0.0.1 alpha (Southampton, October 2000) \ REV: 0.0.1 beta (Southampton, November 2000) \ REV: 0.0.1 alpha++ (Southampton, July 2004) \ REV: 0.0.1 beta++ (Cork, May 2010) \ \ \ MOD: HeP 03/05/99 Started project afresh! \ This version keeps most of the "intelligence" in the \ objects, while the piece specific elements are kept to a \ minimum. It is also a test for the "laurie" project. \ MOD: HeP 02/07/00 Get rid of conditional compilation of the multiple parser \ objects -- they all get compiled now. \ MOD: HeP 02/21/00 Add the global control word IO.STANDBY and corresponding \ words to each component. \ MOD: HeP 04/09/00 Load the file myt:parser_list. \ MOD: HeP 04/10/00 Trash input-channel-holder since we use the components \ from myt:parser_list file. \ MOD: HeP 04/17/00 Move INPUT.PRESENT? to io_glob since the output components \ need to use it. \ MOD: HeP 05/08/00 Move INPUT.PRESENT? back from io_glob. \ MOD: HeP 05/09/00 Implement NEXT.ON to return time interval to next \ predicted note on event. \ MOD: HeP 05/10/00 Rename SET.PARSER to SET.PARSER.TYPE. \ MOD: HeP 05/15/00 New functions for setting up parser type, channel, etc. \ Uglier code, but a little tighter... \ MOD: HeP 05/31/00 Assume that the static.particle will be held in the first \ element of the space. \ MOD: HeP 06/01/00 Replace the confusing array of configuration words with \ IO.INPUT and SET.INPUT.TYPE. Add provisions for setting up \ ptrackers and banalyzers for different types of input. \ MOD: HeP 06/04/00 Trash the global input pulse.tracker and banalyzers. \ Parsers are OPEN: and CLOSE:ed when performance is started \ or stoped, _not_ when instantiated and deinstantiated. \ MOD: HeP 06/08/00 Check if non-zero before deinstantiating the items held by \ the parser-holder. \ MOD: HeP 06/20/00 Split off io_ui from io_screen and io_input. \ MOD: HeP 09/26/00 Trash the io specific variable last-parser, and instead \ use current-parser defined in file myt:parser. \ Move the current-parser zero-ing from io_glob (don't know \ what it was doing there). \ MOD: HeP 10/13/00 Add the PUT.DATA: and GET.DATA: methods to the device (and \ thus the parser) class. This eases calling the matrix. \ MOD: HeP 10/18/00 static.particle's mass is normalized when a note on is \ recieved. \ Current version uses a single static.particle. \ MOD: HeP 10/19/00 midi parser is kept on for io_ui. \ REV: 0.0.1 alpha __________________________________________________________ \ MOD: HeP 10/25/00 Fix incorrect resetting of midi parser vectors in \ IO.INPUT.STOP. \ MOD: HeP 10/28/00 Separate on and off functions for the guitar.parser since \ it has an extra value (string number) passed to it. \ MOD: HeP 11/01/00 Banalyzers are reconfigured depending on input type! \ Correctly assign dimension# to banalyzers. \ MOD: HeP 11/02/00 Rename dcycle-blyzer-holder as density-blyzer-holder since \ the function of these banalyzers will depend on the type \ of input. \ MOD: HeP 11/02/00 Update doc and comments. \ MOD: HeP 11/02/00 Load the file myt:mono_parser+. \ MOD: HeP 11/06/00 Use the words PTRK.NEXT.TIME and PTRK.NEXT.ON.DUR from \ myt:pulse_tracker for predicting input events. \ io's rhythmic sense is pretty good now! \ Use ob.mono.parser+ and add separate parser functions per \ input type. \ MOD: HeP 11/07/00 Implement and enable density banalyzers. \ The polyphonic density measurements don't work because the \ system does not account for stepwise reduction of \ polyphony! \ MOD: HeP 11/09/00 First attempt at auto start/stop of performance. \ MOD: HeP 11/11/00 Fix bug when banalyzer stops performance: Other banalyzer \ pending input would recieve bogus shape from closed \ parser. See file myt:banalyzer for fix. \ MOD: HeP 11/14/00 Set banalyzers' tolerance mode to linear_tolerance. \ MOD: HeP 11/17/00 Enable #parsers_enabled number of parser at when .DEFAULT \ (and thus .INIT) is called. \ MOD: HeP 11/18/00 Use INPUT.PARSER@ and INPUT.CHANNEL@ from file io_config. \ MOD: HeP 11/20/00 Move PARSER.ERROR.DIALOG from io_screen. \ REV: 0.0.1 beta __________________________________________________________ \ MOD: HeP 03-21-04 Use return stack version of CONFIGURE.BANALYZER. \ Working version of POLY.DENSITY.FUNC using the updated \ polyphonic parser classes. Experiment with calling these \ during note on or off. \ MOD: HeP 03-21-04 Experiments with revised pulse.tracker. \ MOD: HeP 05-11-04 Updated the description/comment. \ MOD: HeP 07-03-04 Each component's .INIT function no longer calls the \ corresponding .DEFAULT function. Instead these are all \ called at the end of IO.INIT. See file io_top. \ REV: 0.0.1 a ++ __________________________________________________________ \ MOD: HeP 03-20-09 Add meta-blyzer. We have an alert for alerts. ToDo: Need \ someway of triggering changes of patch, interp-tables and \ time-advance values from this. \ MOD: HeP 03-21-09 See: io_matrix for details on what the meta-blyzer \ triggers. \ MOD: HeP 03-24-09 Fix bug in ob.banalyzer+ (see myt:banalyzer+) and have \ consequently increased the alert windows of banalyzers. \ REV: 0.0.1 b ++ __________________________________________________________ \ Version for performance at Blackrock Castle Observatory, \ Cork, Ireland, May 25, 2010. \ \ \ ToDo: Does not go into standby if no parser (external input) -- io must be \ doing a solo if no one else is playing. \ ToDo: Couple static.particles with parsers? Use current-parser? \ ToDo: Clearup the parser setup/configuration words! \ ToDo: More consistent and comprehensive error reporting. anew task-io_input ob.objlist parser-holder ob.objlist fout-holder ob.objlist ptracker-holder ob.objlist pulse-blyzer-holder ob.objlist volume-blyzer-holder ob.objlist density-blyzer-holder ob.objlist pitch-blyzer-holder \ input stats variable last-ptracker \ most recently updated pulse tracker variable last-alert \ banalyzer which sent the last alert variable last-alert-time \ time of the last alert variable last-pulse-alert variable last-volume-alert variable last-density-alert variable last-pitch-alert : RESET.INPUT.STATS ( -- , zero variables ) 0 current-parser ! \ 0 last-ptracker ! 0 last-alert ! 0 last-pulse-alert ! 0 last-volume-alert ! 0 last-density-alert ! 0 last-pitch-alert ! ; \ input activity : INPUT.PRESENT? ( -- flag , true if input is active ) current-parser @ \ -- addr | 0 dup IF get.time: [] time@ swap - io_timeout < \ -- flag THEN ; : PULSE@ ( -- ticks | false , current pulse value of input ) last-ptracker @ \ -- addr | 0 dup IF get: [] \ -- ticks | 0 THEN ; : NEXT.ON.TIME@ ( -- ticks | false , time of next predicted note on event ) last-ptracker @ \ -- addr | 0 dup IF ptrk.next.time \ -- ticks | 0 THEN ; : NEXT.ON.DUR@ ( -- ticks | false , duration until next predicted note on ) last-ptracker @ \ -- addr | 0 dup IF ptrk.next.on.dur \ -- ticks | 0 THEN ; \ input parser : PARSER.ON.FUNC ( note# vel prsr -- , generic parser on function ) -rot HP.NOTEON \ note# vel -- get.data: [] execute: on-matrix ; : PARSER.OFF.FUNC ( note# vel prsr -- , generic parser off function ) -rot HP.NOTEOFF \ note# vel -- get.data: [] execute: off-matrix ; : MONO.ON.FUNC ( pitch vel ontime prsr -- ) 2over 2over RAW.ON: [] nip PARSER.ON.FUNC ; : MONO.OFF.FUNC ( pitch vel ontime prsr -- ) 2over 2over RAW.OFF: [] nip PARSER.OFF.FUNC ; : POLY.ON.FUNC ( pitch vel prsr -- ) 3dup RAW.ON: [] PARSER.ON.FUNC ; : POLY.OFF.FUNC ( pitch vel prsr -- ) 3dup RAW.OFF: [] PARSER.OFF.FUNC ; : GUITAR.ON.FUNC ( pitch vel strg# prsr -- ) 2over 2over RAW.ON: [] nip PARSER.ON.FUNC ; : GUITAR.OFF.FUNC ( pitch vel strg# prsr -- ) 2over 2over RAW.OFF: [] nip PARSER.OFF.FUNC ; \ configure parsers : PARSER.ENABLED? ( indx -- flag ) get: parser-holder 0= NOT ; : DISABLE.PARSER ( indx -- , disable parser with given index ) dup get: parser-holder ?dup IF dup delete.parser: midi-parser-holder deinstantiate THEN \ 0 swap put: parser-holder ; : USE.MONO.PARSER ( prsr -- ) 'c mono.on.func over put.on.function: [] 'c mono.off.func swap put.off.function: [] ; : USE.POLY.PARSER ( prsr -- ) 'c poly.on.func over put.on.function: [] 'c poly.off.func swap put.off.function: [] ; : USE.GUITAR.PARSER ( prsr -- ) 'c guitar.on.func over put.on.function: [] 'c guitar.off.func swap put.off.function: [] ; : HOOKUP.PARSER { p_type indx | prsr -- , setup parser for use } indx get: parser-holder -> prsr \ indx put.data: prsr \ assign parser's indx \ p_type CASE mono_parser OF prsr use.mono.parser ENDOF poly_parser OF prsr use.poly.parser ENDOF guitar_parser OF prsr use.guitar.parser ENDOF ENDCASE \ indx get: fout-holder \ -- fout put.instrument: prsr \ assign fan.out as instrument to parser ; \ error handling 0 constant err_null \ *** put these in io_glob? *** 1 constant err_out_of_range \ *** should these constants *** 2 constant err_overlap \ *** be used by other *** 3 constant err_instantiate \ *** components? *** : CHAN.OUT.OF.RANGE.DIALOG ( -- ) " Channel number out of range. Guitars are expected to transmit on six channels (eg. 11 to 16)." dialog.a ; : CHAN.OVERLAP.DIALOG ( -- ) " Invalid channel number. Two input devices cannot share the same MIDI channel(s)." dialog.a ; : OBJ.INSTANTIATE.DIALOG ( -- ) " Sorry, unable to create input object (maybe a memory error). The program will quit, but you might want to try again." dialog.a TRUE quit-hmsl ! ; : PARSER.ERROR.DIALOG ( err -- , report appropriate error message ) CASE err_out_of_range OF chan.out.of.range.dialog ENDOF err_overlap OF chan.overlap.dialog ENDOF err_instantiate OF obj.instantiate.dialog ENDOF ENDCASE update.screen ; : PARSER.CHANNEL.ERROR? { chan# prsr -- err } get.#channels: prsr chan# + 17 > IF err_out_of_range ELSE chan# put.channel: prsr \ prsr ?available: midi-parser-holder IF err_null ELSE err_overlap THEN THEN ; : (SET.PARSER.TYPE) ( p_type -- addr | 0 ) CASE mono_parser OF instantiate ob.mono.parser+ ENDOF poly_parser OF instantiate ob.poly.parser ENDOF guitar_parser OF instantiate ob.guitar.parser ENDOF ENDCASE ; : SET.PARSER.TYPE { p_type indx | p_old p_new -- err , set parser type } p_type (set.parser.type) ?dup IF -> p_new \ indx get: parser-holder -> p_old \ save old parser p_old delete.parser: midi-parser-holder \ get.channel: p_old p_new PARSER.CHANNEL.ERROR? dup IF p_new deinstantiate \ p_old add.parser: midi-parser-holder \ restore old parser ELSE get.channel: p_old put.channel: p_new \ p_old deinstantiate \ p_new indx put: parser-holder p_new add.parser: midi-parser-holder \ p_type indx HOOKUP.PARSER THEN ELSE err_instantiate THEN ; : SET.PARSER.CHAN# { chan# indx | prsr -- err , set parser's channel number } indx get: parser-holder -> prsr \ get.channel: prsr \ save old channel number \ chan# prsr PARSER.CHANNEL.ERROR? dup IF swap put.channel: prsr \ restore old channel number ELSE nip \ prsr delete.parser: midi-parser-holder \ chan# put.channel: prsr prsr add.parser: midi-parser-holder THEN ; : SET.PARSER.BEND ( bend indx -- , set bend range for given parser ) get: parser-holder dup IF put.bend.range: [] ELSE 2drop THEN ; : SET.PARSER { p_type chan# bend indx | p_old p_new -- err } p_type (set.parser.type) ?dup IF -> p_new \ indx get: parser-holder -> p_old \ save old parser p_old IF p_old delete.parser: midi-parser-holder THEN \ chan# p_new PARSER.CHANNEL.ERROR? dup IF p_new deinstantiate \ p_old IF p_old indx put: parser-holder \ restore old parser p_old add.parser: midi-parser-holder THEN ELSE p_old IF p_old deinstantiate THEN \ chan# put.channel: p_new bend put.bend.range: p_new \ p_new indx put: parser-holder p_new add.parser: midi-parser-holder \ p_type indx HOOKUP.PARSER THEN ELSE err_instantiate THEN ; : IO.PARSER.INIT ( -- ) sub" io.parser.init" \ io_#input new: parser-holder io_#input set.many: parser-holder \ 'c ob.fan.out io_#input ?instantiate: fout-holder IF io_#input 0 DO 5 i get: fout-holder new: [] LOOP ELSE " Sorry, an error occurred while trying to create input fan.out objects. Quit and try restarting the program." init.error THEN ; : IO.PARSER.TERM ( -- ) sub" io.parser.term" \ mp.reset midi.parser.off \ many: parser-holder 0 DO i get: parser-holder ?dup IF deinstantiate THEN LOOP \ deinstantiate: fout-holder ; : IO.PARSER.RESET ( -- ) sub" io.parser.reset" \ \ *** do parsers have a useful RESET: method? *** \ ; \ pulse tracker : PTRACKER.ON.FUNC ( elm# shape ptrckr -- ) dup last-ptracker ! ON: [] \ 2drop ; \ configure pulse trackers : CONFIGURE.PTRACKER ( pTracker -- ) \ *** stuff goes here *** drop ; : USE.MONO.PTRACKER ( indx# -- ) get: ptracker-holder \ *** stuff goes here *** configure.ptracker ; : USE.POLY.PTRACKER ( indx# -- ) get: ptracker-holder \ *** stuff goes here *** configure.ptracker ; : USE.GUITAR.PTRACKER ( indx# -- ) get: ptracker-holder \ *** stuff goes here *** configure.ptracker ; : SET.PTRACKER ( p_type indx# -- , configure ptracker for parser type ) swap CASE mono_parser OF use.mono.ptracker ENDOF poly_parser OF use.poly.ptracker ENDOF guitar_parser OF use.guitar.ptracker ENDOF ENDCASE ; : IO.PTRACKER.INIT ( -- ) sub" io.ptracker.init" \ io_#input new: ptracker-holder \ 'c ob.pulse.tracker+ io_#input ?instantiate: ptracker-holder IF io_#input 0 DO i get: ptracker-holder \ 'c ptracker.on.func over put.on.function: [] io_min_pulse io_max_pulse rot put.range: [] LOOP ELSE " Sorry, an error occurred while trying to create input pulse.trackers. Quit and try restarting the program." init.error THEN ; : IO.PTRACKER.TERM ( -- ) sub" io.ptracker.term" \ deinstantiate: ptracker-holder ; : RESET.PTRACKERS ( -- ) many: ptracker-holder 0 DO i get: ptracker-holder reset: [] LOOP ; : IO.PTRACKER.RESET ( -- ) sub" io.ptracker.reset" \ reset.ptrackers ; io_test? .IF \ testing banalyzers: alert stats variable meta-alerts variable pulse-alerts variable volume-alerts variable density-alerts variable pitch-alerts : zero.alerts ( -- ) 0 meta-alerts ! 0 pulse-alerts ! 0 volume-alerts ! 0 density-alerts ! 0 pitch-alerts ! ; : print.alerts ( -- ) cr tab ." Meta =" meta-alerts @ 3 .r cr tab ." Pulse =" pulse-alerts @ 3 .r cr tab ." Volume =" volume-alerts @ 3 .r cr tab ." Density =" density-alerts @ 3 .r cr tab ." Pitch =" pitch-alerts @ 3 .r cr cr ; .THEN \ meta banalyzer ob.banalyzer+ meta-blyzr : META.ALERT ( data addr -- , test and maybe execute meta alert ) [ io_test? .IF ] >newline ." META.ALERT" meta-alerts incr [ .THEN ] \ 2drop 0 execute: meta-alert-matrix ; : MAYBE.META.ALERT ( -- , test and maybe execute meta alert ) midi.rtc.time@ dup last-alert-time @ - io_min_pulse > IF dup on: meta-blyzr THEN last-alert-time ! ; : IO.META.BANALYZER.INIT ( -- ) sub" io.meta.banalyzer.init" \ 'c meta.alert put.alert.function: meta-blyzr \ DELTA.ON: meta-blyzr \ 16 put.alert.window: meta-blyzr io_timeout put.tolerance: meta-blyzr io_timeout 4/ put.tolerance.increment: meta-blyzr io_min_pulse 2* io_timeout put.tolerance.range: meta-blyzr io_min_pulse io_timeout put.tolerance.range: meta-blyzr \ open: meta-blyzr ; : IO.META.BANALYZER.TERM ( -- ) sub" io.meta.banalyzer.term" \ close: meta-blyzr ; : IO.META.BANALYZER.RESET ( -- ) sub" io.meta.banalyzer.reset" \ reset: meta-blyzr ; \ banalyzers \ alert functions : PULSE.ALERT ( data addr -- ) [ io_test? .IF ] >newline ." PULSE.ALERT" pulse-alerts incr [ .THEN ] \ MAYBE.META.ALERT \ nip dup last-alert ! dup last-pulse-alert ! \ get.data: [] execute: alert-matrix ; : VOLUME.ALERT ( data addr -- ) [ io_test? .IF ] >newline ." VOLUME.ALERT" volume-alerts incr [ .THEN ] \ MAYBE.META.ALERT \ nip dup last-alert ! dup last-volume-alert ! \ dup get.average: [] HP.ALERT \ vel -- , reposition static.particle \ get.data: [] execute: alert-matrix ; : DENSITY.ALERT ( data addr -- ) [ io_test? .IF ] >newline ." DENSITY.ALERT" density-alerts incr [ .THEN ] \ MAYBE.META.ALERT \ nip dup last-alert ! dup last-density-alert ! \ get.data: [] execute: alert-matrix ; : PITCH.ALERT ( data addr -- ) [ io_test? .IF ] >newline ." PITCH.ALERT" pitch-alerts incr [ .THEN ] \ MAYBE.META.ALERT \ nip dup last-alert ! dup last-pitch-alert ! \ get.data: [] execute: alert-matrix ; \ auto start and stop : STANDBY.ALERT ( data addr -- , start playing when alert is executed ) test" *** STANDBY.ALERT *** " 2drop \ SAFE.START ; : IMBNF.ALERT ( data addr -- , stop playing when alert is executed ) test" *** IMBNF.ALERT *** " 2drop \ SAFE.STOP ; variable saved-banalyzer-holder variable saved-alert-cfa : SAVE.ALERT ( -- ) 4 choose CASE 0 OF pulse-blyzer-holder saved-banalyzer-holder ! ENDOF 1 OF volume-blyzer-holder saved-banalyzer-holder ! ENDOF 2 OF density-blyzer-holder saved-banalyzer-holder ! ENDOF 3 OF pitch-blyzer-holder saved-banalyzer-holder ! ENDOF ENDCASE \ 0 saved-banalyzer-holder @ get: [] get.alert.function: [] saved-alert-cfa ! ; : RESTORE.ALERT ( -- ) saved-banalyzer-holder @ many: [] 0 DO saved-alert-cfa @ i saved-banalyzer-holder @ get: [] put.alert.function: [] LOOP ; \ density OFF functions : MONO.DENSITY.FUNC { elm# shape blyzr -- , analyze input's duty cycle } elm# parser_ontime_dim# ed.at: shape ON: blyzr ; \ polyphonic density depends on the number of held notes (notes in a "chord") \ against the time in which those notes occurred. : (POLY.DENSITY.FUNC) { blyzr | parser chord -- } current-parser @ ?dup IF -> parser get.chord: parser -> chord \ 0 \ -- poly , initial value thru loop time: parser \ -- poly time , time of last event \ many: chord 0 DO dup \ -- poly time time i 1 ed.at: chord \ -- poly time time timeB , time of ith note in chord - \ -- poly time timeD io_max_pulse <= IF nip \ -- time many: chord i - \ -- time poly swap \ -- poly time LEAVE THEN LOOP drop ON: blyzr THEN ; : POLY.DENSITY.FUNC ( elm# shape blyzr -- ) -rot 2drop (poly.density.func) ; : GUITAR.DENSITY.FUNC ( elm# shape blyzr -- ) -rot 2drop (poly.density.func) ; \ configure banalyzers false .IF \ local variable or return stack versions : CONFIGURE.BANALYZER { aWindow tolerance tIncr tMin tMax blyzr -- } aWindow put.alert.window: blyzr tolerance put.tolerance: blyzr tIncr put.tolerance.increment: blyzr tMin tMax put.tolerance.range: blyzr ; .ELSE : CONFIGURE.BANALYZER ( aWindow tolerance tIncr tMin tMax blyzr -- ) >r r@ put.tolerance.range: [] r@ put.tolerance.increment: [] r@ put.tolerance: [] r> put.alert.window: [] ; .THEN : USE.MONO.BANALYZER ( indx# -- ) dup get: pulse-blyzer-holder dup DELTA.ON: [] >r 32 \ alert window io_rtc_rate 2/ \ tolerance io_min_pulse \ tolerance increment io_min_pulse io_timeout \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: volume-blyzer-holder >r 32 \ alert window 64 \ tolerance 8 \ tolerance increment 8 96 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: density-blyzer-holder 'c mono.density.func over put.off.function: [] >r 8 \ alert window io_min_pulse 4/ \ tolerance io_min_pulse 2/ \ tolerance increment 1 io_max_pulse \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ get: pitch-blyzer-holder >r 32 \ alert window 1200 \ tolerance 100 \ tolerance increment 100 2400 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- ; : USE.POLY.BANALYZER ( indx# -- ) dup get: pulse-blyzer-holder dup DELTA.ON: [] >r 64 \ alert window io_rtc_rate 2/ \ tolerance io_min_pulse \ tolerance increment io_min_pulse io_timeout \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: volume-blyzer-holder >r 64 \ alert window 64 \ tolerance 8 \ tolerance increment 8 96 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: density-blyzer-holder 'c POLY.DENSITY.FUNC over put.off.function: [] >r 64 \ alert window 4 \ tolerance 1 \ tolerance increment 1 7 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ get: pitch-blyzer-holder >r 48 \ alert window 2400 \ tolerance 100 \ tolerance increment 300 9600 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- ; : USE.GUITAR.BANALYZER ( indx# -- ) dup get: pulse-blyzer-holder dup DELTA.ON: [] >r 48 \ alert window io_rtc_rate 2/ \ tolerance io_min_pulse \ tolerance increment io_min_pulse io_timeout \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: volume-blyzer-holder >r 48 \ alert window 64 \ tolerance 8 \ tolerance increment 8 96 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ dup get: density-blyzer-holder 'c GUITAR.DENSITY.FUNC over put.off.function: [] >r 48 \ alert window 2 \ tolerance 1 \ tolerance increment 1 4 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- \ get: pitch-blyzer-holder >r 48 \ alert window 1200 \ tolerance 100 \ tolerance increment 300 3600 \ tolerance min and max r> configure.banalyzer \ aWindow tolerance tIncr tMin tMax blyzr -- ; : SET.BANALYZER ( p_type indx# -- , configure banalyzer for parser type ) swap CASE mono_parser OF use.mono.banalyzer ENDOF poly_parser OF use.poly.banalyzer ENDOF guitar_parser OF use.guitar.banalyzer ENDOF ENDCASE ; : BUILD.BANALYZERS { indx dim# cfa list -- indx } io_#input new: list 'c ob.banalyzer+ io_#input ?instantiate: list IF io_#input 0 DO i get: list dim# over put.dim: [] cfa over put.alert.function: [] indx over put.data: [] \ linear_tolerance swap PUT.TOLERANCE.MODE: [] \ indx 1+ -> indx LOOP ELSE " Sorry, an error occurred while trying to create input analyzers. Quit and try restarting the program." init.error THEN indx ; : IO.BANALYZER.INIT ( -- ) sub" io.banalyzer.init" \ 0 \ -- indx \ parser_time_dim# 'c pulse.alert pulse-blyzer-holder build.banalyzers \ -- indx \ parser_vol_dim# 'c volume.alert volume-blyzer-holder build.banalyzers \ -- indx \ 0 'c density.alert density-blyzer-holder build.banalyzers \ -- indx \ parser_pitch_dim# 'c pitch.alert pitch-blyzer-holder build.banalyzers \ -- indx \ drop \ many: density-blyzer-holder 0 DO 'c 3DROP i get: density-blyzer-holder put.on.function: [] LOOP ; : IO.BANALYZER.TERM ( -- ) sub" io.banalyzer.term" \ deinstantiate: pulse-blyzer-holder deinstantiate: volume-blyzer-holder deinstantiate: density-blyzer-holder deinstantiate: pitch-blyzer-holder ; : (RESET.BANALYZERS) { list -- } many: list 0 DO i get: list reset: [] LOOP ; : RESET.BANALYZERS ( -- ) pulse-blyzer-holder (reset.banalyzers) volume-blyzer-holder (reset.banalyzers) density-blyzer-holder (reset.banalyzers) pitch-blyzer-holder (reset.banalyzers) ; : IO.BANALYZER.RESET ( -- ) sub" io.banalyzer.reset" \ reset.banalyzers ; \ configure input : SET.INPUT.TYPE { p_type indx -- err } p_type indx set.parser.type dup NOT IF p_type indx set.ptracker p_type indx set.banalyzer THEN ; : SET.INPUT { p_type chan# bend indx -- err } p_type chan# bend indx set.parser dup NOT IF p_type indx set.ptracker p_type indx set.banalyzer THEN ; \ system control : IO.INPUT.DEFAULT ( -- ) io_#input 0 DO i disable.parser LOOP \ #parsers_enabled 0 DO i input.parser@ \ -- p_type i input.channel@ \ -- chan# io_input_bend \ -- bend i \ -- indx \ SET.INPUT \ p_type chan# bend indx -- err \ err_instantiate = IF obj.instantiate.dialog LEAVE THEN LOOP ; : IO.INPUT.RESET ( -- ) test" IO.INPUT.RESET" \ io.parser.reset io.ptracker.reset io.meta.banalyzer.reset io.banalyzer.reset \ reset.input.stats ; : IO.INPUT.UPDATE ( -- ) reset.input.stats ; : IO.INPUT.PANIC ( -- ) midi.clear ; : IO.INPUT.STANDBY ( -- ) midi.clear \ 'c parser.on.vector mp-on-vector ! 'c parser.off.vector mp-off-vector ! 'c parser.bend.vector mp-bend-vector ! \ io_#input 0 DO i get: parser-holder ?dup IF open: [] THEN LOOP \ reset.input.stats \ save.alert \ save alert function of selected banalyzers \ io_#input 0 DO 'c STANDBY.ALERT i saved-banalyzer-holder @ get: [] put.alert.function: [] LOOP ; : IO.INPUT.START ( -- ) [ io_test? .IF ] zero.alerts [ .THEN ] \ restore.alert \ restore normal alert function of selected banalyzers ; : INPUT.IMBNF ( -- , it must be nearly finished ) io_#input 0 DO 'c IMBNF.ALERT i saved-banalyzer-holder @ get: [] put.alert.function: [] LOOP ; : IO.INPUT.STOP ( -- ) [ io_test? .IF ] print.alerts [ .THEN ] \ 'c 2drop mp-on-vector ! 'c 2drop mp-off-vector ! 'c 2drop mp-bend-vector ! \ io_#input 0 DO i get: parser-holder ?dup IF close: [] THEN LOOP \ restore.alert \ restore normal alert function of selected banalyzers \ reset.ptrackers reset.banalyzers ; : IO.INPUT.PAUSE ( -- ) 'c 2drop mp-on-vector ! 'c 2drop mp-off-vector ! 'c 2drop mp-bend-vector ! ; : IO.INPUT.RESUME ( -- ) 'c parser.on.vector mp-on-vector ! 'c parser.off.vector mp-off-vector ! 'c parser.bend.vector mp-bend-vector ! ; \ setup & clearup : IO.INPUT.INIT ( -- ) test" IO.INPUT.INIT" \ reset.input.stats \ PARSER.INIT \ initialize midi parser list \ 'c 2drop mp-on-vector ! 'c 2drop mp-off-vector ! 'c 2drop mp-bend-vector ! \ io.parser.init io.ptracker.init io.banalyzer.init io.meta.banalyzer.init \ io_#input 0 DO i get: fout-holder \ i get: ptracker-holder over add: [] i get: pulse-blyzer-holder over add: [] i get: volume-blyzer-holder over add: [] i get: density-blyzer-holder over add: [] i get: pitch-blyzer-holder swap add: [] LOOP \ \ io.input.default \ removed MOD: 07-03-04 \ midi.clear midi.parser.on ; : IO.INPUT.TERM ( -- ) test" IO.INPUT.TERM" \ PARSER.TERM \ io.parser.term io.ptracker.term io.banalyzer.term io.meta.banalyzer.term \ midi.clear midi.parser.off ; if.forgotten io.input.term io_test? .IF : IO.INPUT.PRINT ( -- ) >newline ." IO_INPUT" cr ." Parsers" cr ." last parser = " current-parser @ ob.name cr ." Pulse Trackers" cr ." last ptracker = " last-ptracker @ ob.name cr ." Banalyzers" cr ." last alert = " last-alert @ ob.name cr ." pule alert = " last-pulse-alert @ ob.name cr ." volume alert = " last-volume-alert @ ob.name cr ." density alert = " last-density-alert @ ob.name cr ." pitch alert = " last-pitch-alert @ ob.name cr >newline ." Print objects?" y/n cr IF >newline ." Print parsers?" y/n cr IF print: midi-parser-holder ?pause >newline cr many: parser-holder 0 DO i get: parser-holder ?dup IF print: [] ?pause >newline THEN LOOP THEN >newline ." Print ptrackers?" y/n cr IF many: ptracker-holder 0 DO i get: ptracker-holder print: [] ?pause >newline LOOP THEN >newline ." Print banalyzers?" y/n cr IF >newline ." Print pulse banalyzers?" y/n cr IF many: pulse-blyzer-holder 0 DO i get: pulse-blyzer-holder print: [] ?pause >newline LOOP THEN >newline ." Print volume banalyzers?" y/n cr IF many: volume-blyzer-holder 0 DO i get: volume-blyzer-holder print: [] ?pause >newline LOOP THEN >newline ." Print density banalyzers?" y/n cr IF many: density-blyzer-holder 0 DO i get: density-blyzer-holder print: [] ?pause >newline LOOP THEN >newline ." Print pitch banalyzers?" y/n cr IF many: pitch-blyzer-holder 0 DO i get: pitch-blyzer-holder print: [] ?pause >newline LOOP THEN THEN THEN ; .THEN