' ************************************************* ' * * ' * for recorder and interactive electronics * ' * 1999/2000 * ' * Godfried-Willem RAES * ' * A composition commissioned by * ' * Tomma Wessel * ' ************************************************* ' 16.10.1999: coding started ' 31.01.2000: waves recorded. ' 01.01.2000: decision: input sections must be played on the tenorrecorder. ' 04.02.2000: wave functions revised. Need a queued waveplayer task. ' 15.02.2000: callback timer lib. implemented ' 22.02.2000: midi delaylines added ' 26.02.2000: cleanup - score manual in html written ' 29.02.2000: minor changes. ' 01.03.2000: Stick1 & Stick2 added: manual for now. ' 04.03.2000: some deglitching added after premiere of this piece on 03.03.2000 ' by Tomma Wessel & Geert Logghe ' 06.03.2000: restructured with all wave procs in the dll. ' 07.06.2000: common procs. placed in gmt_gwr.bas - pitch shift procedure isolated. ' code improvements also applied to ' 22.03.2000: Ported to G Version 5.00 ' 12.04.2000: recompiled for version 5.05 ' 21.04.2000: recompiled for version 5.09 ' 04.05.2000: button code modified. ' 05.12.2000: solving crash conditions on Miel and Putty... Version 5.20 ' 29.07.2001: minor changes to accomodate , ported to GMT version 5.40 ' 02.09.2001: GetLastNote procedure moved to gmt_gwr.inc ' 11.06.2002: Ported to GMT version 5.82 ' 26.06.2002: recompiled under PBWIN7.0 ' 27.03.2005: adapted to PBWIN8.0 ' 03.10.2006: adapted to new path's for audiofiles %LickStick_Score_Task = 17 %LickStick_V1_Task = 25 ' Stimme 1 %LickStick_V2_Task = 26 ' Stimme 2 #IF NOT %DEF(%Pattern1_Task) %Pattern1_Task = 28 ' Formel 1 %Pattern2_Task = 29 ' Formel 2 %Pattern3_Task = 30 ' Formel 3 #ENDIF %RecoDetune_Task = 32 ' delay line 1 ' as in cellopi: %InvFast_Task = 33 ' midi delay line players %BackInv_Task = 34 %BackSlow_Task = 35 %Gerade_Task = 36 %LS_RingModulator_Task = %AudioRingModulator_Task ' =53 specific for LickStick %LS_PitchShift_Task = %AudioVarspeed_Task ' =56 split off from %AudioProcess Task 07.03.2000 GLOBAL TenRec AS MUSICIAN DECLARE FUNCTION InitLickStick () AS LONG DECLARE SUB LickStickInitSynth () DECLARE SUB ButnSW_LickStickStartStop () DECLARE SUB LickStickScore() DECLARE SUB RecoListen () ' midi input listering task DECLARE SUB LickStickPatternAlgo (pattern AS BYTE) ' input score calculation DECLARE SUB SetRecorderContext (noot?, velo?) ' as in cellopi DECLARE SUB LickStickDoEvent () ' interactive score DECLARE SUB LickStickPattern1 () ' Formel 1 DECLARE SUB LickStickPattern2 () ' Formel 2 DECLARE SUB LickStickPattern3 () ' Formel 3 DECLARE SUB Stock1 () ' stimme1 / voice1 / stick1 DECLARE SUB Stock2 () ' audio tasks DECLARE SUB LickStickPitchShift () ' speeds up/down recorded sample DECLARE SUB LickStickPlaySample () ' plays prerecorded samples from disk - LickStickSpecific DECLARE SUB LickStickRingModulator () ' midi delaylines: DECLARE SUB RecoDetune() DECLARE SUB LickStickDelayInvertFast () DECLARE SUB LickStickDelayBackInvert () DECLARE SUB LickStickDelayBackSlow () DECLARE SUB LickStickDelayPlayerNormal () ' generalizable: DECLARE FUNCTION GetDifferentPatternNote (PatternSeq() AS PatternSequenceType, pattern AS BYTE) AS INTEGER '------------------------------------------------------------------- FUNCTION InitLickStick () 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 $LICKSTICKINI, Meq() Update_MidiEquipment Meq() ReadPatternRecognitionDataFile $LICKSTICKINI ReadSynthConfigFile $LICKSTICKINI, Meq() ' should know the Meq() selected!!! ' ReadFaderParams $LICKSTICKINI, AudioFader() ReadCockpitLabelsFromFile $LICKSTICKINI, CockpitLayo Recording_Available = %False ' false on init. - global variable GetInstrumentParams TenRec, %ID_RECORDER_TEN Tenrec.minvel = 6 ' new 29.02.2000 - placed here 29.07.01 TenRec.channel = 0 ' midi input listening channel TenRec.patch = 131 Recog.Cptr = CODEPTR(LickStickDoEvent) ' input recognition callback ButnSW(1).tag0 = "START" ' start/stop toggle ButnSW(1).tag1 = "STOP" ButnSW(1).cptr = CODEPTR(ButnSW_LickStickStartStop) ' 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 = "Hören" Task(%Listen_Task).freq = 30 Task(%Listen_Task).channel = TenRec.channel Task(%Listen_Task).cptr = CODEPTR(RecoListen) Task(%Listen_Task).starttime = 0 Task(%Listen_Task).stoptime = 1000 Task(%Listen_Task).Rit.minduur = TenRec.minduur/1000 ' in ms Task(%Listen_Task).Rit.maxduur = TenRec.maxduur/1000 Task(%Listen_Task).flags = Task(%Listen_Task).flags OR %MIDI_TASK OR %HARM_TASK OR %SCORE_TASK Task(%LickStick_Score_Task).naam = "Ablauf" ' for automatic playing - scheduler Task(%LickStick_Score_Task).freq = 1 Task(%LickStick_Score_Task).tempo = 60 Task(%LickStick_Score_Task).cptr = CODEPTR(LickStickScore) Task(%LickStick_V1_Task).naam = "Stock 1" ' vertical harmony stimme 1 Task(%LickStick_V1_Task).cptr = CODEPTR(Stock1) Task(%LickStick_V1_Task).freq = 1 Task(%LickStick_V1_Task).tempo = 20 Task(%LickStick_V1_Task).flags = Task(%LickStick_V1_Task).flags OR %MIDI_TASK OR %SCORE_TASK Task(%LickStick_V2_Task).naam = "Stock 2" ' vertical harmony stimme 2 Task(%LickStick_V2_Task).cptr = CODEPTR(Stock2) Task(%LickStick_V2_Task).freq = 1 Task(%LickStick_V2_Task).tempo = 20 Task(%LIckStick_V2_Task).flags = Task(%LickStick_V2_Task).flags OR %MIDI_TASK OR %SCORE_TASK Task(%Pattern1_Task).naam = "Formel 1" Task(%Pattern1_Task).freq = 20 Task(%Pattern1_Task).tempo = 60 Task(%Pattern1_Task).cptr = CODEPTR(LickStickPattern1) 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 = "Formel 2" Task(%Pattern2_Task).freq = 30 Task(%Pattern2_Task).tempo = 61 Task(%Pattern2_Task).cptr = CODEPTR(LickStickPattern2) 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 = "Formel 3" Task(%Pattern3_Task).freq = 16 Task(%Pattern3_Task).tempo = 62 Task(%Pattern3_Task).cptr = CODEPTR(LickStickPattern3) 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(%RecoDetune_Task).naam = "Falsch" Task(%RecoDetune_Task).freq = 24 Task(%RecoDetune_Task).cptr = CODEPTR(RecoDetune) Task(%RecoDetune_Task).Rit.minduur = 0.035 ' in s Task(%RecoDetune_Task).Rit.maxduur = 5.000 ' in s Task(%RecoDeTune_Task).flags = Task(%RecoDetune_Task).flags OR %MIDI_TASK Task(%InvFast_Task).naam = "UmRasch" Task(%InvFast_Task).freq = 60 Task(%InvFast_Task).cptr = CODEPTR(LickStickDelayInvertFast) 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 = "UmKrebs" Task(%BackInv_Task).freq = 58 Task(%BackInv_Task).cptr = CODEPTR(LickStickDelayBackInvert) 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 = "LanKrebs" Task(%BackSlow_Task).freq = 31 Task(%BackSlow_Task).cptr = CODEPTR(LickStickDelayBackSlow) 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 = "Gerade" Task(%Gerade_Task).freq = 35 Task(%Gerade_Task).cptr = CODEPTR(LickStickDelayPlayerNormal) 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(LickStickPlaySample) ' - specific code for LickStick 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(LickStickRingModulator) 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(LickStickPitchShift) Task(%LS_PitchShift_Task).freq = 8 ' nr = ReadAudioDataFromFile ($LICKSTICKINI, 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 LickStickInitSynth LastNotePlayed = 62 '74 for soprano recorder. ' 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 = " Partitur" SendMessage gh.MelPat, %WM_SETTEXT,0, VARPTR(m) FUNCTION = %True END FUNCTION SUB LickStickInitSynth () 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 LickStickDoEvent () ' 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 lickstick. DrawAllPatterns gh.MelPat ' experiment SELECT CASE Recog.nr CASE 1 ' samples: detunes IF Task(%RecoDetune_Task).swit THEN StartTask %RecoDetune_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 %RecoDetune_Task ReadDelayLine% %RecoDeTune_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 LickStickPatternAlgo 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 LickStickPatternAlgo 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 'LickStickDelayBackSlow ELSE StopTask %BackSlow_Task ReadDelayLine% %BackSlow_Task, 0, 0 ' force a reset END IF END IF LickStickPatternAlgo 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 LickStickPatternAlgo 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 LickStickPatternAlgo 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 LickStickPatternAlgo 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 RecoListen () 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? >= TenRec.lowtes) AND (noot? <= TenRec.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 , TenRec ' sets/updates the global var LastNotePlayed END IF ' adjust for weird dynamic scale of recorders... SELECT CASE noot? CASE <= 62 Xlatv = velo? * 6.8 CASE 63 Xlatv = velo? * 5.6 CASE 64 Xlatv = velo? * 4.7 CASE 65 Xlatv = velo? * 3.9 CASE 66 Xlatv = velo? * 3.3 CASE 67 Xlatv = velo? * 2.7 CASE 68 Xlatv = velo? * 2.2 CASE 69 Xlatv = velo? * 1.8 CASE 70 Xlatv = velo? * 1.5 CASE 71 Xlatv = velo? * 1.2 CASE ELSE Xlatv = velo? END SELECT IF Xlatv > 127 THEN velo? = 127 ELSE velo? = Xlatv AddNote2Har Task(%Listen_Task).Har, (noot?), (velo?) WriteDelayLine noot?, velo? GetLastNote noot?, velo?, TenRec oldnote% = noot? ELSE ' if note off... WriteDelayLine noot?, 0 GetLastNote noot?, 0, TenRec 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 SetRecorderContext noot?, velo? ' following should become part of a monitoring task... SetDlgItemText gh.Cockpit, %GMT_TEXT_TES, STR$(INT(LickStick.tes)) SetDlgItemText gh.Cockpit, %GMT_MSG1, "V=" & STR$(LickStick.vol) & " d=" & FORMAT$(LickStick.dens,"##.#") END IF END SUB SUB RecoDetune () 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(%RecoDetune_task).tog THEN IF (Task(%RecoDeTune_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%RecoDetune_task).tog = %True END IF nv% = ReadDelayLine%(%RecoDetune_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%(%RecoDetune_Task, 0, 0) ' force a reset AllNotesOff Task(%RecoDetune_Task).channel StopTask %RecoDetune_Task Task(%RecoDetune_task).tog = %False EXIT SUB END SELECT velo? = LOBYT (nv%) noot? = HIBYT (nv%) IF velo? THEN AllNotesOff Task(%RecoDetune_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(%RecoDetune_Task).channel, detunednote!, velo? ELSE AllNotesOff Task(%RecoDetune_Task).channel END IF END SUB SUB LickStickScore() EXPORT STATIC msduration AS DWORD ' scoring task. IF ISFALSE Task(%LickStick_Score_Task).tog THEN IF (Task(%LickStick_Score_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%LickStick_Score_Task).tog = %True msduration = App.komposduur * 1000 ' convert to milliseconds Task(%LickStick_Score_Task).freq = 1 END IF IF Getpromil% < 0 THEN EXIT SUB 'Normprop = (tnow - tstart)/ msduration LickStick.Angle = ((timeGetTime - App.tstart) * Pi2)/ msduration ' 0 to Pi2 (radians) IF LickStick.Angle > Pi2 THEN LickStick.Angle = Lickstick.Angle - Pi2 ' circles ' here we should add all code for linear scoring (if any...) ' If Getpromil% < 10 END SUB SUB ButnSW_LickStickStartStop () 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.MTSpeedTaskNr ' optional ' StartTask App.RunTimeTaskNr Runtime %True StartTask %Listen_Task StartTask %LickStick_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 SetRecorderContext (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 LickStick.vol = 24 ' midi level LickStick.tes = 440 ' in Hz LickStick.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 IF velo? THEN LickStick.Vol = LickStick.Vol + LickStick.Vol + LickStick.Vol + velo? SHIFT RIGHT LickStick.Vol, 2 END IF ' ' bereken de gemiddelde tessituurligging van de input IF noot? THEN LickStick.tes = ((LickStick.tes * 3) + N2F(noot?)) / 4 END IF ' calculate the density of the input over a timeframe of 255cs. ' The result is returned in LickStick.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 LickStick.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 Stock1 () EXPORT STATIC Ritmeteller% STATIC HarV1 AS HarmType STATIC starttempo AS SINGLE LOCAL tiks! IF ISFALSE Task(%LickStick_V1_Task).tog THEN IF (Task(%LickStick_V1_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%LickStick_V1_Task).tog = %True HarV1.vel = STRING$(128,0) starttempo = Task(%LickStick_V1_Task).tempo ' should be dependent on input tempo! END IF ' This procedure is polyphonic. IF Task(%LickStick_V1_Task).Rit.pattern(Ritmeteller%) = 0 THEN Ritmeteller% = 0 ' get new parameters: Task(%LickStick_V1_Task).tempo = LickStick.dens / 8 IF Task(%LickStick_V1_Task).tempo < 5 THEN Task(%LickStick_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, %LickStick_V1_Task, 3 END IF tiks! = RitmSigma!(Task(%LickStick_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(%LickStick_V1_Task).freq = (tiks! * Task(%LickStick_V1_Task).tempo ) / (60 * ABS(Task(%LickStick_V1_Task).Rit.pattern(Ritmeteller%))) IF Task(%LickStick_V1_Task).Rit.pattern(Ritmeteller%) < 0 THEN ' this means we have to mPlay a rest... Task(%LickStick_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(%LickStick_V1_Task).Har.vel = SolveHar$ (Task(App.GlobalHarmonyTasknr).Har, BYCOPY LastNotePlayed, 0.05) CASE %True Task(%LickStick_V1_Task).Har.vel = InBetweenHar$(HarV1, Task(App.GlobalHarmonyTaskNr).Har) CASE 2 Task(%LickStick_V1_Task).Har.vel = DiminuteHar$(HarV1,LastNotePlayed MOD 12,11,1) ' aug END SELECT ELSE Task(%LickStick_V1_Task).Har.vel = STRING$(128,0) END IF END IF INCR Ritmeteller% IF Task(%LickStick_V1_Task).Har.vel <> HarV1.vel THEN IF Task(%LickStick_V1_Task).Har.vel <> Task(App.GlobalHarmonyTasknr).Har.vel THEN PlayHar Task(%LickStick_V1_Task).Har, Task(%LickStick_V1_Task).channel ' playhar keeps track of oldnotes internally... IF Task(%LickStick_V1_Task).Har.vel <> STRING$(128,0) THEN HarV1.vel = Task(%LickStick_V1_Task).Har.vel ' remember previous output. END IF END IF END IF END SUB SUB Stock2 () EXPORT STATIC Ritmeteller% STATIC HarV2 AS HarmType STATIC starttempo AS SINGLE LOCAL tiks! IF ISFALSE Task(%LickStick_V2_Task).tog THEN IF (Task(%LickStick_V2_Task).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB Task(%LickStick_V2_Task).tog = %True HarV2.vel = STRING$(128,0) starttempo = Task(%LickStick_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(%LickStick_V2_Task).Rit.pattern(Ritmeteller%) = 0 THEN Ritmeteller% = 0 ' get new parameters: Task(%LickStick_V2_Task).tempo = LickStick.dens / 8 IF Task(%LickStick_V2_Task).tempo < 4 THEN Task(%LickStick_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, %LickStick_V2_Task, 2 END IF tiks! = RitmSigma!(Task(%LickStick_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(%LickStick_V2_Task).freq = (tiks! * Task(%LickStick_V2_Task).tempo ) / (60 * ABS(Task(%LickStick_V2_Task).Rit.pattern(Ritmeteller%))) IF Task(%LickStick_V2_Task).Rit.pattern(Ritmeteller%) < 0 THEN ' this means we have to mPlay a rest... Task(%LickStick_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(%LickStick_V2_Task).Har.vel = SolveHar$ (Task(App.GlobalHarmonyTasknr).Har, BYCOPY LastNotePlayed, 0.05) CASE %True Task(%LickStick_V2_Task).Har.vel = InBetweenHar$(HarV2, Task(App.GlobalHarmonyTaskNr).Har) CASE 2 Task(%LickStick_V2_Task).Har.vel = DiminuteHar$(HarV2,LastNotePlayed MOD 12,11,1) ' aug CASE 3 Task(%LickStick_V2_Task).Har.vel = SymDimHar$(HarV2,LastNotePlayed MOD 12,-1) ' dim END SELECT ELSE Task(%LickStick_V2_Task).Har.vel = STRING$(128,0) END IF END IF INCR Ritmeteller% IF Task(%LickStick_V2_Task).Har.vel <> HarV2.vel THEN IF Task(%LickStick_V2_Task).Har.vel <> Task(App.GlobalHarmonyTasknr).Har.vel THEN PlayHar Task(%LickStick_V2_Task).Har, Task(%LickStick_V2_Task).channel ' playhar keeps track of oldnotes internally... IF Task(%LickStick_V2_Task).Har.vel <> STRING$(128,0) THEN HarV2.vel = Task(%LickStick_V2_Task).Har.vel ' remember previous output. END IF END IF END IF END SUB SUB LickStickPattern1 () 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 13) ' 14 notes FOR i = 0 TO UBOUND(Melody) Melody(i) = 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%),LickStick.vol OR 1 ' midi level depends on input level toets% = %False AddNote2Har Task(%Pattern1_Task).Har,Melody(i%), LickStick.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 = LickStick.dens ' in events/sec (Hz) END SUB SUB LickStickPattern2 () 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 10) ' 21 notes FOR i = 0 TO UBOUND(Melody) Melody(i) = 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%), LickStick.vol OR 1 toets% = %False AddNote2Har Task(%Pattern2_Task).Har,Melody(i%), LickStick.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 = (LickStick.dens * 3 / 2) ' in events/sec (Hz) END SUB SUB LickStickPattern3 () 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 6) ' 7 notes FOR i = 0 TO UBOUND(Melody) Melody(i) = 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%), LickStick.vol OR 1 toets% = %False AddNote2Har Task(%Pattern3_Task).Har,Melody(i%), LickStick.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 = (LickStick.dens * 2 / 3) ' in events/sec (Hz) END SUB SUB LickStickPatternAlgo (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) > Tenrec.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) < TenRec.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) < TenRec.LowTes THEN EXIT SUB ' end reached IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) > TenRec.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) < TenRec.LowTes THEN EXIT SUB ' end reached IF PatternSeq(pattern).noot(PatternSeq(pattern).lengte) > TenRec.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 >= TenRec.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) < TenRec.LowTes THEN EXIT SUB ' end reached IF PatternSeq(4).noot(PatternSeq(4).lengte) > TenRec.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 >= TenRec.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 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,Tenrec.lowtes, Tenrec.hightes) ' returns the notes not present in ' the Har$ passed. FUNCTION = StealNoteFromHar(H2, PatternSeq(pattern).noot(PatternSeq(pattern).lengte-1), TenRec.lowtes, TenRec.hightes) END FUNCTION SUB LickStickPlaySample () ' this task plays the prerecorded wave files on disk. ' This task has very specific lickstick 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 = "LS0" & TRIM$(STR$(CatIdx1)) & ".WAV" INCR CatIdx1 IF CatIdx1 > 2 THEN CatIdx1 = 0 CASE 2 Filnam = "LS1" & TRIM$(STR$(CatIdx2)) & ".WAV" INCR CatIdx2 IF CatIdx2 > 10 THEN CatIdx2 = 0 CASE 3 Filnam = "LS2" & TRIM$(STR$(CatIdx3)) & ".WAV" INCR CatIdx3 IF CatIdx3 > 7 THEN CatIdx3 = 0 CASE 4 Filnam = "LS3" & TRIM$(STR$(CatIdx4)) & ".WAV" INCR CatIdx4 IF CatIdx4 > 17 THEN CatIdx4 = 0 CASE 5 Filnam = "LS4" & TRIM$(STR$(CatIdx5)) & ".WAV" INCR CatIdx5 IF CatIdx5 > 4 THEN CatIdx5 = 0 CASE 6 Filnam = "LS5" & TRIM$(STR$(CatIdx6)) & ".WAV" INCR CatIdx6 IF CatIdx6 > 3 THEN CatIdx6 = 0 CASE 7 Filnam = "LS6" & TRIM$(STR$(CatIdx7)) & ".WAV" INCR CatIdx7 IF CatIdx7 > 4 THEN CatIdx7 = 0 CASE 8 Filnam = "LS7" & TRIM$(STR$(CatIdx8)) & ".WAV" INCR CatIdx8 IF CatIdx8 > 15 THEN CatIdx8 = 0 END SELECT Filnam = "solokomp\lickstick\" + TRIM$(LCASE$(Filnam)) + CHR$(0) ' here we check for the existence of these files... IF ISFALSE Existfile(UCASE$(Filnam)) THEN StopTask %AudioPlaySample_Task 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 LickStickRingModulator () 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 LickStickPitchShift () ' 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 LickStick.tes > %False THEN retval = SizeAudioTrack (Track2,duur * (La/LickStick.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: LickStick.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 LickStickDelayInvertFast () ' 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 recorder. 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 LickStickDelayBackInvert () ' 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 LickStickDelayBackSlow () ' 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 LickStickDelayPlayerNormal () ' 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] _ _