'*************************************************** '* * '* DLL-besturingskode 2000 * '*************************************************** ' define %Thunderwood_2000 to include this module in het compilation of g_robo.dll GLOBAL pTw AS ThunderWoodType PTR ' only for ThunderWood ' DECLARE SUB TW_Listen () DECLARE SUB TW_Listen_Start () ' 24.07.2004 DECLARE SUB TW_Listen_Stop () DECLARE SUB TW_Velo (BYVAL noot AS BYTE, BYVAL param AS BYTE) DECLARE FUNCTION TW_VeloPulse (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL EventNr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) AS LONG ' ************************************************************ ' code support for * ' ************************************************************ FUNCTION TW_InitDLL (BYREF gh AS GMT_HANDLES, BYREF Tw AS ThunderWoodType) EXPORT AS DWORD LOCAL m AS ASCIIZ * 40 LOCAL i AS LONG LOCAL pmask AS QUAD PTR ' 07.08.2001 must be called before all others IF ISFALSE pgh THEN ' pgh is a global pointer pgh = VARPTR(gh) END IF pTw = VARPTR(Tw) ' this pointer is global in the dll ' new 20.04.2002: IF ISFALSE Tw.simulator THEN IF ISFALSE Tw.preg THEN i = Ro_IOportselector (%IDM_THUNDERWOOD) m = " using port &H" & LTrimZero(HEX$(Tw.padr)) END IF ELSE m = "Simulator for " END IF Tw.ListenTask = %ppListen Tw.channel = %ThunderWood_Channel Tw.chimestask = Tw.thundertask + 1 Tw.raintask = Tw.thundertask + 2 Tw.beattask(1) = Tw.thundertask + 3 ' low woodpecker Tw.beattask(2) = Tw.thundertask + 4 Tw.beattask(3) = Tw.thundertask + 5 Tw.beattask(4) = Tw.thundertask + 6 Tw.windtask = Tw.thundertask + 7 Tw.ratchettask = Tw.thundertask + 8 @pT(Tw.Listentask).cPtr = CODEPTR(TW_Listen) @pT(Tw.Listentask).channel = Tw.channel @pT(Tw.Listentask).level = %False @pT(Tw.Listentask).naam = "Listen" ' midi input listen task for ThunderWood @pT(Tw.Listentask).freq = 100 ' changed 24.07.2004 , was 500 '910 @pT(Tw.Listentask).Har.vel = NUL$(128) @pT(Tw.listentask).flags = %DLL_TASK OR %PERTIM_TASK @pTeX(Tw.listentask).startcptr = CODEPTR(Tw_Listen_Start) @pTeX(Tw.listentask).stopcptr = CODEPTR(Tw_Listen_Stop) @pT(Tw.thundertask).naam = "Thunder" ' thundersheet shaker task @pT(Tw.thundertask).freq = 5 @pT(Tw.thundertask).level = 30 @pT(Tw.thundertask).channel = 9 @pT(Tw.thundertask).patch = 48 @pT(Tw.thundertask).Har.Vel = NUL$(128) @pT(Tw.thundertask).cPtr = CODEPTR(TW_Thunder_Task) @pT(Tw.chimestask).naam = "Chimes " ' bamboo chimes shaker task @pT(Tw.chimestask).freq = 2 @pT(Tw.chimestask).Har.Vel = NUL$(128) @pT(Tw.chimestask).channel = 9 @pT(Tw.chimestask).patch = 72 @pT(Tw.chimestask).level = 100 @pT(Tw.chimestask).cPtr = CODEPTR(TW_Chimes_Task) @pT(Tw.raintask).naam = "Rain" ' rainmaker task @pT(Tw.raintask).freq = 10 @pT(Tw.raintask).Har.Vel = NUL$(128) @pT(Tw.raintask).level = 100 @pT(Tw.raintask).channel = 5 @pT(Tw.raintask).patch = 115 @pT(Tw.raintask).cPtr = CODEPTR(TW_Rain_Task) @pT(Tw.beattask(1)).naam = "BasPeck" @pT(Tw.beattask(1)).Har.Vel = NUL$(128) @pT(Tw.beattask(1)).level = 20 @pT(Tw.beattask(1)).channel = 5 @pT(Tw.beattask(1)).freq = 5 @pT(Tw.beattask(1)).cPtr = CODEPTR(PeckerLow) @pT(Tw.beattask(2)).naam = "TenPeck" @pT(Tw.beattask(2)).Har.Vel = NUL$(128) @pT(Tw.beattask(2)).level = 20 @pT(Tw.beattask(2)).channel = 5 @pT(Tw.beattask(2)).freq = 5 @pT(Tw.beattask(2)).cPtr = CODEPTR(PeckerTenor) @pT(Tw.beattask(3)).naam = "AltPeck" @pT(Tw.beattask(3)).Har.Vel = NUL$(128) @pT(Tw.beattask(3)).level = 20 @pT(Tw.beattask(3)).channel = 5 @pT(Tw.beattask(3)).freq = 4 @pT(Tw.beattask(3)).cPtr = CODEPTR(PeckerAlto) @pT(Tw.beattask(4)).naam = "SopPeck" @pT(Tw.beattask(4)).Har.Vel = NUL$(128) @pT(Tw.beattask(4)).level = 20 @pT(Tw.beattask(4)).channel = 5 @pT(Tw.beattask(4)).freq = 3 @pT(Tw.beattask(4)).cPtr = CODEPTR(PeckerHigh) Sendmessage gh.Cockpit, %WM_SETTEXT,0, VARPTR(m) IF ISFALSE Tw.simulator THEN ThunderWood_On %true TW_AllOff END IF pmask = SetMidiListenChannel (Tw.channel, %False) @pmask = %False ' 24.07.2004 FUNCTION = %True END FUNCTION FUNCTION Tw_Init_Io(BYVAL msg AS DWORD) EXPORT AS LONG 'helper of io_ports selector - everything that needs the robot types is done here, nidaq and usb api calls in g_nh LOCAL cptr AS DWORD LOCAL i AS LONG IF ISFALSE pTw THEN MSGBOX "Call Tw_Init_dll before Tw_Init_Io!!" + $CRLF + "Failed initialising thunderwood",,"g_robo.dll" SELECT CASE msg CASE 1 @pIOports.padr = %Padr OR %Portused @pTW.padr = %Padr @pTW.preg = %Padr + 2 @pTW.reg(0) = %ppP0 @pTW.reg(1) = %ppP1 @pTW.reg(2) = %ppP2 @pTW.reg(3) = %ppP3 @pTW.reg(4) = %ppP4 @pTW.reg(5) = %ppP5 @pTW.reg(6) = %ppP6 @pTW.reg(7) = %ppP7 FUNCTION = %True CASE 2 @pTW.pAdr= %False ' use port 0 for data. '@pTW.pInp= 1 ' input port @pTW.pReg= 2 ' controll port - low nibble @pTW.reg(0) = %npP0 @pTW.reg(1) = %npP1 @pTW.reg(2) = %npP2 @pTW.reg(3) = %npP3 @pTW.reg(4) = %npP4 @pTW.reg(5) = %npP5 @pTW.reg(6) = %npP6 @pTW.reg(7) = %npP7 FUNCTION = %True CASE 4 TO 13 msg = msg - 4 @pIOports.USB(msg)= %Portused OR %True SHIFT LEFT msg, 12 @pTW.pAdr = msg OR &H0FF0 @pTW.pReg = msg OR &H0FF1 @pTW.reg(0) = %npP0 @pTW.reg(1) = %npP1 @pTW.reg(2) = %npP2 @pTW.reg(3) = %npP3 @pTW.reg(4) = %npP4 @pTW.reg(5) = %npP5 @pTW.reg(6) = %npP6 @pTW.reg(7) = %npP7 FUNCTION = %True CASE 14 TO 46 ' activewire USB ports msg = msg - 14 @pIOports.AwUSB(@pIOports.msg)= %PortUsed OR %True SHIFT LEFT msg, 1 ' = x 2 @pTW.pAdr = msg OR &H08A00 ' even @pTW.pReg = msg OR &H08A01 ' odd @pTW.reg(0) = %npP0 @pTW.reg(1) = %npP1 @pTW.reg(2) = %npP2 @pTW.reg(3) = %npP3 @pTW.reg(4) = %npP4 @pTW.reg(5) = %npP5 @pTW.reg(6) = %npP6 @pTW.reg(7) = %npP7 FUNCTION = %True ' #ENDIF END SELECT END FUNCTION #ENDIF #IF %DEF(%Thunderwood_2000) SUB ThunderWood_On (BYVAL onoff AS DWORD) EXPORT ' 25.04.2002 IF @pTw.simulator THEN EXIT SUB LOCAL retval AS LONG LOCAL b AS STRING * 4 SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 IF ISFALSE onoff THEN b = CHR$(&B00000101) & CHR$(@pTW.Reg(3) AND &H0FE) & CHR$(&B00000101) & CHR$(@pTW.Reg(3) OR 1) ELSE b = CHR$(&B00011010) & CHR$(@pTW.Reg(3) AND &H0FE) & CHR$(&B00011010) & CHR$(@pTW.Reg(3) OR 1) END IF retval = ro_bufout (@pTW.Padr, VARPTR(b),4) CASE ELSE IF ISFALSE onoff THEN Ro_PortOut @pTW.Padr, &B00000101 ' redundant - pincode = NOT Ro_PortOut @pTW.preg, @pTW.Reg(3) ' port nr.4 - ext2port Ro_PortOut @pTW.Padr, &B00000101 retval = g_ro_strobe (@pTW.preg,@pTW.Reg(3),0) TW_AllOff ELSE Ro_PortOut @pTW.Padr, &B00011010 ' redundant - pincode = 26, only five lowest bits are decoded. Ro_PortOut @pTW.preg, @pTW.Reg(3) Ro_PortOut @pTW.Padr, &B00011010 retval = g_ro_strobe (@pTW.preg,@pTW.Reg(3),0) END IF END SELECT TW_Storm %False END SUB SUB TW_Storm (BYVAL value AS BYTE) EXPORT ' 01.08.2002 ' parameter is frequency of rotation for the fan. (0-400Hz) ' This value is read by the PIC controller on Thunderwood. ' 0 will switch the fan off. ' The reaction latency depends on the value previously sent ' to the device: at 400Hz (value 255) it will be 140 ms. ' at 20Hz it will be 2.8 seconds. ' However 20Hz is dangerous for the motor and thus we limit ' the lowest non-zero value here to ca. 40 Hz (latency max. 1.4sec) ' So task frequencies using this call should never be faster ' than 7Hz IF @pTw.simulator THEN EXIT SUB LOCAL retval AS LONG LOCAL b AS STRING * 4 SHIFT RIGHT value,1 ' divide by 2 IF value THEN value = value OR %d7 value = flipbyte(value) ' d0-d7 mirrored in the hardware ! END IF SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 b = CHR$(value) & CHR$(@pTW.Reg(2) AND &H0FE) & CHR$(value) & CHR$(@pTW.Reg(2) OR 1) retval = ro_bufout (@pTW.Padr, VARPTR(b),4) CASE ELSE Ro_PortOut @pTW.Padr, value ' redundant Ro_PortOut @pTW.preg, @pTW.Reg(2) Ro_PortOut @pTW.Padr, value retval = g_ro_strobe (@pTW.preg,@pTW.Reg(2),0) END SELECT END SUB #ENDIF '------------------------------------------------------------------ #IF %DEF(%Thunderwood_2000) SUB TW_Bird (BYVAL velo AS DWORD) EXPORT LOCAL retval AS DWORD ' pump mechanism - Vibi type coil ' bird mapped on note 22 IF velo > 127 THEN velo = 127 IF velo THEN retval = TimeSetEvent(velo,0,CODEPTR(TW_VeloPulse),22,%Time_ONESHOT OR %TIME_CALLBACK_FUNCTION) IF ISFALSE retval THEN TW_Velo 22, %False ELSE TW_Velo 22, %True END IF END IF END SUB SUB TW_Listen () PRIVATE ' no longer EXPORT ' 07.08.2001 'peckers:notes, velo, aftertouch for tremolo speed. velo 0 to stop tremolo 'ratchet:note, velo = duration (ms) lbound put to 25 'wind: note, velo mapped to speed 'thunder: note, velo, aftertouch for shake 'rain:note, velo as ubound of random velos, aftt for min speed, midi ctrl 7 for rnd part of speed LOCAL nv AS INTEGER LOCAL noot AS DWORD LOCAL velo AS DWORD LOCAL tremolo AS DWORD LOCAL value AS DWORD STATIC ScalePeckSpeed AS SINGLE STATIC ScaleThSpeed AS SINGLE IF ISFALSE ScalePeckSpeed THEN ScalePeckSpeed = 127/11 ScaleThspeed = 127/17 'snelheden > 17 Hz doen toch niets END IF nv = GetMidiNote% (@pT(@pTW.listentask).channel, %Remove OR %Oldest) IF nv > %NotFalse THEN velo = LOBYT (nv) noot = HIBYT (nv) SELECT CASE noot CASE 0 ' lightning strobo Thunderwood_on %True ' added 15.12.2002 TW_Light velo CASE 1 TO 5 @pT(@pTW.beattask(1)).level = velo PeckerLow IF ISFALSE velo THEN IF BIT(@pT(@pTW.beattask(1)).swit, %TASK_ONOFF) THEN StopTask @pTW.beattask(1) END IF END IF CASE 6 TO 9 @pT(@pTW.beattask(2)).level = velo PeckerTenor IF ISFALSE velo THEN IF BIT(@pT(@pTW.beattask(2)).swit, %TASK_ONOFF) THEN StopTask @pTW.beattask(2) END IF END IF CASE 10 TO 12 @pT(@pTW.beattask(3)).level = velo PeckerAlto IF ISFALSE velo THEN IF BIT(@pT(@pTW.beattask(3)).swit, %TASK_ONOFF) THEN StopTask @pTW.beattask(3) END IF END IF CASE 13 TO 14 @pT(@pTW.beattask(4)).level = velo PeckerHigh IF ISFALSE velo THEN IF BIT(@pT(@pTW.beattask(4)).swit, %TASK_ONOFF) THEN StopTask @pTW.beattask(4) END IF END IF CASE 15 TW_Ratch velo CASE 16 @pT(@pTW.raintask).level = velo IF ISFALSE BIT(@pT(@pTW.raintask).swit, %TASK_ONOFF) THEN TW_Rain_Task ' luizig om taken op die manier te schakelen... END IF IF ISFALSE velo THEN IF BIT(@pT(@pTW.raintask).swit, %TASK_ONOFF) THEN StopTask @pTW.raintask END IF END IF ThunderWood_on %True ' added 15.12.2002 CASE 17,18 @pT(@pTW.chimestask).level = velo IF ISFALSE BIT(@pT(@pTW.chimestask).swit, %TASK_ONOFF) THEN TW_Chimes_Task END IF IF ISFALSE velo THEN IF BIT(@pT(@pTW.chimestask).swit, %TASK_ONOFF) THEN StopTask @pTW.chimestask END IF END IF CASE 19,20 @pT(@pTW.thundertask).level = velo IF ISFALSE BIT(@pT(@pTW.thundertask).swit, %TASK_ONOFF) THEN TW_Thunder_Task END IF IF ISFALSE velo THEN IF BIT(@pT(@pTW.thundertask).swit, %TASK_ONOFF) THEN StopTask @pTW.thundertask END IF END IF CASE 22 IF velo THEN TW_Bird velo CASE 23 ' not connected yet CASE 24 ' wind machine TW_Wind velo + velo CASE 25 ' storm machine TW_Storm velo + velo ' new 01.08.2002 CASE ELSE ' niks END SELECT END IF nv = GetPressure%(@pT(@pTW.listentask).channel, %REMOVE OR %OLDEST) IF nv> %NotFalse THEN tremolo = LOBYT(nv) noot = HIBYT(nv) ' thunderLog "noot" + STR$(noot) + CHR$(13)+"att" + STR$(tremolo?) IF tremolo THEN SELECT CASE noot CASE 1 TO 5 @pT(@pTW.beattask(1)).freq = tremolo/ScalePeckSpeed 'rescalen!!!!! IF ISFALSE BIT (@pT(@pTW.beattask(1)).swit, %TASK_ONOFF) THEN StartTask @pTW.beattask(1) END IF CASE 6 TO 9 @pT(@pTW.beattask(2)).freq = tremolo/ScalePeckSpeed 'rescalen!!!!! IF ISFALSE BIT (@pT(@pTW.beattask(2)).swit, %TASK_ONOFF) THEN StartTask @pTW.beattask(2) END IF CASE 10 TO 12 @pT(@pTW.beattask(3)).freq = tremolo/ScalePeckSpeed 'rescalen!!!!! IF ISFALSE BIT (@pT(@pTW.beattask(3)).swit, %TASK_ONOFF) THEN StartTask @pTW.beattask(3) END IF CASE 13 TO 14 @pT(@pTW.beattask(4)).freq = tremolo/ScalePeckSpeed 'rescalen!!!!! IF ISFALSE BIT (@pT(@pTW.beattask(4)).swit, %TASK_ONOFF) THEN StartTask @pTW.beattask(4) END IF CASE 16 'rain 'aftertouch controller for random part of speed 'volume contoller(c.s.) for fixed minimum 'when sending midi: send first note + velo, then min(vol), then rnd(aftt) @pT(@pTW.raintask).tempo = tremolo IF ISFALSE BIT(@pT(@pTW.raintask).swit, %TASK_ONOFF) THEN StartTask @pTW.raintask END IF CASE 17,18 'chimes @pT(@pTW.chimestask).freq = 2 + ((tremolo * 4) / 127!) 'INT(tremolo * 4/127) IF ISFALSE BIT(@pT(@pTW.chimestask).swit, %TASK_ONOFF) THEN StartTask @pTW.chimestask CASE 19,20 'thundersheet @pT(@pTW.thundertask).freq = tremolo/ScaleThSpeed IF ISFALSE BIT(@pT(@pTW.thundertask).swit, %Task_ONOFF) THEN StartTask @pTW.thundertask END IF END SELECT END IF END IF nv = GetProgChange(@pTW.Channel, %REMOVE OR %OLDEST) ' this should be limited to valid pieces... Cakewalk sends progchanges at startup... IF nv > %notfalse THEN ThunderWood_on %True @pTW.messagevalue = %WSB_CHANGE_PIECE OR LOBYT(nv) CALL DWORD @pTW.pMessageHandler END IF nv = GetControllers(@pTW.Channel, %Remove OR %oldest) ' rewritten 26.07.2004 IF nv > %Notfalse THEN SELECT CASE HIBYT(nv) CASE %WSB_CHANGE_VELO @pTW.Messagevalue = %WSB_CHANGE_VELO OR LOBYT(nv) CALL DWORD @pTW.pMessageHandler CASE %WSB_CHANGE_SPEED @pTW.Messagevalue = %WSB_CHANGE_SPEED OR LOBYT(nv) CALL DWORD @pTW.pMessageHandler CASE %WSB_CHANGE_DENSITY @pTW.MessageValue = %WSB_CHANGE_DENSITY OR LOBYT(nv) 'messagehandler should remember what we're playing... CALL DWORD @pTW.pMessageHandler CASE 7 ' volume used for rain tremolo = LOBYT(nv) @pT(@pTW.raintask).duur = tremolo / 20 CASE &H7B TW_AllOff ThunderWood_on %True ' 15.12.2002 END SELECT END IF END SUB SUB TW_Listen_Start () PRIVATE LOCAL pmask AS QUAD PTR pmask = SetMidiListenChannel (@pTW.channel, %True) END SUB SUB TW_Listen_Stop () PRIVATE LOCAL pmask AS QUAD PTR pmask = SetMidiListenchannel (@pTW.channel, %False) @pmask = %False ' 24.07.2004 END SUB SUB PeckerLow () EXPORT 'plays rolls on low woodblock 'all peckers limit their own frequency .1 > 25 'velo(task.level) values 1 - 127 remapped in TW_Woodpecker (dll) STATIC count AS LONG 'hammer counter IF @pT(@pTW.beattask(1)).freq > 25 THEN @pT(@pTW.beattask(1)).freq = 25 IF @pT(@pTW.beattask(1)).freq < .1 THEN @pT(@pTW.beattask(1)).freq = .1 INCR count IF count > 5 THEN count = 1 TW_WoodPecker count, @pT(@pTW.beattask(1)).level END SUB SUB PeckerTenor () EXPORT STATIC count AS LONG 'hammer counter IF ISFALSE count THEN count = 6 IF @pT(@pTW.beattask(2)).freq > 25 THEN @pT(@pTW.beattask(2)).freq = 25 IF @pT(@pTW.beattask(2)).freq < .1 THEN @pT(@pTW.beattask(2)).freq = .1 INCR count IF count > 9 THEN count = 6 IF @pT(@pTW.beattask(2)).level > 1000/@pT(@pTW.beattask(2)).freq THEN @pT(@pTW.beattask(2)).level = 1000\@pT(@pTW.beattask(2)).freq TW_WoodPecker count, @pT(@pTW.beattask(2)).level END SUB SUB PeckerAlto () EXPORT STATIC count AS LONG 'hammer counter IF ISFALSE count THEN count = 10 IF @pT(@pTW.beattask(3)).freq > 25 THEN @pT(@pTW.beattask(3)).freq = 25 IF @pT(@pTW.beattask(3)).freq < .1 THEN @pT(@pTW.beattask(3)).freq = .1 ' ThunderLog STR$(@pT(@pTW.beattask(3)).level) INCR count IF count > 12 THEN count = 10 IF @pT(@pTW.beattask(3)).level > 1000/@pT(@pTW.beattask(3)).freq THEN @pT(@pTW.beattask(3)).level = 1000\@pT(@pTW.beattask(3)).freq TW_WoodPecker count, @pT(@pTW.beattask(3)).level END SUB SUB PeckerHigh () EXPORT STATIC count AS LONG 'hammer counter IF ISFALSE count THEN count = 13 IF @pT(@pTW.beattask(4)).freq > 25 THEN @pT(@pTW.beattask(4)).freq = 25 IF @pT(@pTW.beattask(4)).freq < .1 THEN @pT(@pTW.beattask(4)).freq = .1 IF @pT(@pTW.beattask(4)).level > 1000/@pT(@pTW.beattask(4)).freq THEN @pT(@pTW.beattask(4)).level = 1000\@pT(@pTW.beattask(4)).freq INCR count IF count > 14 THEN count = 13 TW_WoodPecker count, @pT(@pTW.beattask(4)).level END SUB SUB TW_Ratch (BYVAL velo AS DWORD) EXPORT ' 1 - any , lbound trimmed to 25 'now one shot ratchet, for long rolls give large velo values ' this uses note on / note off !!! ' connected via 24V relais to midi note 15 output in the Thunderwood board ' The velo parameter just switches ON/OFF (0 switches the ratchet off, any other value switches it ON) ' ratchet is connected to the velo ports!!! ' kristof, wat doe je voor note-off hier ??? 'task ThunderWood.Ratchettask (= 'midiratchetoff) switches the midi ratchet off 'it has a tog to prevent it switching the note off @ starttask, 'so the note length is determined by its taskfreq. it switches itself of and resets its tog. TW_Ratchet velo END SUB SUB TW_Thunder_Task () EXPORT 'uses shaker task as in 'task.level (for velocity = pulse duration) should be ranged from 1 - 127 & is recomputed 'here to pulse... 'limits its own max frequency, ranging 0.1 - 20 ' since we map velo directly on the pulse duration in ms, the maximum velocity for single notes ' should be limited to 1000/freq STATIC tog AS DWORD ' uses notes 19 and 20 IF @pT(@pTW.thundertask).freq > 10 THEN @pT(@pTW.thundertask).freq = 10 'was 20 but maybe too fast? IF @pT(@pTW.thundertask).freq < .2 THEN @pT(@pTW.thundertask).freq = .2 'freq 0 = land of no return IF ISFALSE @pT(@pTW.thundertask).level THEN EXIT SUB IF ISFALSE tog THEN TW_ThunderPlate @pT(@pTW.thundertask).level tog = %True 'BIT SET tog,0 ELSE TW_ThunderPlate @pT(@pTW.thundertask).level tog = %False 'BIT RESET tog, 0 END IF END SUB SUB TW_Chimes_Task () EXPORT 'uses shaker tasks as in 'velocity values should be passed with values 1 - 127 'recomputed internally to pulse 'limits its own frequency, ranging 2 - 5.4 ' since we map velo directly on the pulse duration in ms, the maximum velocity for single notes ' should be limited to 1000/freq STATIC pulse AS DWORD STATIC tog AS DWORD IF @pT(@pTW.chimestask).freq < .2 THEN @pT(@pTW.chimestask).freq = .2 IF @pT(@pTW.chimestask).freq > 6 THEN @pT(@pTW.chimestask).freq = 6 IF ISFALSE @pT(@pTW.chimestask).level THEN EXIT SUB IF ISFALSE tog THEN pulse = 40 + ((@pT(@pTW.chimestask).level * 80) /127) TW_WindChimes pulse tog = %True 'BIT SET tog,0 ELSE TW_WindChimes @pT(@pTW.chimestask).level tog = %False 'BIT RESET tog, 0 END IF END SUB SUB TW_Rain_Task () EXPORT ' need zero protection!!! ' this is very shaky code! 'task duur = min task frequency 1-127, remapped here 'task.tempo = lbound of random frequencyamount 1-127 '?should we have frequency limits here ? 'task.level = max velo, values between 1 and level, range 1 - 127, scaled to pulse 'so we have values between starttime and (starttime + stoptime) STATIC pulse AS DWORD 'reschedule random frequency for every call ' this requires random pulses with parametric density for a good rain sound. ' could use task if we reschedule continuously with different frequencies. ' here we do not need toggling between two notes ! ' The rain machine has two parameters: velo (reflecting volume) and density (reflecting spectrum) ' Power supply: 45Volts !!! (all notes 16 to 23) IF ISFALSE @pT(@pTW.raintask).level THEN EXIT SUB pulse = @pT(@pTW.raintask).level / 5 IF pulse < 1 THEN pulse = 1 ' gwr 27.04.2002 @pT(@pTW.raintask).freq = (@pT(@pTW.raintask).duur/10) + (4*RND(1) * @pT(@pTW.raintask).tempo) ' needs further limitations on freq. IF pulse > 900/@pT(@pTW.raintask).freq THEN pulse = 900/@pT(@pTW.raintask).freq '900: was 1000 for ms, for security TW_Rain @pT(@pTW.raintask).level END SUB SUB TW_AllOff () EXPORT LOCAL bank AS BYTE LOCAL retval AS LONG STATIC b AS STRING * 18 ' should switch off all devices contained in ' added 20.11.2002: make sure all TW-tasks are switched OFF!!! StopTask @pTW.raintask StopTask @pTW.chimestask StopTask @pTW.Thundertask StopTask @pTW.beattask(1) StopTask @pTW.beattask(2) StopTask @pTW.beattask(3) StopTask @pTW.beattask(4) ' end addition 20.11.2002 - gwr TW_Wind %False SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 FOR bank = 0 TO 2 @pTW.vlatch(bank)= %False @pTW.hlatch(bank)= %False b = CHR$(bank) & CHR$(@pTW.reg(5)) & CHR$(bank) & CHR$(@pTW.reg(5) AND &H0FE) & CHR$(bank) & CHR$(@pTW.reg(5))_ & CHR$(0) & CHR$(@pTW.reg(1)) & CHR$(0) & CHR$(@pTW.reg(1) AND &H0FE) & CHR$(0) & CHR$(@pTW.reg(1))_ & CHR$(0) & CHR$(@pTW.reg(7)) & CHR$(0) & CHR$(@pTW.reg(7) AND &H0FE) & CHR$(0) & CHR$(@pTW.reg(7)) retval = ro_bufout (@pTW.pAdr, VARPTR(b),18) NEXT bank CASE ELSE FOR bank = 0 TO 2 ' 3 8-bit banks, for all 24 notes in ThunderWood Ro_PortOut @pTW.Preg, @pTW.reg(5) '%SelVeloPort ' prepare register 11.08.2000 ' Wait 1 Ro_PortOut @pTW.Padr, bank ' select bank ' Wait 1 retval = g_ro_strobe (@pTW.Preg, @pTW.reg(5),0) ' Wait 1 Ro_PortOut @pTW.Padr, %False ' all notes off in that bank ' Wait 1 Ro_PortOut @pTW.Preg, @pTW.reg(1) '%VeloReg ' Wait 1 retval = g_ro_strobe (@pTW.Preg, @pTW.reg(1),0) ' Wait 1 Ro_PortOut @pTW.Preg, @pTW.reg(7) '%VeloOut ' Wait 1 retval = g_ro_strobe (@pTW.Preg, @pTW.reg(7),0 ) ' Wait 1 @pTW.vlatch(bank)= %False @pTW.hlatch(bank)= %False NEXT bank END SELECT TW_Storm %False 'ThunderWood_on %True ' added 15.12.2002 - thats too much! END SUB SUB TW_Wind (BYVAL speed AS BYTE) EXPORT LOCAL retval AS LONG STATIC b AS STRING * 6 ' this procedure is used in Thunderwood to send a byte to the note-databus, used for ' communication with the motor DAC of the wind machine ' The note bus cannot be used for anything else here!!! ' We do not use the note latches here. 'values should be passed range 0 - 127 and are remapped internally 'the windmachine starts working at speed +- 48 'all values > 70 sound the same 'when slowing down, it keeps on moving until value 39 IF speed > 0 THEN 'speed = 39 + (speed * 31.0/127.0) ' range becomes now 30 to 70 , for speed=1 to 127 ' ' for speed=1 to 255, the range is 30 to 101 ' changed 22.04.2004: speed = 39 + (speed / 3) ' 39 to 81 for input range 7-bit ' 39 to 124 for input range 8-bit END IF SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 b = CHR$(speed) & CHR$(@pTW.reg(0)) & CHR$(speed) & CHR$(@pTW.reg(0) AND &H0FE) & CHR$(speed) & CHR$(@pTW.reg(0)) retval = ro_bufout(@pTW.padr, VARPTR(b),6) CASE ELSE Ro_PortOut @pTW.Preg,@pTW.reg(0) '%NoteReg ' prepare register 11.08.2000 Ro_PortOut @pTW.Padr, speed retval = g_ro_strobe (@pTW.Preg,@pTW.reg(0),0) ' strobe the speed data to the note latch END SELECT END SUB SUB TW_WoodPecker(BYVAL note AS DWORD, BYVAL velo AS DWORD) EXPORT ' lowest hammer of low woodblock is connected to the midi note 1 output in the Thunderwood board ' The low block has 5 hammers: 1,2,3,4,5 ' tenor block, 4 hammers : 6,7,8,9 ' alto block, 3 hammers : 10,11,12 ' high block, 2 hammers : 13,14 ' velo values 1 - 127 remapped in this procedure IF note < 1 THEN EXIT SUB IF note > 14 THEN EXIT SUB IF velo > 127 THEN velo = 127 IF ISFALSE velo THEN EXIT SUB SHIFT RIGHT velo, 2 'rescaling velo = velo + 5 TW_Beat note, velo END SUB SUB TW_ratchet (BYVAL velo AS DWORD) EXPORT IF velo < 25 THEN velo = 25 TW_Beat 15, velo END SUB SUB TW_ThunderPlate (BYVAL velo AS DWORD) EXPORT ' note mapping in hardware: alternating between notes 19 and 20 STATIC note AS BYTE IF ISFALSE note THEN note = 19 ' note0 = 19 note1 = 20 IF velo THEN velo = 14 + ((velo * 24)/127) ELSE EXIT SUB END IF TW_Beat note, velo INCR note IF note > 20 THEN note = 19 END SUB SUB TW_WindChimes (BYVAL velo AS DWORD) EXPORT ' note mapping in hardware: alternating between notes 17 and 18 STATIC note AS BYTE IF ISFALSE note THEN note = 17 IF velo THEN velo = 16 + ((velo * 34)/127) ELSE EXIT SUB END IF TW_Beat note, velo INCR note IF note > 18 THEN note = 17 END SUB SUB TW_Rain (BYVAL velo AS DWORD) EXPORT ' mapped in hardware on note 16 IF velo THEN velo = 1 + (velo * RND(1)) TW_Beat 16, velo END IF END SUB SUB TW_Light (BYVAL level AS BYTE) EXPORT LOCAL retval AS LONG LOCAL b AS STRING * 18 ' new, added 27.04.2002 - light is mapped on note 0 IF level THEN BIT SET @pTW.vlatch(0), 0 ELSE BIT RESET @pTW.vLatch(0), 0 END IF SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 b = CHR$(0) & CHR$(@pTW.reg(5)) & CHR$(0) & CHR$(@pTW.reg(5) AND &H0FE) & CHR$(0) & CHR$(@pTW.reg(5))_ & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(1)) & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(1) AND &H0FE) & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(1))_ & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(7)) & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(7) AND &H0FE) & CHR$(@pTW.vLatch(0)) & CHR$(@pTW.reg(7)) retval = ro_bufout (@pTW.padr,VARPTR(b),18) CASE ELSE Ro_PortOut @pTW.Preg,@pTW.reg(5) Ro_PortOut @pTW.Padr, 0 ' select the correct note adress for the velo data latch retval = g_ro_strobe (@pTW.Preg,@pTW.reg(5), 0) ' strobe it into the 74574, nr 4 ' latch the note bits: Ro_PortOut @pTW.Preg,@pTW.reg(1) ' prepare register Ro_PortOut @pTW.padr, @pTW.vLatch(0) retval = g_ro_strobe (@pTW.Preg,@pTW.reg(1), 0) ' strobe the note data to the velo latch ' strobe the 74154, which has been loaded with data: Ro_PortOut @pTW.Preg,@pTW.reg(7) retval = g_ro_strobe (@pTW.Preg,@pTW.reg(7),0) END SELECT END SUB SUB TW_Beat (BYVAL note AS BYTE, BYVAL velo AS BYTE) EXPORT LOCAL retval AS LONG IF ISFALSE velo THEN EXIT SUB IF ISFALSE note THEN EXIT SUB 'not for lightning ' we use thread oneshot timers in the DLL for velocity timing... retval = TimeSetEvent(velo,0,CODEPTR(TW_VeloPulse),note, %TIME_ONESHOT OR %TIME_CALLBACK_FUNCTION) IF ISFALSE retval THEN TW_Velo note, %False ELSE TW_Velo note, %True ' set the velo-bit high, immediately after starting the timer ' to avoid double triggering. END IF ' the one-shot should reset the velo bit... END SUB FUNCTION TW_VeloPulse (BYVAL wTimerID AS LONG, BYVAL msg AS LONG, BYVAL EventNr AS LONG, BYVAL dw1 AS LONG, BYVAL dw2 AS LONG) AS LONG ' callback function for one-shot timers, used for percussion instruments. LOCAL retval AS LONG ' note passed via parameter EventNr (0-127), thus there are as many timers as we have notes. TW_Velo EventNr, %False ' reset velo bit. retval = timeKillEvent (wTimerID) FUNCTION = %False END FUNCTION SUB TW_Velo (BYVAL noot AS BYTE, BYVAL param AS BYTE) LOCAL retval AS LONG LOCAL b AS STRING * 18 ' this procedure sends the corresponding note bit to the latch and holds it high ' param = %False is velo OFF ' param = %True is velo ON IF noot THEN IF param THEN BIT SET @pTW.vlatch(noot \ 8), noot AND 7 ELSE BIT RESET @pTW.vLatch(noot \8), noot AND 7 END IF SELECT CASE @pTW.padr CASE &H08A00 TO &H08A40 b = CHR$(noot\8) & CHR$(@pTW.reg(5)) & CHR$(noot\8) & CHR$(@pTW.reg(5) AND &H0FE) & CHR$(noot\8) & CHR$(@pTW.reg(5))_ & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(1)) & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(1) AND &H0FE) & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(1))_ & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(7)) & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(7) AND &H0FE) & CHR$(@pTW.vLatch(noot\8)) & CHR$(@pTW.reg(7)) retval = ro_bufout (@pTW.padr, VARPTR(b), 18) CASE ELSE Ro_PortOut @pTW.Preg,@pTW.reg(5) Ro_PortOut @pTW.Padr,noot \ 8 ' select the correct note adress for the velo data latch ' DATA= 0-15 (127 \ 8 = 15) retval = g_ro_strobe (@pTW.Preg,@pTW.reg(5), 0) ' strobe it into the 74574, nr 4 ' latch the note bits: Ro_PortOut @pTW.Preg,@pTW.reg(1) ' prepare register Ro_PortOut @pTW.padr, @pTW.vLatch(noot\8) retval = g_ro_strobe (@pTW.Preg,@pTW.reg(1), 0) ' strobe the note data to the velo latch ' output the attack start pulse: ' strobe the 74154, which has been loaded with data: Ro_PortOut @pTW.Preg,@pTW.reg(7) retval = g_ro_strobe (@pTW.Preg,@pTW.reg(7),0) END SELECT ELSE TW_light param END IF END SUB #ENDIF