\ io \ \ io_glob \ global data and functions used by io. \ \ \ this file contains data, data structures, and functions shared between \ several components of io. \ \ the vectored global control procedures (IO.START, IO.STOP, etc) are \ declared here, but defined or configured in the file io_top. \ \ \ 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/21/00 Add the global control word IO.STANDBY and corresponding \ words to each component. \ MOD: HeP 04/17/00 Implement INPUT.PRESENT? and move word from io_input since \ the output components need to use it. \ MOD: HeP 04/30/00 The io-pdur-job no longer resides in a hierarchy, but is \ executed and terminated independently. \ MOD: HeP 05/08/00 Move INPUT.PRESENT? back to io_input. \ MOD: HeP 05/16/00 Add IO.TITLE text string to be shared between components. \ MOD: HeP 06/01/00 Add IO.PLAY to the set of global control words. \ MOD: HeP 06/04/00 Remove the highest level morph, io-coll. \ MOD: HeP 06/07/00 Move hp_ constants from io_config. io_glob now loads \ before modules. \ MOD: HeP 06/24/00 Remove half the IO.GR... words. Note that there words now \ call the corresponding global control procedures in \ addition to changing the gui state. \ MOD: HeP 09/26/00 Move the current-parser zero-ing to io_input (don't know \ what it was doing here). \ MOD: HeP 10/01/00 Define shared velocity dimension# (constant vel_dim#). \ MOD: HeP 10/06/00 Define a commonly used value as constant hp_range/2. \ MOD: HeP 10/13/00 Add init-error? and provisions for error reporting. \ Add IT.MUST.BE.NEARLY.FINISHED to the system control \ words. \ MOD: HeP 10/14/00 Separate variable io-paused? for indicating paused state. \ This prevents players from starting when we resume after \ a pause. \ Call IT.MUST.BE.NEARLY.FINISHED before pdur is up. Force \ end if way past ending point. \ MOD: HeP 10/16/00 Messy but functional automated start/stop. Note that \ restoring the job function in IO.GLOB.STOP will cause a \ recursive bug. (Not sure why...) \ REV: 0.0.1 alpha __________________________________________________________ \ MOD: HeP 11/10/00 Add state safe control procedures for start and stop. \ MOD: HeP 11/14/00 Move START/STOP and PAUSE/RESUME to io_glob. \ MOD: HeP 11/15/00 Add io_imbnf to possible values of io-state. \ Add additional state safe control procedures. \ MOD: HeP 11/20/00 Calculate io-stop-time in IO.GLOB.IMBNF if not in \ strict_pdur mode. \ REV: 0.0.1 beta __________________________________________________________ \ MOD: HeP 01/18/01 No longer set midi manager client id in io_glob. \ MOD: HeP 04-13-04 Add variable unsaved-changes? used by io_file to keep \ track of changes. (Moved these from io_screen.) \ Defer UNSAVED.CHANGE if io_file? and io_tunrkey? are true. \ MOD: HeP 04-14-04 Add SAVED.CHANGE. \ MOD: HeP 05-03-04 Add SELECT.SCENE, NEXT.SCENE and PREV.SCENE. (I hope this \ is not the start of io getting hopelessly complicated.) \ Add constant io_rev#. \ MOD: HeP 05-05-04 Optimizations in modules:io_interp mean that there are \ some _theoretical_ limitations on the values of hp/midi \ and hp_range. \ MOD: HeP 05-14-04 Add ADD.SCENE and DELETE.SCENE. \ MOD: HeP 05-16-04 Modify words that track file save state (SAVED.CHANGE, \ etc) to use OB.IO.SCENE's save state. \ 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-22-09 Setting of rtc.rate! and time-advance moved from \ io_config. \ Add (MODIFY.TIME.ADVANCE) called by the meta-alert-matrix. \ See: io_matrix. \ REV: 0.0.1 b ++ __________________________________________________________ \ Version for performance at Blackrock Castle Observatory, \ Cork, Ireland, May 25, 2010. \ \ \ ToDo: IO.PLAY doen's _need_ to be a deferred word to be defined later, why \ not just define it here? \ ToDo: More consistent and comprehensive error reporting. anew task-io_glob \ title " IO_ " ostype: 'IO_' : IO.TITLE ( -- $ , title string ) " io 0.0.1 beta++" ; \ version number false .IF 0 constant rev#_a \ alpha 1 constant rev#_b \ beta .THEN 2 constant rev#_b++ \ beta plus plus 0 24 shift 0 16 shift OR 1 8 shift OR rev#_b++ OR constant io_rev# \ error report io_turnkey? .IF variable init-#errors variable init-error? : INIT.ERROR ( $ -- ) init-#errors incr init-error? ! ; .ELSE : INIT.ERROR ( $ -- ) $. abort ; .THEN \ global control procedures defer IO.DEFAULT \ note: each .init calls the corresponding .default defer IO.RESET \ reset the "personality" of io defer IO.UPDATE defer IO.PANIC defer IO.STANDBY \ called before io.start defer IO.START defer IT.MUST.BE.NEARLY.FINISHED defer IO.STOP defer IO.PAUSE defer IO.RESUME defer IO.PLAY \ calls io.standby, and (depending on pdur-mode) io.start 'c noop is IO.DEFAULT 'c noop is IO.RESET 'c noop is IO.UPDATE 'c noop is IO.PANIC 'c noop is IO.STANDBY 'c noop is IO.START 'c noop is IT.MUST.BE.NEARLY.FINISHED 'c noop is IO.STOP 'c noop is IO.PAUSE 'c noop is IO.RESUME 'c noop is IO.PLAY \ procedures that additionally alter gui state defer IO.GR.DEFAULT defer IO.GR.PLAY defer IO.GR.STOP defer IO.GR.PAUSE defer IO.GR.RESUME 'c noop is IO.GR.DEFAULT 'c noop is IO.GR.PLAY 'c noop is IO.GR.STOP 'c noop is IO.GR.PAUSE 'c noop is IO.GR.RESUME \ file I/O words io_file? .IF \ scenes defer SELECT.SCENE ( indx -- ) defer NEXT.SCENE ( -- ) defer PREV.SCENE ( -- ) defer ADD.SCENE ( -- ) defer DELETE.SCENE ( -- ) 'c drop is SELECT.SCENE 'c noop is NEXT.SCENE 'c noop is PREV.SCENE 'c noop is ADD.SCENE 'c noop is DELETE.SCENE \ keep track of changes for file saving defer UNSAVED.CHANGE ( -- ) defer SAVED.CHANGE ( -- ) defer UNSAVED.CHANGE? ( -- flag ) 'c noop is UNSAVED.CHANGE 'c noop is SAVED.CHANGE 'c false is UNSAVED.CHANGE? .ELSE : UNSAVED.CHANGE ( -- ) ; immediate : SAVED.CHANGE ( -- ) ; immediate .THEN \ shared dimension# 02 constant vel_dim# \ global velocity (volume) dimesion \ event buffer \ \ meta-alert-matrix function (see: io_matrix) : (MODIFY.TIME.ADVANCE) ( -- ) io_rtc_rate choose time-advance ! ; \ henri poincare \ \ because of use of W/ and W* in modules:io_interp there are some limitations \ on the possible values of hp/midi and hp_range. Not much of a limitation \ since we can assume that midi is already within the range of 16 bits, and \ that hp/midi will realistically be less than $ 7fff. \ \ in addition, to get full midi range (0-127), hp/midi should be an even, so \ the theoretical range of hp/midi is between $ 2 and $ 7ffe. 04 constant hp/midi \ hp_ coord to midi scaling factor hp/midi 127 * constant hp_range \ size of hp_ space hp_range 2/ constant hp_range/2 \ system status 0 constant io_idle 1 constant io_standby 2 constant io_playing 3 constant io_imbnf variable io-state variable io-paused? : IO.IDLE? ( -- flag ) io-state @ io_idle = ; : IO.STANDBY? ( -- flag ) io-state @ io_standby = ; : IO.PLAYING? ( -- flag ) io-state @ io_playing = io-state @ io_imbnf = OR \ *** is this necessary? *** ; : IO.IMBNF? ( -- flag ) io-state @ io_imbnf = ; : IO.PAUSED? ( -- flag ) io-paused? @ ; \ state safe control procedures : SAFE.PLAY ( -- , start if idle ) io.idle? IF IO.GR.PLAY THEN ; : SAFE.START ( -- , start if standby ) io.standby? IF IO.START THEN ; : SAFE.STOP ( -- , stop if playing ) io.playing? IF IO.GR.STOP THEN ; : IMBNF/STOP ( -- , stop or get ready to stop depending on state ) io.imbnf? io.standby? OR IF IO.GR.STOP ELSE IT.MUST.BE.NEARLY.FINISHED THEN ; : START/STOP ( -- , start or stop depending on state ) io.idle? IF IO.GR.PLAY ELSE IMBNF/STOP THEN ; : PAUSE/RESUME ( -- , pause or resume depending on current state ) io.idle? NOT IF io.paused? IF IO.GR.RESUME ELSE IO.GR.PAUSE THEN THEN ; \ performance duration ob.job io-pdur-job \ keep track of performance duration -1 constant null_pdur \ don't stop playing for testing purposes! 0 constant strict_pdur \ end the performance on the dot 1 constant loose_pdur \ stop playing 'round about time 2 constant open_pdur \ finish playing whenever variable io-pdur-mode variable io-pdur \ duration in ticks variable io-start-time \ time to start if tired of waiting variable io-pause-time \ time at which paused variable io-imbnf-time \ time to get ready to stop variable io-stop-time \ (last) time to end performance : PDUR.SEC@ ( -- sec , fetch pdur and convert to seconds ) io-pdur @ io_rtc_rate / ; : PDUR.SEC! ( sec -- , convert value in seconds and store pdur ) io_rtc_rate * io-pdur ! ; : TIME.TO.START? ( -- flag , true if tired of waiting for the humans ) time@ io-start-time @ >= ; : NEARLY.TIME.TO.STOP? ( -- flag , true if time to get ready to stop ) time@ io-imbnf-time @ >= ; : TIME.TO.STOP? ( -- flag , true if time to end performance ) time@ io-stop-time @ >= ; : CALC.PDUR ( -- , calculate reasonable performance duration ) max_pdur min_pdur - 2/ dup choose choose+/- + min_pdur + io-pdur ! ; \ job function if strict_pdur : STRICT.PDUR.FUNC ( job -- ) drop time.to.stop? IF empty: io-pdur-job \ SAFE.STOP THEN ; \ job functions if loose_pdur or open_pdur : STANDBY.PDUR.FUNC ( job -- , start if tired of waiting for humans ) drop time.to.start? IF SAFE.START THEN ; : START.PDUR.FUNC ( job -- ) drop nearly.time.to.stop? IF it.must.be.nearly.finished THEN ; : IMBNF.PDUR.FUNC ( job -- , stop if way past time to stop ) drop time.to.stop? IF empty: io-pdur-job \ SAFE.STOP THEN ; io_test? .IF \ job function if null_pdur : NULL.PDUR.FUNC ( job -- , job function for testing io ) drop ; .THEN \ select mode : SET.PDUR.MODE ( mode -- , setup job for appropriate mode ) dup io-pdur-mode ! \ open_pdur = IF calc.pdur THEN ; \ user midi control variable io-ui-ctrl variable io-ui-chan# variable io-ui-c1 variable io-ui-c2 \ system control : IO.GLOB.DEFAULT ( -- ) io_rtc_rate rtc.rate! io_rtc_rate time-advance ! \ io_pdur io-pdur ! loose_pdur set.pdur.mode \ io_ui io-ui-ctrl ! \ io_ui_c1 io-ui-c1 ! io_ui_c2 io-ui-c2 ! io_ui_chan# io-ui-chan# ! ; : IO.GLOB.RESET ( -- ) test" IO.GLOB.RESET" ; : IO.GLOB.UPDATE ( -- ) ; : IO.GLOB.PANIC ( -- ) ; : IO.GLOB.STANDBY ( -- ) io_standby io-state ! \ io-pdur-mode @ strict_pdur = NOT IF time@ io_timeout 4* choose + io_timeout + io-start-time ! \ empty: io-pdur-job 'c standby.pdur.func add: io-pdur-job \ start: io-pdur-job THEN ; : IO.GLOB.START ( -- ) io_playing io-state ! \ io-pdur-mode @ strict_pdur = IF time@ io-pdur @ + io-stop-time ! \ empty: io-pdur-job 'c strict.pdur.func add: io-pdur-job \ setup main job function \ start: io-pdur-job ELSE time@ io-pdur @ io_timeout - 0 max + io-imbnf-time ! \ empty: io-pdur-job 'c start.pdur.func add: io-pdur-job \ setup main job function THEN ; : GLOB.IMBNF ( -- , it must be nearly finished ) io_imbnf io-state ! \ io-pdur-mode @ strict_pdur = NOT IF time@ io_timeout + io_timeout 4* choose + io-stop-time ! \ empty: io-pdur-job 'c imbnf.pdur.func add: io-pdur-job THEN ; : IO.GLOB.STOP ( -- ) io_idle io-state ! \ stop: io-pdur-job \ \ altering the job function here will crash system!?! \ io-pdur-mode @ open_pdur = IF calc.pdur THEN ; : IO.GLOB.PAUSE ( -- ) true io-paused? ! \ time@ io-pause-time ! \ stop: io-pdur-job ; : IO.GLOB.RESUME ( -- ) false io-paused? ! \ time@ io-pause-time @ - dup io-start-time @ + io-start-time ! dup io-stop-time @ + io-stop-time ! io-imbnf-time @ + io-imbnf-time ! \ start: io-pdur-job ; \ setup & clearup : IO.GLOB.INIT ( -- ) test" IO.GLOB.INIT" \ io_idle io-state ! \ 1 new: io-pdur-job io_rtc_rate put.duration: io-pdur-job \ one second resolution \ \ io.glob.default \ removed MOD: 07-03-04 ; : IO.GLOB.TERM ( -- ) test" IO.GLOB.TERM" \ [ io_turnkey? NOT .IF ] 60 rtc.rate! 60 time-advance ! [ .THEN ] \ free: io-pdur-job ; if.forgotten io.glob.term io_test? .IF : PRINT.PDUR.MODE ( -- ) io-pdur-mode @ CASE null_pdur OF 'c null_pdur >name $. ENDOF open_pdur OF 'c open_pdur >name $. ENDOF loose_pdur OF 'c loose_pdur >name $. ENDOF strict_pdur OF 'c strict_pdur >name $. ENDOF \ ." Unrecognized mode!" ENDCASE ; : IO.GLOB.PRINT ( -- ) >newline ." IO_GLOB" cr ." perf duration =" io-pdur @ 6 .r cr ." pdur mode =" print.pdur.mode cr ." hp_" cr ." hp_range =" hp_range 6 .r cr ; .THEN