\ parser_list \ \ class of objlist responsible for sending midi data to the corresponding \ parser object. The current design is for parsing single port, multi channel \ midi input, but it can be adapted for other kinds of data. \ \ \ description of methods: \ \ OPEN: ( -- , open all parsers in list ) \ CLOSE: ( -- , close all parsers ) \ \ ?AVAILABLE: ( addr -- flag , check if channel is already taken ) \ \ ADD.PARSER: ( addr -- , add parser to list ) \ DELETE.PARSER: ( addr -- , remove parser from list ) \ \ ?INSTANTIATE: ( class_cfa chan# -- claff_pfa | false ) \ DEINSTANTIATE: ( -- ) \ \ \ midi parser words: \ \ PARSER.INIT ( -- ) \ PARSER.TERM ( -- ) \ \ \ Code: Han-earl Park \ Copyright 2000 Buster & Friends C-ALTO Labs \ (Valencia, November 1999 - \ (Southampton, September 2000 - \ \ MOD: HeP 03/02/00 Spin off the parser.list class and related forth words \ from the mono_parser file. \ MOD: HeP 04/04/00 Add the ?AVAILABLE: method. \ Get rid of the iv-channel-holder instance object. \ MOD: HeP 04/09/00 Add ?INSTANTIATE: method. \ Fix bug in DEINSTANTIATE: due to having defined a \ nonstandard PUT: (PUT: is now reverted to old behavior). \ Fix bug in ADD: that didn't handle number of channels \ correctly. \ MOD: HeP 04/10/00 Add a DELETE.PARSER: method, and rename the ADD: method \ to ADD.PARSER: \ MOD: HeP 05/10/00 ?AVAILABLE: checks that channel numbers do not excede \ its MANY: value, and returns false if the parser requires \ more channels than available. \ MOD: HeP 05/15/00 DELETE.PARSER: no longer relies on the internal channel \ information of the parser. We just delete the parser from \ the list. (Stops annoying bugs when the parser and the \ parser.list have inconsistent data.) \ Fix bug when checking if the parser's channel is out of \ range. include? task-mono_parser myt:mono_parser anew task-parser_list method ?AVAILABLE: method ADD.PARSER: method DELETE.PARSER: :class OB.PARSER.LIST IF 2drop 2drop FALSE ELSE swap DO i get: self ?dup IF over = NOT IF nip FALSE swap LEAVE THEN THEN LOOP drop THEN ;m :m ADD.PARSER: ( addr -- , add parser to list ) dup get.channel: [] 1- over get.#channels: [] over + swap DO dup i put: self LOOP drop ;m :m DELETE.PARSER: ( addr -- , remove parser from list ) many: self 0 DO dup i get: self = IF 0 i put: self THEN LOOP drop ;m :m DEINSTANTIATE: ( -- ) many: self 0 DO i get: self dup IF dup close: [] deinstantiate 0 i put: self ." Get this far!" \ *** we need to remove the parser from _all_ channels *** \ *** before deinstantiating the parser. Otherwise we *** \ *** may be left with a bogus address in the list *** \ \ *** call DELETE.PARSER: which removes all traces? *** ELSE drop THEN LOOP ;m :m ?INSTANTIATE: ( class_cfa chan# -- class_pfa | false ) >r >body r> \ need pfa for instantiate dup 1 many: self within? IF swap ?dup IF swap over put.channel: [] add.parser: self ELSE 2drop FALSE THEN ELSE 2drop FALSE THEN ;m :m PRINT.ELEMENT: ( elm# -- ) dup get: self IF get: self dup name: [] tab .class: [] ELSE drop tab ." --" THEN ;m ;class \ midi parser vectors ob.parser.list midi-parser-holder : PARSER.ON.VECTOR ( note# vel -- ) mp-state ..@ mp_channel get: midi-parser-holder dup IF note.on: [] ELSE 3drop THEN ; : PARSER.OFF.VECTOR ( note# vel -- ) mp-state ..@ mp_channel get: midi-parser-holder dup IF note.off: [] ELSE 3drop THEN ; : PARSER.BEND.VECTOR ( bendLo bendHi -- ) mp-state ..@ mp_channel get: midi-parser-holder dup IF -rot 7lo7hi->14 \ bendLo bendHi -- bend swap bend: [] ELSE 3drop THEN ; : PARSER.CTRL.VECTOR ( ctrl# value -- ) mp-state ..@ mp_channel get: midi-parser-holder dup IF -rot swap \ ctrl# value -- value ctrl# rot control: [] ELSE 3drop THEN ; \ setup and clearup : PARSER.INIT ( -- ) new: midi-parser-holder \ mp.reset 'c parser.on.vector mp-on-vector ! 'c parser.off.vector mp-off-vector ! 'c parser.bend.vector mp-bend-vector ! 'c parser.ctrl.vector mp-control-vector ! ; : PARSER.TERM ( -- ) free: midi-parser-holder \ mp.reset ; if.forgotten parser.term cr ." Enter parser.init to setup midi parser vectors." cr cr