' ************************************************* ' * * ' * for clarinet and interactive electronics * ' * 2001 * ' * Godfried-Willem RAES * ' * A composition commissioned by * ' * Michele Marelli * ' ************************************************* ' 05.06.2001 started off from Lickstick code framework. ' 29.07.2001 cannot be compiled without LickStick ! ' 13.06.2002 adapted to version 5.82 ' 11.10.2003 adepted to version 7.20 ' 27.03.2005 adapted to PBWIN8.0 ' 03.10.2006: adapted to new paths for audiofiles %WoodStock_Score_Task = 17 %WoodStock_V1_Task = 25 ' Voice 1 / Stimme 1 %WoodStock_V2_Task = 26 ' Voice 2 / Stimme 2 #IF NOT %DEF(%Pattern1_Task) %Pattern1_Task = 28 ' Formula 1 %Pattern2_Task = 29 ' Formula 2 %Pattern3_Task = 30 ' Formula 3 #ENDIF %ClarDetune_Task = 32 ' delay line 1 ' as in cellopi and lickstick %InvFast_Task = 33 ' midi delay line players %BackInv_Task = 34 %BackSlow_Task = 35 %Gerade_Task = 36 ' straight delay line %LS_RingModulator_Task = %AudioRingModulator_Task ' =53 specific for LickStick/WoodStock %LS_PitchShift_Task = %AudioVarspeed_Task ' =56 split off from %AudioProcess Task 07.03.2000 GLOBAL Clarinet AS MUSICIAN DECLARE FUNCTION InitWoodStock () AS LONG DECLARE SUB WoodStockInitSynth () DECLARE SUB ButnSW_WoodStockStartStop () DECLARE SUB WoodStockScore() DECLARE SUB ClarListen () ' midi input listening task DECLARE SUB WoodStockPatternAlgo (pattern AS BYTE) ' input score calculation DECLARE SUB SetClarinetContext (noot?, velo?) ' as in cellopi DECLARE SUB WoodStockDoEvent () ' interactive score ' following is borrowed from Lickstick module... 'DECLARE SUB GetLastNote(noot?, velo?, Instrument AS musician) ' generalized version to replace former individual procedures ' in Cellopi, Cohiba, Obotek, Toverfluit... DECLARE SUB WoodStockPattern1 () ' Formel 1 DECLARE SUB WoodStockPattern2 () ' Formel 2 DECLARE SUB WoodStockPattern3 () ' Formel 3 ' borrowed from Lickstick: DECLARE SUB WS_Stock1 () ' stimme1 / voice1 / stick1 DECLARE SUB WS_Stock2 () ' audio tasks DECLARE SUB WoodStockPitchShift () ' speeds up/down recorded sample DECLARE SUB WoodStockPlaySample () ' plays prerecorded samples from disk - WoodStockSpecific DECLARE SUB WoodStockRingModulator () ' midi delaylines: DECLARE SUB ClarDetune() DECLARE SUB WoodStockDelayInvertFast () DECLARE SUB WoodStockDelayBackInvert () DECLARE SUB WoodStockDelayBackSlow () DECLARE SUB WoodStockDelayPlayerNormal () ' generalizable: ' borrowed from lickstick module: DECLARE FUNCTION WS_GetDifferentPatternNote (PatternSeq() AS PatternSequenceType, pattern AS BYTE) AS INTEGER '------------------------------------------------------------------- FUNCTION InitWoodStock () AS LONG LOCAL tasknr AS INTEGER LOCAL nr AS LONG LOCAL CockpitLayo AS CockpitLabels FUNCTION = %False IF ISFALSE hMidiI(0) THEN ErrorMidiIn : EXIT FUNCTION IF ISFALSE hMidiO(0) THEN ErrorMidiOut : EXIT FUNCTION SelectMidiEquipment $WOODSTOCKINI, Meq() Update_MidiEquipment Meq() ReadPatternRecognitionDataFile $WOODSTOCKINI ReadSynthConfigFile $WOODSTOCKINI ,Meq() ' should know the Meq() selected!!! ' ReadFaderParams $WOODSTOCKINI , AudioFader() ReadCockpitLabelsFromFile $WOODSTOCKINI, CockpitLayo Recording_Available = %False ' false on init. - global variable GetInstrumentParams Clarinet, %ID_Clarinet Clarinet.channel = 0 ' midi input listening channel Clarinet.patch = %ID_Clarinet ' gm patch is 71 Recog.Cptr = CODEPTR(WoodStockDoEvent) ' input recognition callback ButnSW(1).tag0 = "START" ' start/stop toggle ButnSW(1).tag1 = "STOP" ButnSW(1).cptr = CODEPTR(ButnSW_WoodStockStartStop) ' change the default routing !!! ButnSW(2).tag0 = "" ' "STAFF" ' creates/kills a music monitoring window ButnSW(3).tag0 = "" ' "USER" ' creates/kills a user feedback window ButnSW(7).tag0 = "" ButnSW(8).tag0 = "" ButnSW(9).tag0 = "" ButnSW(10).tag0 = "" ButnSW(11).tag0 = "" ' ONE SHOT FUNCTIONS: ButnOS(1).tag = "" ButnOS(2).tag = "" ButnOS(3).tag = "" ButnOS(4).tag = "" ButnOS(5).tag = "" ButnOS(6).tag = "" ButnOS(8).tag = "Clear" ' clears delay lines ButnOS(7).tag = "" ButnOS(9).tag = "" ButnOS(10).tag = "" ' declaration of specific tasks: Task(%Listen_Task).naam = "Listen" Task(%Listen_Task).freq = 30 Task(%Listen_Task).channel = Clarinet.channel Task(%Listen_Task).cptr = CODEPTR(ClarListen) Task(%Listen_Task).starttime = 0 Task(%Listen_Task).stoptime = 1000 Task(%Listen_Task).Rit.minduur = Clarinet.minduur/1000 ' in ms in type Task(%Listen_Task).Rit.maxduur = Clarinet.maxduur/1000 Task(%Listen_Task).flags = Task(%Listen_Task).flags OR %MIDI_TASK OR %HARM_TASK OR %SCORE_TASK Task(%WoodStock_Score_Task).naam = "Scoring" ' for automatic playing - scheduler Task(%WoodStock_Score_Task).freq = 1 Task(%WoodStock_Score_Task).tempo = 60 Task(%WoodStock_Score_Task).cptr = CODEPTR(WoodStockScore) Task(%WoodStock_V1_Task).naam = "wStock 1" ' vertical harmony stimme 1 Task(%WoodStock_V1_Task).cptr = CODEPTR(WS_Stock1) Task(%WoodStock_V1_Task).freq = 1 Task(%WoodStock_V1_Task).tempo = 20 Task(%WoodStock_V1_Task).flags = Task(%WoodStock_V1_Task).flags OR %MIDI_TASK OR %SCORE_TASK Task(%WoodStock_V2_Task).naam = "wStock 2" ' vertical harmony stimme 2 Task(%WoodStock_V2_Task).cptr = CODEPTR(WS_Stock2) Task(%WoodStock_V2_Task).freq = 1 Task(%WoodStock_V2_Task).tempo = 20 Task(%WoodStock_V2_Task).flags = Task(%WoodStock_V2_Task).flags OR %MIDI_TASK OR %SCORE_TASK Task(%Pattern1_Task).naam = "Formula1" Task(%Pattern1_Task).freq = 20 Task(%Pattern1_Task).tempo = 60 Task(%Pattern1_Task).cptr = CODEPTR(WoodStockPattern1) Task(%Pattern1_Task).starttime = -1 Task(%Pattern1_Task).stoptime = 1000 Task(%Pattern1_Task).Rit.minduur = .035 Task(%Pattern1_Task).Rit.maxduur = 4 ' in s Task(%Pattern1_Task).flags = Task(%Pattern1_Task).flags OR %MIDI_TASK Task(%Pattern2_Task).naam = "Formula2" Task(%Pattern2_Task).freq = 30 Task(%Pattern2_Task).tempo = 61 Task(%Pattern2_Task).cptr = CODEPTR(WoodStockPattern2) Task(%Pattern2_Task).starttime = -1 Task(%Pattern2_Task).stoptime = 1000 Task(%Pattern2_Task).Rit.minduur = .025 Task(%Pattern2_Task).Rit.maxduur = 4 ' in s Task(%Pattern2_Task).flags = Task(%Pattern2_Task).flags OR %MIDI_TASK Task(%Pattern3_Task).naam = "Formula3" Task(%Pattern3_Task).freq = 16 Task(%Pattern3_Task).tempo = 62 Task(%Pattern3_Task).cptr = CODEPTR(WoodStockPattern3) Task(%Pattern3_Task).starttime = -1 Task(%Pattern3_Task).stoptime = 1000 Task(%Pattern3_Task).Rit.minduur = .045 Task(%Pattern3_Task).Rit.maxduur = 4 ' in s Task(%Pattern3_Task).flags = Task(%Pattern3_Task).flags OR %MIDI_TASK Task(%ClarDetune_Task).naam = "Detune" Task(%ClarDetune_Task).freq = 24 Task(%ClarDetune_Task).cptr = CODEPTR(ClarDetune) Task(%ClarDetune_Task).Rit.minduur = 0.035 ' in s Task(%ClarDetune_Task).Rit.maxduur = 5.000 ' in s Task(%ClarDetune_Task).flags = Task(%ClarDetune_Task).flags OR %MIDI_TASK Task(%InvFast_Task).naam = "FastInv" Task(%InvFast_Task).freq = 60 Task(%InvFast_Task).cptr = CODEPTR(WoodStockDelayInvertFast) Task(%InvFast_Task).Rit.minduur = 0.050 ' in s Task(%InvFast_Task).Rit.maxduur = 5.000 ' in s Task(%InvFast_Task).flags = Task(%InvFast_Task).flags OR %MIDI_TASK OR %HARM_TASK Task(%BackInv_Task).naam = "InvCanc" Task(%BackInv_Task).freq = 58 Task(%BackInv_Task).cptr = CODEPTR(WoodStockDelayBackInvert) Task(%BackInv_Task).Rit.minduur = 0.050 ' in s Task(%BackInv_Task).Rit.maxduur = 5.000 ' in s Task(%BackInv_Task).flags = Task(%BackInv_Task).flags OR %MIDI_TASK OR %HARM_TASK Task(%BackSlow_Task).naam = "SloCanc" Task(%BackSlow_Task).freq = 31 Task(%BackSlow_Task).cptr = CODEPTR(WoodStockDelayBackSlow) Task(%BackSlow_Task).Rit.minduur = 0.10 ' in s Task(%BackSlow_Task).Rit.maxduur = 10.000 ' in s Task(%BackSlow_Task).flags = Task(%BackSlow_Task).flags OR %MIDI_TASK OR %HARM_TASK Task(%Gerade_Task).naam = "Straight" Task(%Gerade_Task).freq = 35 Task(%Gerade_Task).cptr = CODEPTR(WoodStockDelayPlayerNormal) Task(%Gerade_Task).Rit.minduur = 0.10 ' in s Task(%Gerade_Task).Rit.maxduur = 10.000 ' in s Task(%Gerade_Task).flags = Task(%Gerade_Task).flags OR %MIDI_TASK OR %HARM_TASK ' realtime audio tasks:----------------------------------------------- Task(%AudioDelay_Task).naam = "Delay" ' = 48 Task(%AudioDelay_Task).cPtr = CODEPTR(gwrAudioDelay) ' in gmt_gwr.bas Task(%AudioDelay_Task).freq = 20 Task(%AudioDelay_Task).duur = 8000 Task(%AudioSample_Task).naam = "Record" ' =49 Task(%AudioSample_Task).cPtr = CODEPTR(gwrRecordSample) ' in gmt_gwr.bas Task(%AudioSample_Task).freq = 20 Task(%AudioSample_Task).duur = 4000 ' was 3000 on 28.02.2000 ' this time is increased during the piece. ' (cfr. do-event code) Task(%AudioPlayReversed_Task).naam = "Reverse" '50 Task(%AudioPlayReversed_Task).cPtr = CODEPTR(gwrPlayReversed) ' backwards Task(%AudioPlayReversed_Task).freq = 20 Task(%AudioPlaySample_Task).naam = "PlaySamp" ' = 51 - playback of prerecorded samples Task(%AudioPlaySample_Task).cPtr = CODEPTR(WoodStockPlaySample) ' - specific code for WoodStock Task(%AudioPlaySample_Task).freq = 20 Task(%AudioPlayRecordedSample_Task).naam = "PlayBack" '[ = 52] Task(%AudioPlayRecordedSample_Task).cPtr = CODEPTR(gwrPlayRecordedSample) ' in gmt_gwr.bas Task(%AudioPlayRecordedSample_Task).freq = 22 Task(%LS_RingModulator_Task).naam = "RingMod" ' 53 Task(%LS_RingModulator_Task).cPtr = CODEPTR(WoodStockRingModulator) Task(%Ls_RingModulator_Task).freq = 7 Task(%AudioCrossModulator_Task).naam = "CrossMod" ' 54 Task(%AudioCrossModulator_Task).cPtr = CODEPTR(gwrCrossModulator) ' in gmt_gwr.bas Task(%AudioCrossModulator_Task).freq = 6 Task(%AudioCrossTimeModulator_Task).naam = "CrossTim" ' 55 ' in gmt_gwr.bas Task(%AudioCrossTimeModulator_Task).cPtr = CODEPTR(gwrCrossTimeModulator) Task(%AudioCrossTimeModulator_Task).freq = 6 Task(%LS_PitchShift_Task).naam = "VarSpeed" ' split of from audioprocess 07.03.2000 Task(%LS_PitchShift_Task).cPtr = CODEPTR(WoodStockPitchShift) Task(%LS_PitchShift_Task).freq = 8 nr = ReadAudioDataFromFile ($WoodStockINI, AudioFader()) ' dll call ' for now, lets delete audiofader tasks... Task(0).naam = "" Task(0).cPtr = %False Task(AudioFader(0).TaskNr).naam = "" Task(AudioFader(0).TaskNr).cPtr = %False Task(AudioFader(1).TaskNr).naam = "" Task(AudioFader(1).TaskNr).cPtr = %False WoodStockInitSynth LastNotePlayed = 50 'Bb Clarinet. ' create the melody window automatically on startup: LOCAL msg AS tagMSG msg.hWnd = gh.Cockpit msg.message = %WM_COMMAND msg.wParam = %GMT_BUTNSW_ID + 5 ' creates score display window. msg.lParam = %Null DispatchMessage msg DrawAllPatterns gh.MelPat ' display the score... (this only prepares the window size!) ' write caption bars: LOCAL m AS ASCIIZ * 40 m = "GMT: " Sendmessage gh.Cockpit, %WM_SETTEXT,0, VARPTR(m) m = " Score" SendMessage gh.MelPat, %WM_SETTEXT,0, VARPTR(m) FUNCTION = %True END FUNCTION SUB WoodStockInitSynth () EXPORT LOCAL i AS DWORD LOCAL param AS BYTE LOCAL value AS BYTE ' this procedure sends all midi settings to the midi gear needed for this piece. ' if the tasks are already initialized: ' It is not indispensable to do this, since starting a task that uses midi, will automatically send the ' correct patch to the port/channel, if it uses only a single channel at least and if the autoflag is set. FOR i = LBOUND(Task) TO UBOUND(Task) IF BIT (Task(i).flags, 0) THEN ' bit 0 = %Midi_TASK = 1 SELECT CASE TRIM$(UCASE$(Meq(0).naam)) CASE "PROTEUS2", "PROTEUS2XR","PROTEUS2000","PROTEUS3","PROTEUS3XR" ProteusPatch Meq(0), Task(i).channel, Task(i).patch CASE ELSE ProgChange Task(i).channel, Task(i).patch END SELECT ModeMess Task(i).channel, &H79, 0 ' reset all controllers ModeMess Task(i).channel, 7, Task(i).level ModeMess Task(i).channel, 10, Task(i).pan END IF NEXT i SetPitchBendRange Meq(0),0,1 ' set global pitchbendrange to +/- 1 semitone -dll procedure END SUB SUB WoodStockDoEvent () ' recognition wave playing waits for device available, so that the sample always plays, even if too late... ' however, in the present version, there is no cueing up of files/ tracks to be played... STATIC delaytimecounter AS BYTE LOCAL chk AS BYTE IF ISFALSE Task(%AudioPlaySample_Task).swit THEN StartTask %AudioPlaySample_Task ' specific version for WoodStock. DrawAllPatterns gh.MelPat SELECT CASE Recog.nr CASE 1 ' samples: detunes IF Task(%ClarDetune_Task).swit THEN StartTask %ClarDetune_Task ' starts/stops velo-dependent detuning on recognition of La IF BIT(Task(%BackInv_Task).swit,%TASK_ONOFF) THEN StopTask %BackInv_Task ReadDelayLine% %BackInv_Task, 0, 0 ' force a reset END IF ELSE StopTask %ClarDetune_Task ReadDelayLine% %ClarDetune_Task, 0,0 ' force reset IF ISFALSE Task(%BackInv_Task).swit THEN StartTask %BackInv_Task ELSE StopTask %BackInv_Task ReadDelayLine% %BackInv_Task, 0, 0 ' force a reset END IF END IF WoodStockPatternAlgo Recog.nr - 1 ' recalculate new pattern CASE 2 ' samples: ademklasse chk = %False IF ISFALSE Task(%AudioSample_Task).swit THEN IF ISFALSE Task(%AudioDelay_Task).swit THEN Task(%AudioSample_Task).duur = Task(%AudioSample_Task).duur * 1.5 ' recording duration ' was set to 5000 ms before 29.02.2000. StartTask %AudioSample_Task ' autostops. chk = %True IF BIT(Task(%Gerade_Task).swit,%TASK_ONOFF) THEN StopTask %Gerade_Task ReadDelayLine% %Gerade_Task, 0, 0 ' force a reset END IF END IF END IF IF ISFALSE chk THEN IF ISFALSE Task(%Gerade_Task).swit THEN StartTask %Gerade_Task ELSE StopTask %Gerade_Task ReadDelayLine% %Gerade_Task, 0, 0 ' force a reset END IF END IF WoodStockPatternAlgo Recog.nr -1 CASE 3 ' samples: multiphonics ' mPlay RT recorded sample. only if a recorded sample is available... IF Recording_Available THEN ' flag to signal availibility of a recorded sample. IF ISFALSE Task(%AudioPlayRecordedSample_Task).swit THEN StartTask %AudioPlayRecordedSample_Task ' autostops IF BIT(Task(%BackSlow_Task).swit,%TASK_ONOFF) THEN StopTask %BackSlow_Task ReadDelayLine% %BackSlow_Task, 0, 0 ' force a reset END IF ELSE IF BIT(Task(%BackSlow_Task).swit,%TASK_ONOFF) THEN StopTask %BackSlow_Task ReadDelayLine% %Backslow_Task, 0,0 ' reset END IF END IF ELSE IF ISFALSE Task(%BackSlow_Task).swit THEN StartTask %BackSlow_Task 'WoodStockDelayBackSlow ELSE StopTask %BackSlow_Task ReadDelayLine% %BackSlow_Task, 0, 0 ' force a reset END IF END IF WoodStockPatternAlgo Recog.nr -1 CASE 4 ' samples: Pitched clicks ' start audio delay line... ' we pass the delay time in Task().duur , expressed in milliseconds ' the duration of the delay event in Task().stoptime, expressed in seconds IF ISFALSE Task(%AudioDelay_Task).swit THEN INCR delaytimecounter Task(%AudioDelay_Task).duur = 2000 - (delaytimecounter * 100) ' in ms. IF Task(%AudioDelay_Task).duur < 255 THEN Task(%AudioDelay_Task).duur = 255 Task(%AudioDelay_Task).stoptime = 30 - (delaytimecounter) ' in seconds IF Task(%AudioDelay_Task).stoptime < 1 THEN Task(%AudioDelay_Task).stoptime = 1 StartTask %AudioDelay_Task ' SetDlgItemText hCockpit, %GMT_MSG1, "Audio-delay " & STR$(Task(%AudioDelay_Task).duur) & "ms " & STR$(Task(%AudioDelay_Task).stoptime) & " s " ELSE ' start a midi-delay... IF ISFALSE Task(%InvFast_Task).swit THEN StartTask %InvFast_Task ' autostops ELSE StopTask %InvFast_Task ReadDelayLine% %InvFast_Task, 0, 0 ' force a reset END IF END IF WoodStockPatternAlgo Recog.nr -1 CASE 5 ' samples: artikulaties IF ISFALSE Task(%Pattern1_Task).swit THEN StartTask %Pattern1_Task ' pattern 1 chk = %True ELSE StopTask %Pattern1_Task IF Recording_Available THEN IF ISFALSE Task(%AudioPlayReversed_Task).swit THEN StartTask %AudioPlayReversed_Task ' reverse playback audio chk = %True IF BIT(Task(%InvFast_Task).swit,%TASK_ONOFF) THEN StopTask %InvFast_Task ReadDelayLine% %InvFast_Task, 0, 0 ' force a reset END IF ELSE chk = %False END IF ELSE chk = %False END IF END IF IF ISFALSE chk THEN IF ISFALSE Task(%InvFast_Task).swit THEN StartTask %InvFast_Task ELSE StopTask %InvFast_Task ReadDelayLine% %InvFast_Task, 0, 0 ' force a reset END IF END IF WoodStockPatternAlgo Recog.nr -1 CASE 6 ' samples: noiseclicks IF ISFALSE Task(%Pattern2_Task).swit THEN StartTask %Pattern2_Task ELSE StopTask %Pattern2_Task IF Recording_Available THEN IF ISFALSE Task(%AudioCrossTimeModulator_Task).swit THEN StartTask %AudioCrossTimeModulator_Task END IF END IF END IF WoodStockPatternAlgo Recog.nr -1 CASE 7 ' samples: flatterzunge IF ISFALSE Task(%Pattern3_Task).swit THEN StartTask %Pattern3_Task ' pattern 3 IF Recording_Available THEN ' added 07.03.2000 IF ISFALSE Task(%LS_PitchShift_Task).swit THEN StartTask %LS_PitchShift_Task END IF END IF ELSE StopTask %Pattern3_Task IF Recording_Available THEN IF ISFALSE Task(%AudioCrossModulator_Task).swit THEN StartTask %AudioCrossModulator_Task END IF END IF END IF CASE 8 ' samples: Noise IF Recording_Available THEN IF ISFALSE Task(%LS_RingModulator_Task).swit THEN StartTask %LS_RingModulator_Task IF BIT(Task(%InvFast_Task).swit,%TASK_ONOFF) THEN StopTask %InvFast_Task ReadDelayLine% %InvFast_Task, 0, 0 ' force a reset END IF END IF ELSE IF ISFALSE Task(%InvFast_Task).swit THEN StartTask %InvFast_Task ELSE StopTask %InvFast_Task ReadDelayLine% %InvFast_Task, 0, 0 ' force a reset END IF END IF END SELECT END SUB SUB ClarListen () EXPORT LOCAL nv% LOCAL noot? LOCAL velo? LOCAL Xlatv AS WORD STATIC oldnote% IF ISFALSE Task(%Listen_Task).tog THEN IF (Task(%Listen_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB oldnote% = %False Task(%Listen_Task).tog = %True END IF nv% = GetMidiNote% (Task(%Listen_Task).channel, %Remove OR %Oldest) IF nv% = %NotFalse THEN EXIT SUB ' no new note in buffer velo? = LOBYT (nv%) noot? = HIBYT (nv%) ' if note within range... IF (noot? >= Clarinet.lowtes) AND (noot? <= Clarinet.hightes) THEN ' if note-on.... IF velo? > %False THEN IF oldnote% THEN DelNote2Har Task(%Listen_Task).Har, oldnote% ' remove oldnote ... This implies monophonic instrument. WriteDelayLine oldnote%, 0 GetLastNote LOBYT(oldnote%), 0 , Clarinet ' sets/updates the global var LastNotePlayed END IF AddNote2Har Task(%Listen_Task).Har, (noot?), (velo?) WriteDelayLine noot?, velo? GetLastNote noot?, velo?, Clarinet oldnote% = noot? ELSE ' if note off... WriteDelayLine noot?, 0 GetLastNote noot?, 0, Clarinet DelNote2Har Task(%Listen_Task).Har, (noot?) ' we delete the note after calling GetLastNote and its ' implied MatchPattern call, since we need the velo value of the ' note just switched of there! oldnote% = %False END IF SetClarinetContext noot?, velo? ' following should become part of a monitoring task... SetDlgItemText gh.Cockpit, %GMT_TEXT_TES, STR$(INT(WoodStock.tes)) SetDlgItemText gh.Cockpit, %GMT_MSG1, "V=" & STR$(WoodStock.vol) & " d=" & FORMAT$(WoodStock.dens,"##.#") END IF END SUB SUB ClarDetune () EXPORT ' the midi output of this procedure should be routed to a Proteus synth, or, ' to a TSR24 in pitch shifting mode...(on real-audio input). LOCAL nv% LOCAL noot? LOCAL velo? LOCAL detunednote! IF ISFALSE Task(%ClarDetune_Task).tog THEN IF (Task(%ClarDetune_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%ClarDetune_Task).tog = %True END IF nv% = ReadDelayLine%(%ClarDetune_Task, 20, 1!) ' 20 millisecond delay SELECT CASE nv% CASE %False EXIT SUB CASE %NotFalse EXIT SUB ' if no note came in, exit the task CASE -2 ' This can only happen if speed! > 1! nv% = ReadDelayLine%(%ClarDetune_Task, 0, 0) ' force a reset AllNotesOff Task(%ClarDetune_Task).channel StopTask %ClarDetune_Task Task(%ClarDetune_Task).tog = %False EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) IF velo? THEN AllNotesOff Task(%ClarDetune_Task).channel detunednote! = noot? + ((velo? - 64)/64) ' deze modulator is een funktie van de ' geluidsterkte van de input. ' Tested O.K. works very nicely. NoteCentOn Task(%ClarDetune_Task).channel, detunednote!, velo? ELSE AllNotesOff Task(%ClarDetune_Task).channel END IF END SUB SUB WoodStockScore() EXPORT STATIC msduration AS DWORD ' scoring task. IF ISFALSE Task(%WoodStock_Score_Task).tog THEN IF (Task(%WoodStock_Score_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%WoodStock_Score_Task).tog = %True msduration = App.komposduur * 1000 ' convert to milliseconds Task(%WoodStock_Score_Task).freq = 1 END IF IF Getpromil% < 0 THEN EXIT SUB 'Normprop = (tnow - tstart)/ msduration WoodStock.Angle = ((timeGetTime - App.tstart) * Pi2)/ msduration ' 0 to Pi2 (radians) IF WoodStock.Angle > Pi2 THEN WoodStock.Angle = WoodStock.Angle - Pi2 ' circles ' here we should add all code for linear scoring (if any...) ' If Getpromil% < 10 END SUB SUB ButnSW_WoodStockStartStop () LOCAL ButtonNr AS LONG LOCAL i AS DWORD ButtonNr = App.butnSWparam - %GMT_BUTNSW_ID IF ButnSW(Buttonnr).flag THEN App.MTstart = %True App.tstart = timeGetTime ' start the chronometerfunction SetDlgItemText gh.Cockpit, %GMT_BUTNSW_ID + ButtonNr, "STOP" ClearMiBuf 0 ' start with a blank midi input buffer BlockSysExReception hMidiI(0) 'SxThread ' dll proc ' StartTask App.PromilTasknr Promil %True ' StartTask App.RunTimeTaskNr runtime %True StartTask %Listen_Task StartTask %WoodStock_Score_Task StartTask App.GlobalHarmonyTaskNr DrawAllPatterns gh.MelPat ' does not work here!, only on a second push on the button... ELSE App.MTstart = %False SetDlgItemText gh.Cockpit, %GMT_BUTNSW_ID + ButtonNr, "CONT" END IF App.butnSWparam = %False END SUB SUB SetClarinetContext (noot?, velo?) EXPORT STATIC tog AS BYTE STATIC Cnt() AS BYTE STATIC oldwijzer AS DWORD LOCAL wijzer AS DWORD LOCAL nrevents AS LONG IF ISFALSE tog THEN WoodStock.vol = 24 ' midi level WoodStock.tes = 440 ' in Hz WoodStock.dens = 0.5 ' in events/sec (Hz) tog = %True DIM Cnt(0 TO 255) ' 1 byte for every cs. - so we integrate over 2,56 seconds END IF ' bereken de gemiddelde geluidsterkte van de input (integration) IF velo? THEN WoodStock.Vol = WoodStock.Vol + WoodStock.Vol + WoodStock.Vol + velo? SHIFT RIGHT WoodStock.Vol, 2 END IF ' ' bereken de gemiddelde tessituurligging van de input IF noot? THEN WoodStock.tes = ((WoodStock.tes * 3) + N2F(noot?)) / 4 END IF ' calculate the density of the input over a timeframe of 255cs. ' The result is returned in WoodStock.dens wijzer = (timeGetTime / 10) 'MOD 256 wijzer = wijzer AND 255 IF wijzer <> oldwijzer THEN DO INCR oldwijzer oldwijzer = oldwijzer AND 255 Cnt(oldwijzer) = %False LOOP UNTIL oldwijzer = wijzer END IF Cnt(wijzer) = %True ' now count the number of events in the buffer: FOR wijzer = 0 TO 255 IF Cnt(wijzer) THEN INCR nrevents NEXT wijzer WoodStock.dens = nrevents / 2.56! ' express result in events/second ' max.value = 100 ' note that these values should be halved for approximate tempo ' derivation, since here we count both note-ons and note-offs. END SUB SUB WS_Stock1 () EXPORT STATIC Ritmeteller% STATIC HarV1 AS HarmType STATIC starttempo AS SINGLE LOCAL tiks! IF ISFALSE Task(%WoodStock_V1_Task).tog THEN IF (Task(%WoodStock_V1_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%WoodStock_V1_Task).tog = %True HarV1.vel = STRING$(128,0) starttempo = Task(%WoodStock_V1_Task).tempo ' should become dependent on input tempo! END IF ' This procedure is polyphonic. IF Task(%WoodStock_V1_Task).Rit.pattern(Ritmeteller%) = 0 THEN Ritmeteller% = 0 ' get new parameters: Task(%WoodStock_V1_Task).tempo = WoodStock.dens / 8 IF Task(%WoodStock_V1_Task).tempo < 5 THEN Task(%WoodStock_V1_Task).tempo = 5 ' return a new pattern for the rhythm as soon as the actual one has been completed. (new bar): Iprop2Rit Task(App.GlobalHarmonyTasknr).Har, %WoodStock_V1_Task, 3 END IF tiks! = RitmSigma!(Task(%WoodStock_V1_Task).Rit) IF tiks! <= 0 THEN EXIT SUB ' het tempo voor een gehele maat is frq = task(tasknr%).tempo / 60 ' zo'n gehele maat beslaat een aantal eenheden gegeven in tiks! Task(%WoodStock_V1_Task).freq = (tiks! * Task(%WoodStock_V1_Task).tempo ) / (60 * ABS(Task(%WoodStock_V1_Task).Rit.pattern(Ritmeteller%))) IF Task(%WoodStock_V1_Task).Rit.pattern(Ritmeteller%) < 0 THEN ' this means we have to mPlay a rest... Task(%WoodStock_V1_Task).Har.vel = STRING$(128,0) ELSE ' now we have to find a new chord to mPlay for our task... IF Task(App.GlobalHarmonyTasknr).Har.vel <> STRING$(128, 0) THEN SELECT CASE Ritmeteller% MOD 3 CASE %False Task(%WoodStock_V1_Task).Har.vel = SolveHar$ (Task(App.GlobalHarmonyTasknr).Har, BYCOPY LastNotePlayed, 0.05) CASE %True Task(%WoodStock_V1_Task).Har.vel = InBetweenHar$(HarV1, Task(App.GlobalHarmonyTaskNr).Har) CASE 2 Task(%WoodStock_V1_Task).Har.vel = DiminuteHar$(HarV1,LastNotePlayed MOD 12,11,1) ' aug END SELECT ELSE Task(%WoodStock_V1_Task).Har.vel = STRING$(128,0) END IF END IF INCR Ritmeteller% IF Task(%WoodStock_V1_Task).Har.vel <> HarV1.vel THEN IF Task(%WoodStock_V1_Task).Har.vel <> Task(App.GlobalHarmonyTasknr).Har.vel THEN PlayHar Task(%WoodStock_V1_Task).Har, Task(%WoodStock_V1_Task).channel ' playhar keeps track of oldnotes internally... IF Task(%WoodStock_V1_Task).Har.vel <> STRING$(128,0) THEN HarV1.vel = Task(%WoodStock_V1_Task).Har.vel ' remember previous output. END IF END IF END IF END SUB SUB WS_Stock2 () EXPORT STATIC Ritmeteller% STATIC HarV2 AS HarmType STATIC starttempo AS SINGLE LOCAL tiks! IF ISFALSE Task(%WoodStock_V2_Task).tog THEN IF (Task(%WoodStock_V2_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%WoodStock_V2_Task).tog = %True HarV2.vel = STRING$(128,0) starttempo = Task(%WoodStock_V2_Task).tempo ' should be dependent on input tempo! END IF ' modelled after VoicePrototype in GMT.BAS / Cohiba.bas ' This procedure is polyphonic. IF Task(%WoodStock_V2_Task).Rit.pattern(Ritmeteller%) = 0 THEN Ritmeteller% = 0 ' get new parameters: Task(%WoodStock_V2_Task).tempo = WoodStock.dens / 8 IF Task(%WoodStock_V2_Task).tempo < 4 THEN Task(%WoodStock_V2_Task).tempo = 4 ' return a new pattern for the rhythm as soon as the actual one has been completed. (new bar): Iprop2Rit Task(App.GlobalHarmonyTasknr).Har, %WoodStock_V2_Task, 2 END IF tiks! = RitmSigma!(Task(%WoodStock_V2_Task).Rit) IF tiks! <= 0 THEN EXIT SUB ' het tempo voor een gehele maat is frq = task(tasknr%).tempo / 60 ' zo'n gehele maat beslaat een aantal eenheden gegeven in tiks! Task(%WoodStock_V2_Task).freq = (tiks! * Task(%WoodStock_V2_Task).tempo ) / (60 * ABS(Task(%WoodStock_V2_Task).Rit.pattern(Ritmeteller%))) IF Task(%WoodStock_V2_Task).Rit.pattern(Ritmeteller%) < 0 THEN ' this means we have to mPlay a rest... Task(%WoodStock_V2_Task).Har.vel = STRING$(128,0) ELSE ' now we have to find a new chord to mPlay for our task... IF Task(App.GlobalHarmonyTasknr).Har.vel <> STRING$(128, 0) THEN SELECT CASE Ritmeteller% MOD 4 CASE %False Task(%WoodStock_V2_Task).Har.vel = SolveHar$ (Task(App.GlobalHarmonyTasknr).Har, BYCOPY LastNotePlayed, 0.05) CASE %True Task(%WoodStock_V2_Task).Har.vel = InBetweenHar$(HarV2, Task(App.GlobalHarmonyTaskNr).Har) CASE 2 Task(%WoodStock_V2_Task).Har.vel = DiminuteHar$(HarV2,LastNotePlayed MOD 12,11,1) ' aug CASE 3 Task(%WoodStock_V2_Task).Har.vel = SymDimHar$(HarV2,LastNotePlayed MOD 12,-1) ' dim END SELECT ELSE Task(%WoodStock_V2_Task).Har.vel = STRING$(128,0) END IF END IF INCR Ritmeteller% IF Task(%WoodStock_V2_Task).Har.vel <> HarV2.vel THEN IF Task(%WoodStock_V2_Task).Har.vel <> Task(App.GlobalHarmonyTasknr).Har.vel THEN PlayHar Task(%WoodStock_V2_Task).Har, Task(%WoodStock_V2_Task).channel ' playhar keeps track of oldnotes internally... IF Task(%WoodStock_V2_Task).Har.vel <> STRING$(128,0) THEN HarV2.vel = Task(%WoodStock_V2_Task).Har.vel ' remember previous output. END IF END IF END IF END SUB SUB WoodStockPattern1 () EXPORT STATIC i% STATIC toets% STATIC Initpattern AS BYTE STATIC Melody() AS INTEGER STATIC stoptijd AS DWORD LOCAL j% IF ISFALSE Task(%Pattern1_Task).tog THEN IF (Task(%Pattern1_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB i% = %False toets% = %True IF ISFALSE Initpattern THEN DIM Melody (0 TO 12) ' 13 notes (14 in lickstick) FOR i = 0 TO UBOUND(Melody) Melody(i) = 52 '60 NEXT i Initpattern = %True END IF Task(%Pattern1_Task).tog = %True stoptijd = timeGetTime + 20000 ' 20 sec. max. END IF IF toets% THEN mPlay Task(%Pattern1_Task).channel, Melody(i%),WoodStock.vol OR 1 ' midi level depends on input level toets% = %False AddNote2Har Task(%Pattern1_Task).Har,Melody(i%), WoodStock.vol OR 1 ELSE NoteOff Task(%Pattern1_Task).channel, Melody(i%) toets% = %True Task(%Pattern1_Task).Har.vel = STRING$(128, 0) INCR i% IF i% > UBOUND(Melody) THEN i% = 0 j% = RND(1) * UBOUND(Melody) IF LastNotePlayed <> Melody(j%) THEN Melody(j%)= LastNotePlayed END IF IF timeGetTime > stoptijd THEN Task(%Pattern1_Task).tog = %False StopTask %Pattern1_Task END IF END IF ' tempo also depends on input density!: Task(%Pattern1_Task).freq = WoodStock.dens ' in events/sec (Hz) END SUB SUB WoodStockPattern2 () EXPORT STATIC i%, toets% STATIC Melody() AS INTEGER STATIC Initpattern AS BYTE STATIC stoptijd AS DWORD LOCAL j% IF ISFALSE Task(%Pattern2_Task).tog THEN IF (Task(%Pattern2_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB i% = 0 toets% = %NotFalse IF ISFALSE Initpattern THEN DIM Melody (0 TO 6) '7, 11 notes in lickstick FOR i = 0 TO UBOUND(Melody) Melody(i) = 65 '61 NEXT i InitPattern = %True END IF Task(%Pattern2_Task).tog = %True stoptijd = timeGettime + 16000 END IF IF toets% THEN mPlay Task(%Pattern2_Task).channel, Melody(i%), WoodStock.vol OR 1 toets% = %False AddNote2Har Task(%Pattern2_Task).Har,Melody(i%), WoodStock.Vol OR 1 ELSE mPlay Task(%Pattern2_Task).channel, Melody(i%), %False toets% = %NotFalse Task(%Pattern2_Task).Har.vel = STRING$(128, 0) INCR i% IF i% > UBOUND(Melody) THEN i% = 0 j% = RND(1) * UBOUND(Melody) IF LastNotePlayed <> Melody(j%) THEN Melody(j%)= LastNotePlayed ELSE Melody(j%) = LastNotePlayed - 12 IF Melody(j%) < 24 THEN Melody(j%) = 24 ' your never know... END IF END IF IF timeGetTime > stoptijd THEN Task(%Pattern2_Task).tog = %False StopTask %Pattern2_Task END IF END IF ' tempo also depends on input density!: Task(%Pattern2_Task).freq = (WoodStock.dens * 3 / 2) ' in events/sec (Hz) END SUB SUB WoodStockPattern3 () EXPORT STATIC i%, toets% STATIC Melody() AS INTEGER STATIC Initpattern AS BYTE STATIC stoptijd AS DWORD LOCAL j% IF ISFALSE Task(%Pattern3_Task).tog THEN IF (Task(%Pattern3_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB i% = 0 toets% = %NotFalse IF ISFALSE Initpattern THEN DIM Melody (0 TO 10) ' 11, in lickstick 7 notes FOR i = 0 TO UBOUND(Melody) Melody(i) = 78 '62 NEXT i Initpattern = %True END IF Task(%Pattern3_Task).tog = %True stoptijd = timeGetTime + 18000 ' 18 sec. END IF IF toets% THEN mPlay Task(%Pattern3_Task).channel, Melody(i%), WoodStock.vol OR 1 toets% = %False AddNote2Har Task(%Pattern3_Task).Har,Melody(i%), WoodStock.vol OR 1 ELSE mPlay Task(%Pattern3_Task).channel, Melody(i%), %False toets% = %NotFalse Task(%Pattern3_Task).Har.vel = STRING$(128, 0) INCR i% IF i% > UBOUND(Melody) THEN i% = 0 j% = RND(1) * UBOUND(Melody) IF LastNotePlayed <> Melody(j%) THEN Melody(j%)= LastNotePlayed END IF IF timeGetTime > stoptijd THEN Task(%Pattern3_Task).tog = %False StopTask %Pattern3_Task END IF END IF ' tempo also depends on input density!: Task(%Pattern3_Task).freq = (WoodStock.dens * 2 / 3) ' in events/sec (Hz) END SUB SUB WoodStockPatternAlgo (pattern AS BYTE) ' in this piece we recalculate patterns dynamically ' every time a pattern is recognized, it is extended with a single note value. ' pattern = Recog.nr + 1 ' recog.nr starts at 1 , whilst LBOUND(PatternSeq) = 0 LOCAL i AS LONG LOCAL noot AS INTEGER STATIC patduur4 AS SINGLE STATIC tog AS BYTE IF ISFALSE tog THEN patduur4 = PatternSeq(4).duur(0) + PatternSeq(4).duur(1) tog = %True END IF SELECT CASE pattern CASE 0 FOR i = 0 TO PatternSeq(pattern).lengte IF i > 0 THEN PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) + i PatternSeq(pattern).velo(i)= PatternSeq(pattern).velo(i-1) PatternSeq(pattern).duur(i)= PatternSeq(pattern).duur(i-1) END IF NEXT i IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) > Clarinet.Hightes THEN EXIT SUB ' end reached. IF PatternSeq(pattern).lengte < 14 THEN INCR PatternSeq(pattern).lengte END IF CASE 1 FOR i = 0 TO PatternSeq(pattern).lengte IF i > 0 THEN PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) - i PatternSeq(pattern).velo(i)= PatternSeq(pattern).velo(i-1) PatternSeq(pattern).duur(i)= PatternSeq(pattern).duur(i-1) END IF NEXT i IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) < Clarinet.LowTes THEN EXIT SUB ' end reached IF PatternSeq(pattern).lengte < 14 THEN INCR PatternSeq(pattern).lengte END IF CASE 2 FOR i = 0 TO PatternSeq(pattern).lengte IF i > 0 THEN IF BIT(i,0) THEN PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) - i ELSE PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) + i END IF PatternSeq(pattern).velo(i)= PatternSeq(pattern).velo(i-1) PatternSeq(pattern).duur(i)= PatternSeq(pattern).duur(i-1) END IF NEXT i IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) < Clarinet.LowTes THEN EXIT SUB ' end reached IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) > Clarinet.HighTes THEN EXIT SUB IF PatternSeq(pattern).lengte < 14 THEN INCR PatternSeq(pattern).lengte END IF CASE 3 FOR i = 0 TO PatternSeq(pattern).lengte IF i > 0 THEN IF BIT(i,0) THEN PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) + i ELSE PatternSeq(pattern).noot(i)= PatternSeq(pattern).noot(i-1) - i END IF PatternSeq(pattern).velo(i)= PatternSeq(pattern).velo(i-1) PatternSeq(pattern).duur(i)= PatternSeq(pattern).duur(i-1) END IF NEXT i IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) < Clarinet.LowTes THEN EXIT SUB ' end reached IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) > Clarinet.HighTes THEN EXIT SUB IF PatternSeq(pattern).lengte < 14 THEN INCR PatternSeq(pattern).lengte END IF CASE 4 ' mi - sol at start ' we add 1 whole tone up on each recognition - and shorten the durations ' first calculate the total duration now: ' patduur = 0 ' FOR i = 0 TO PatternSeq(4).lengte -1 ' patduur = patduur + PatternSeq(4).duur(i) ' bereken huidige totale tijdsduur ' NEXT i ' patduur = 2 'PatternSeq(4).duur(0) * PatternSeq(4).lengte -1 FOR i = 0 TO PatternSeq(4).lengte ' 27.02.2000 PatternSeq(4).duur(i) = patduur4 / PatternSeq(4).lengte NEXT i noot = GetDifferentPatternNote(PatternSeq(),4) IF noot >= Clarinet.LowTes THEN PatternSeq(4).noot(PatternSeq(4).lengte) = noot PatternSeq(4).velo(PatternSeq(4).lengte)= PatternSeq(4).velo(PatternSeq(4).lengte -1) ELSE PatternSeq(4).noot(PatternSeq(4).lengte)= PatternSeq(4).noot(PatternSeq(4).lengte -1) + 2 PatternSeq(4).velo(PatternSeq(4).lengte)= PatternSeq(4).velo(PatternSeq(4).lengte -1) END IF IF PatternSeq(4).noot(PatternSeq(4).lengte) < Clarinet.LowTes THEN EXIT SUB ' end reached IF PatternSeq(4).noot(PatternSeq(4).lengte) > Clarinet.HighTes THEN EXIT SUB IF PatternSeq(4).lengte < 14 THEN INCR PatternSeq(4).lengte ' so the last element is zero. END IF CASE 5 ' la at start - changes dynamically noot = GetDifferentPatternNote(PatternSeq(),5) IF noot >= Clarinet.LowTes THEN PatternSeq(5).noot(0) = noot END IF ' CASE 6 ' no change ' CASE 7 ' no change END SELECT DrawAllPatterns gh.MelPat END SUB FUNCTION WS_GetDifferentPatternNote (PatternSeq() AS PatternSequenceType, pattern AS BYTE) AS INTEGER ' we pass the pointer to the type such that -at a later moment- we may place ' this procedure in our dll. ' the pattern number passed is the destination pattern for the note, such that the proc. takes ' melodiousness into consideration. LOCAL H AS Harmtype LOCAL H2 AS HarmType LOCAL PatCnt AS LONG LOCAL i AS LONG H.vel = STRING$(128,0) H2.vel = STRING$(128,0) ' this function returns a note missing in the patterns as they are on the moment of the call. FOR patCnt = 0 TO UBOUND(PatternSeq) FOR i = 0 TO PatternSeq(patCnt).lengte IF PatternSeq(patCnt).velo(i) > 0 THEN AddNote2Har H, PatternSeq(patCnt).noot(i), PatternSeq(patCnt).velo(i) END IF NEXT i NEXT patCnt H2.vel = ComplementHar$ (H,Clarinet.lowtes, Clarinet.hightes) ' returns the notes not present in ' the Har$ passed. FUNCTION = StealNoteFromHar(H2, PatternSeq(pattern).noot(PatternSeq(pattern).lengte-1), Clarinet.lowtes, Clarinet.hightes) END FUNCTION SUB WoodStockPlaySample () ' this task plays the prerecorded wave files on disk. ' This task has very specific WoodStock code, since we use a large set of changing sample-files. STATIC Jumpval AS BYTE STATIC CatIdx1 AS BYTE STATIC CatIdx2 AS BYTE STATIC CatIdx3 AS BYTE STATIC CatIdx4 AS BYTE STATIC CatIdx5 AS BYTE STATIC CatIdx6 AS BYTE STATIC CatIdx7 AS BYTE STATIC CatIdx8 AS BYTE LOCAL Filnam AS ASCIIZ * 40 LOCAL retval AS LONG STATIC tracknr AS LONG STATIC duur AS DWORD IF ISFALSE Task(%AudioPlaySample_Task).tog THEN IF (Task(%AudioPlaySample_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB IF ISFALSE Audio.hWo THEN Stoptask %AudioPlaySample_Task EXIT SUB END IF Task(%AudioPlaySample_Task).tog = %True Jumpval = %False ' calculate the filename for the sample to be played...: SELECT CASE Recog.nr CASE 1 ' detunes Filnam = "WS0" & TRIM$(STR$(CatIdx1)) & ".WAV" 'INCR CatIdx1 'IF CatIdx1 > 2 THEN CatIdx1 = 0 CASE 2 Filnam = "WS1" & TRIM$(STR$(CatIdx2)) & ".WAV" 'INCR CatIdx2 'IF CatIdx2 > 10 THEN CatIdx2 = 0 CASE 3 Filnam = "WS2" & TRIM$(STR$(CatIdx3)) & ".WAV" 'INCR CatIdx3 'IF CatIdx3 > 7 THEN CatIdx3 = 0 CASE 4 Filnam = "WS3" & TRIM$(STR$(CatIdx4)) & ".WAV" 'INCR CatIdx4 'IF CatIdx4 > 17 THEN CatIdx4 = 0 CASE 5 Filnam = "WS4" & TRIM$(STR$(CatIdx5)) & ".WAV" 'INCR CatIdx5 'IF CatIdx5 > 4 THEN CatIdx5 = 0 CASE 6 Filnam = "WS5" & TRIM$(STR$(CatIdx6)) & ".WAV" 'INCR CatIdx6 'IF CatIdx6 > 3 THEN CatIdx6 = 0 CASE 7 Filnam = "WS6" & TRIM$(STR$(CatIdx7)) & ".WAV" 'INCR CatIdx7 'IF CatIdx7 > 4 THEN CatIdx7 = 0 CASE 8 Filnam = "WS7" & TRIM$(STR$(CatIdx8)) & ".WAV" 'INCR CatIdx8 'IF CatIdx8 > 15 THEN CatIdx8 = 0 END SELECT Filnam = ".\WoodSt~1\" + TRIM$(LCASE$(Filnam)) + CHR$(0) ' here we check for the existence of these files... IF ISFALSE Existfile(UCASE$(Filnam)) THEN StopTask %AudioPlaySample_Task EXIT SUB END IF ' sofar we know that the file exists... ' so, lets try loading it into a free track: END IF SELECT CASE Jumpval CASE %False retval = PlayWaveFile (Filnam, %MODULATE_VOLUME OR %MODULATE_PANNING) SELECT CASE retval CASE > 15 ' means we played the file without using the waveouthandle. StopTask %AudioPlaySample_Task EXIT SUB CASE 0 TO 15 ' bereken de duur van het te spelen sample... tracknr = retval duur = TrackDuration(Tracknr) ' in milliseconds Jumpval = %True Task(%AudioPlaySample_Task).freq = 1000 / duur EXIT SUB CASE -2 ' no need to try again... StopTask %AudioPlaySample_Task EXIT SUB CASE -1 ' wait until device becomes available... Jumpval = %False Task(%AudioPlaySample_Task).freq = 5 EXIT SUB END SELECT CASE %True IF TrackStatus.playing(tracknr) THEN Task(%AudioPlaySample_Task).freq = 36 EXIT SUB END IF ' now we can stop the task and free its resources: Task(%AudioPlaySample_Task).tog = %False Task(%AudioPlaySample_Task).freq = 20 StopTask %AudioPlaySample_Task END SELECT END SUB SUB WoodStockRingModulator () STATIC Jumpval AS BYTE STATIC effdone AS BYTE STATIC Track AS LONG STATIC duur AS DWORD ' in milliseconds LOCAL LastRecordedFileName AS ASCIIZ * 40 LOCAL retval AS LONG LOCAL freqL AS SINGLE LOCAL freqR AS SINGLE IF ISFALSE Task(%LS_RingModulator_Task).tog THEN IF (Task(%LS_RingModulator_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB IF ISFALSE Audio.hWo THEN Stoptask %LS_RingModulator_Task : EXIT SUB Task(%LS_RingModulator_Task).tog = %True Jumpval = %False effdone = %False track = -1 CheckAudio Audio, App LastRecordedFileName = "GMT_" + LTrimZero(HEX$(Audio.iCnt-1)) + ".WAV" + CHR$(0) IF ISFALSE Existfile(UCASE$(LastRecordedFileName)) THEN StopTask %LS_RingModulator_Task EXIT SUB END IF END IF SELECT CASE Jumpval CASE %False ' get a free audio-track and fill it with the file audio data: Track = ReadWaveData (LastRecordedFileName) IF Track > -1 THEN Jumpval = %True ' bereken de duur van het te spelen sample... duur = Trackduration(Track) ' in milliseconds IF duur = %False THEN MSGBOX "[RingModulator] ZERO-error on track duration" SizeAudioTrack Track, %False StopTask %LS_RingModulator_Task END IF IF ISFALSE effdone THEN freqL = N2F%(INT(LastNotePlayed)) ' input dependent molulation frequency freqR = freqL / 3 freqL = freqL / 2 RingModulate WavHdr(Track),INT(freqR), INT(freqL) ' dll DeglitchStart WavHdr(Track) ' dll DeglitchTail WavHdr(Track) ' dll effdone = %True ' set o.k. END IF ELSE Jumpval = %False EXIT SUB END IF END SELECT SELECT CASE JumpVal CASE %False EXIT SUB CASE %True retval = PlayAudioTrack (Track, %Null) SELECT CASE retval CASE Track Task(%LS_RingModulator_Task).freq = 1000 / duur effdone = %False Jumpval = 2 EXIT SUB CASE -1 Task(%LS_RingModulator_Task).freq = 1 Jumpval = %True ' try again effdone = %True ' exit and wait until device becomes available: EXIT SUB CASE ELSE ' fatal error. effdone = %False Jumpval = %False ' release the track! SizeAudioTrack Track, %False Stoptask %LS_RingModulator_Task END SELECT CASE 2 IF TrackStatus.playing(track) THEN ' track still playing Task(%LS_RingModulator_Task).freq = 33 EXIT SUB END IF ' now we can stop the task and free its resources: Task(%LS_RingModulator_Task).tog = %False Task(%LS_RingModulator_Task).freq = 20 effdone = %False Jumpval = %False StopTask %LS_RingModulator_Task END SELECT END SUB SUB WoodStockPitchShift () ' split off from audioprocess task 07.03.2000 STATIC Jumpval AS BYTE LOCAL LastRecordedFileName AS ASCIIZ * 40 LOCAL freq AS SINGLE STATIC Track AS LONG STATIC Track2 AS LONG LOCAL duur AS DWORD LOCAL retval AS LONG IF ISFALSE Task(%LS_PitchShift_Task).tog THEN IF (Task(%LS_PitchShift_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB CheckAudio Audio, App IF ISFALSE Audio.hWo THEN Stoptask %LS_PitchShift_Task : EXIT SUB LastRecordedFileName = "GMT_" + LTrimZero(HEX$(Audio.iCnt-1)) + ".WAV" + CHR$(0) IF ISFALSE Existfile(UCASE$(LastRecordedFileName)) THEN StopTask %LS_PitchShift_Task: EXIT SUB Task(%LS_PitchShift_Task).tog = %True Jumpval = %False END IF SELECT CASE Jumpval CASE %False ' get a free audio-track and fill it with the file audio data: Track = ReadWaveData (LastRecordedFileName) SELECT CASE Track CASE -2 ' fatal error StopTask %LS_PitchShift_Task EXIT SUB CASE -1 ' try again later... Jumpval = %False EXIT SUB CASE 0 TO 15 ' bereken de duur van het te spelen sample... duur = Trackduration (Track) Track2 = GetFreeAudioTrack IF Track2 > -1 THEN IF WoodStock.tes > %False THEN retval = SizeAudioTrack (Track2,duur * (La/WoodStock.tes)) Varispeed WavHdr(Track), WavHdr(Track2) ' o.k. works fine. duur = Trackduration (Track2) DeglitchStart WavHdr(Track2) retval = PlayAudioTrack (Track2, %Null) IF retval = Track2 THEN Task(%LS_PitchShift_Task).freq = 1000 / duur ' release original track: SizeAudioTrack Track, %False ELSE ' stoptask... ' release tracks!!! SizeAudioTrack Track, %False SizeAudioTrack Track2, %False StopTask %LS_PitchShift_Task EXIT SUB END IF ELSE MSGBOX "Error: WoodStock.tes parameter not set! [pitchshift-task]" ' stoptask... ' release tracks!!! SizeAudioTrack Track, %False SizeAudioTrack Track2, %False StopTask %LS_PitchShift_Task EXIT SUB END IF ELSE Jumpval = %False EXIT SUB END IF END SELECT Jumpval = %True CASE %True IF TrackStatus.Playing(track2) THEN ' this means the task is still playing the sample... Task(%LS_PitchShift_Task).freq = 40 EXIT SUB ELSE ' now we can stop the task and free its resources: Jumpval = %False Task(%LS_PitchShift_Task).tog = %False Task(%LS_PitchShift_Task).freq = 20 StopTask %LS_PitchShift_Task EXIT SUB END IF END SELECT END SUB SUB WoodStockDelayInvertFast () ' This delay plays at always increasing speed. ' All intervals are inverted. ' The mirror note for the inversion depends on ' the momentaneous note played by the Clarinet. LOCAL nv% LOCAL noot? LOCAL velo? STATIC delaytime AS DWORD STATIC SPEED AS SINGLE IF ISFALSE Task(%InvFast_Task).tog THEN IF (Task(%InvFast_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB nv% = GetPromil% IF nv% <= %False THEN StopTask %InvFast_Task EXIT SUB END IF Task(%InvFast_Task).tog = %True delaytime = nv% * App.Komposduur SPEED = 1.3! * (1! + (SPEED/10!)) ' 1.5 = double speed - this goes accellerando! ' the value changes for each new call to the task. END IF nv% = ReadDelayLine%(%InvFast_Task, delaytime, SPEED) SELECT CASE nv% CASE %False, %NotFalse EXIT SUB ' if no note came in, exit the task CASE -2 ' read past present. Task(%InvFast_Task).Har.vel = STRING$(128,0) PlayHar Task(%InvFast_Task).Har, Task(%InvFast_Task).channel nv% = ReadDelayLine%(%InvFast_Task, 0, 0) ' force a reset Task(%InvFast_Task).tog = %False ' force calculation of a new delay time StopTask %InvFast_Task ' stop the task. EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) noot? = LastNotePlayed + LastNotePlayed - noot? IF noot? > 127 THEN EXIT SUB IF noot? <=0 THEN EXIT SUB Task(%InvFast_Task).Har.vel = STRING$(128,0) ' monophonic IF velo? THEN AddNote2Har Task(%InvFast_Task).Har, (noot?),(velo?) PlayHar Task(%InvFast_Task).Har , Task(%InvFast_Task).channel END SUB SUB WoodStockDelayBackInvert () ' plays backwards with inverted intervals LOCAL nv% LOCAL noot? LOCAL velo? STATIC delaytime AS DWORD STATIC SPEED AS SINGLE IF ISFALSE Task(%BackInv_Task).tog THEN IF (Task(%BackInv_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB nv% = GetPromil% ' nv just used to save another variable... IF nv% <= %False THEN StopTask %BackInv_Task EXIT SUB END IF Task(%BackInv_Task).tog = %True delaytime = nv% * App.Komposduur SPEED = 1.3! * (1! + (ABS(SPEED)/10!)) ' 1.5 = double speed - this goes accellerando! ' the value changes for each new call to the task. SPEED = - SPEED END IF nv% = ReadDelayLine%(%BackInv_Task, delaytime, SPEED) ' speed is negative, so we mPlay backwards SELECT CASE nv% CASE %False, %NotFalse, -2 EXIT SUB ' if no note came in, exit the task CASE -3 ' read past delay in backwardsmode: force reset, stop task. Task(%BackInv_Task).Har.vel = STRING$(128,0) PlayHar Task(%BackInv_Task).Har, Task(%BackInv_Task).channel ' notes off nv% = ReadDelayLine%(%BackInv_Task, 0, 0) ' force a reset Task(%BackInv_Task).tog = %False ' force calculation of a new delay time StopTask %BackInv_Task ' stop the task. EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) noot? = LastNotePlayed + LastNotePlayed - noot? ' we mirror/invert the intervals IF noot? > 127 THEN EXIT SUB IF noot? <=0 THEN EXIT SUB Task(%BackInv_Task).Har.vel = STRING$(128,0) ' monophonic IF velo? THEN AddNote2Har Task(%BackInv_Task).Har, (noot?),(velo?) PlayHar Task(%BackInv_Task).Har , Task(%BackInv_Task).channel END SUB SUB WoodStockDelayBackSlow () ' plays backwards at decreasing lower speed ' This task does not always stop before the end of the piece, if not stopped by an interactive event. LOCAL nv% LOCAL noot? LOCAL velo? STATIC delaytime AS DWORD ' in ms STATIC COUNT AS DWORD STATIC SPEED AS SINGLE IF ISFALSE Task(%BackSlow_Task).tog THEN IF (Task(%BackSlow_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB nv% = GetPromil% ' nv just used to save another variable... IF nv% <= %False THEN StopTask %BackSlow_Task EXIT SUB END IF Task(%BackSlow_Task).tog = %True delaytime = 500 'keep it constant to 500ms instead of doing delaytime = nv% * App.Komposduur INCR COUNT SPEED = -(1 -COUNT/Pi) 'slower & negative ' TO BE CHECKED!!!!!!!!!!!!!!!!! ' -0.68169 , -0.3633, -0.045 IF SPEED < -0.045 THEN SPEED = -0.045 ' the value changes for each new call to the task. END IF nv% = ReadDelayLine%(%BackSlow_Task, delaytime, SPEED) ' speed is negative, so we mPlay backwards SELECT CASE nv% CASE %False, %NotFalse, -2 EXIT SUB ' if no note came in, exit the task CASE -3 ' read past delay in backwardsmode: force reset, stop task. cannot happen... Task(%BackSlow_Task).Har.vel = STRING$(128,0) PlayHar Task(%BackSlow_Task).Har, Task(%BackSlow_Task).channel ' notes off nv% = ReadDelayLine%(%BackSlow_Task, 0, 0) ' force a reset Task(%BackSlow_Task).tog = %False ' force calculation of a new delay time StopTask %BackSlow_Task ' stop the task. EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) - 12 ' octave down ' no inversion of intervals. IF noot? > 127 THEN EXIT SUB IF noot? <= 0 THEN EXIT SUB Task(%BackSlow_Task).Har.vel = STRING$(128,0) ' monophonic IF velo? THEN AddNote2Har Task(%BackSlow_Task).Har, (noot?),(velo?) PlayHar Task(%BackSlow_Task).Har , Task(%BackSlow_Task).channel END SUB SUB WoodStockDelayPlayerNormal () ' this taskprocedure demonstrates how to build a delay-line for ' midi input. This one outputs at normal speed. LOCAL nv% LOCAL noot? LOCAL velo? IF ISFALSE Task(%Gerade_Task).tog THEN IF (Task(%Gerade_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%Gerade_Task).tog = %True END IF nv% = ReadDelayLine%(%Gerade_Task, 5000, 1!) ' 5 second delay ' > 1 speed-up ' < 1 slow down SELECT CASE nv% CASE %False EXIT SUB CASE %NotFalse EXIT SUB ' if no note came in, exit the task CASE -2 ' read past present. ' This can only happen if speed! > 1! nv% = ReadDelayLine%(%Gerade_Task, 0, 0) ' force a reset StopTask %Gerade_Task ' switch task off on error. EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) - 24 IF noot? <= %False THEN velo? = %False : Noot? = %False ' lets implement full polyphonic playing: IF velo? = %False THEN DelNote2Har Task(%Gerade_Task).Har, (noot?) PlayHar Task(%Gerade_Task).Har, Task(%Gerade_Task).channel ELSE DelNote2Har Task(%Gerade_Task).Har, (noot) PlayHar Task(%Gerade_Task).Har, Task(%Gerade_Task).channel AddNote2Har Task(%Gerade_Task).Har, (noot?), (velo?) PlayHar Task(%Gerade_Task).Har , Task(%Gerade_Task).channel END IF END SUB '[EOF] _ _