' *************************************************************************** ' * * ' * an automated serinette by dr.Godfried-Willem Raes * ' * first working version 2017 * ' *************************************************************************** ' 15.02.2017: Project started. ' 28.02.2017: all four boards ready and programmed with version 1.0 ' 03.03.2017: to do: add procedure for microtuning of the notes ' Firmware version 1.1 on the PIC's ' 04.03.2017: microtuning tests added. ' 08.03.2017: just intonation tunings added ' none of the tuning procedures seem to work... ' 10.03.2017: debugged ok now. ' 13.03.2017: Pipi demo piece finished. ' 16.08.2017: Pipi for Pi performed again. ' 01.09.2018: Test code for 2Pi added in this module. ' 02.03.2022: Test code for 3Pi added here. ' 28.04.2022: Test code for 4Pi added here. Warning: 4Pi uses another midi channel than the other Pi-robots. ' 12.05.2022: need to add code for testing the tuning , controllers and key pressure on 4Pi ' 13.05.2022: Tests added for JI tunings and key pressure %Pi_Test = 18 %Pi_Params = 19 %Pi_Scale = 20 %Pi_Lite = 21 %Pi_Tune = 22 %Pi_Just = 23 %Pi_Poly = 24 ' 'Pipi' demostukje: (loopt automatisch) %Pipi_Intro = 32 %Pipi_Perc = 33 %Pipi_Triads = 34 %Pipi_Burst = 35 %Pipi = 36 %Pipi_end = 37 ' specific tasks for 2Pi, task range 48 to 50 %Pi2_Scale = 48 %Pi2_Test = 49 %Pi2_Lites = 50 ' 63 ' tests for <3Pi> %Pi3_Scale = 52 %Pi3_Test = 53 ' tests for <4Pi>. Note: this uses midi channel 11, so different than channel 5 used by the other pi-robots. %Pi4_scale = 56 %Pi4_Test = 57 %Pi4_Params = 58 %Pi4_Lites = 59 %Pi4_Just = 60 %Pi4_Pres = 61 ' 'Pipi-4' demostukje: (loopt automatisch) %pi4_Intro = 1 %Pi4_Perc = 2 %Pi4_Burst = 3 '4 %Pi4 = 4 ' 5 %Pi4_end = 5 ' 6 ' Pi four triads: %Pi4_Triads = 7 GLOBAL hwCtrlPi AS DWORD GLOBAL hwCtrl4Pi AS DWORD DECLARE FUNCTION Init_Pi () AS DWORD DECLARE SUB Pi_Test () FUNCTION Init_Pi () EXPORT AS DWORD LOCAL CockpitLayo AS CockpitLabels LOCAL i AS DWORD LOCAL m AS ASCIIZ * 40 LOCAL zText AS ASCIIZ * 25 LOCAL retval AS LONG GetInstrumentParams Pi_, %IDM_Pi retval = SetRobotport (Pi_, Inifilename, hMidiO()) GetInstrumentParams Pi2_, %IDM_2Pi retval = SetRobotport (Pi2_, Inifilename, hMidiO()) GetInstrumentParams Pi3, %IDM_3Pi retval = SetRobotport (Pi3, Inifilename, hMidiO()) GetInstrumentParams Pi4, %IDM_4Pi retval = SetRobotport (Pi4, Inifilename, hMidiO()) Task(App.ReadSeqScoreTaskNr).cPtr = %False ' remove from cockpit. ' delete buttons that are not required or functional: ButnSW(2).tag0 = "Power On" ' CC66 ButnSW(2).tag1 = "Power Off" ButnSW(2).cptr = %False IF ISFALSE hMidiI(0) THEN Task(16).naam = "" Task(16).cptr = %False END IF Task(%Pi_Test).cPtr = CODEPTR(Pi_Test) ' repetitions Task(%Pi_Test).freq = 2 Task(%Pi_Test).naam = "Pi_Reps" Task(%Pi_Test).flags = %False Task(%Pi_Params).cPtr = CODEPTR(Pi_Params) Task(%Pi_Params).freq = 20 Task(%Pi_Params).naam = "Pi_Ctrl" Task(%Pi_Params).flags = %False Task(%Pi_Scale).cPtr = CODEPTR(Pi_Scale) Task(%Pi_Scale).freq = 4 Task(%Pi_Scale).naam = "Pi_Scale" Task(%Pi_Scale).flags = %False Task(%Pi_Lite).cPtr = CODEPTR(Pi_Lite) Task(%Pi_Lite).freq = 4 Task(%Pi_Lite).naam = "Pi_Lite" Task(%Pi_Lite).flags = %False Task(%Pi_Tune).cPtr = CODEPTR(Pi_Tune) Task(%Pi_Tune).freq = 10 Task(%Pi_Tune).naam = "Pi_Tune" Task(%Pi_Tune).flags = %False TaskEX(%Pi_Tune).stopcptr = CODEPTR(Pi_Tune_stop) ' makes tuning logfile Task(%Pi_Just).cPtr = CODEPTR(Pi_Just) Task(%Pi_Just).freq = 2 Task(%Pi_Just).naam = "Pi_Just" Task(%Pi_Just).flags = %False TaskEX(%Pi_Just).stopcptr = CODEPTR(Pi_Just_stop) Task(%Pi_Poly).cPtr = CODEPTR(Pi_Poly) Task(%Pi_Poly).freq = 4 Task(%Pi_Poly).naam = "Pi_Poly" Task(%Pi_Poly).flags = %False ' demo piece gwr: Task(%Pipi_Intro).cPtr = CODEPTR(Pipi_Intro) Task(%Pipi_Intro).freq = 4 Task(%PiPi_Intro).naam = "Pi_Intro" Task(%Pipi_Intro).flags = %False TaskEX(%Pipi_Intro).stopcptr = CODEPTR(Pipi_Intro_Stop) Task(%Pipi_Triads).cPtr = CODEPTR(Pipi_Triads) Task(%Pipi_Triads).freq = 4 Task(%PiPi_Triads).naam = "Pi_3ths" Task(%Pipi_Triads).flags = %False TaskEX(%Pipi_Triads).stopcptr = CODEPTR(Pipi_Triads_Stop) Task(%Pipi_Perc).cPtr = CODEPTR(Pipi_Perc) Task(%Pipi_Perc).freq = 4 Task(%PiPi_Perc).naam = "Pi_Perc" Task(%Pipi_Perc).flags = %False TaskEX(%Pipi_Perc).stopcptr = CODEPTR(Pipi_Perc_Stop) Task(%Pipi_Burst).cPtr = CODEPTR(Pipi_Burst) Task(%Pipi_Burst).freq = 3 Task(%PiPi_Burst).naam = "Pi_Burst" Task(%Pipi_Burst).flags = %False TaskEX(%Pipi_Burst).stopcptr = CODEPTR(Pipi_Burst_Stop) Task(%Pipi).naam = "Pipi" Task(%Pipi).freq = 0.2 Task(%Pipi).channel = Pi_.channel Task(%Pipi).tempo = 12 Task(%Pipi).level = 46 Task(%Pipi).cPtr = CODEPTR(Pipi) Task(%Pipi).flags = %MIDI_TASK OR %HARM_TASK OR %SCORE_TASK Task(%Pipi_end).naam = "Pipi_end" Task(%Pipi_end).freq = 0.2 Task(%Pipi_end).channel = Pi_.channel Task(%Pipi_end).tempo = 8 Task(%Pipi_end).level = 46 Task(%Pipi_end).cPtr = CODEPTR(Pipi_ending) Task(%Pipi_end).flags = %False ' demo piece adapted for 4Pi: Task(%Pi4_Intro).cPtr = CODEPTR(Pi4_Intro) Task(%Pi4_Intro).freq = 4 Task(%Pi4_Intro).naam = "Pi4Intro" Task(%Pi4_Intro).flags = %False TaskEX(%Pi4_Intro).stopcptr = CODEPTR(Pi4_Intro_Stop) Task(%Pi4_Triads).cPtr = CODEPTR(Pi4_Triads) ' now separate piece Task(%Pi4_Triads).freq = 4 Task(%Pi4_Triads).naam = "Pi4_3th" Task(%Pi4_Triads).flags = %False TaskEX(%Pi4_Triads).stopcptr = CODEPTR(Pi4_Triads_Stop) Task(%Pi4_Perc).cPtr = CODEPTR(Pi4_Perc) Task(%Pi4_Perc).freq = 4 Task(%Pi4_Perc).naam = "Pi4Perc" Task(%Pi4_Perc).flags = %False TaskEX(%Pi4_Perc).stopcptr = CODEPTR(Pi4_Perc_Stop) Task(%Pi4_Burst).cPtr = CODEPTR(Pi4_Burst) Task(%Pi4_Burst).freq = 3 Task(%Pi4_Burst).naam = "Pi4Burst" Task(%Pi4_Burst).flags = %False TaskEX(%Pi4_Burst).stopcptr = CODEPTR(Pi4_Burst_Stop) Task(%Pi4).naam = "Pipi4" Task(%Pi4).freq = 0.2 Task(%Pi4).channel = Pi4.channel Task(%Pi4).tempo = 12 Task(%Pi4).level = 46 Task(%Pi4).cPtr = CODEPTR(Pipi4) Task(%Pi4).flags = %False ' %MIDI_TASK OR %HARM_TASK OR %SCORE_TASK Task(%Pi4_end).naam = "Pipi4end" Task(%Pi4_end).freq = 0.2 Task(%Pi4_end).channel = Pi4.channel Task(%Pi4_end).tempo = 8 Task(%Pi4_end).level = 46 Task(%Pi4_end).cPtr = CODEPTR(Pi4_ending) Task(%Pi4_end).flags = %False '--------------------------------------------------------------------------------- App.MidiPlayerTasknr = %h_fileplay 'the playertask expects itself to be located here - if we don't set the ReadSeqscoreTasknr we get a crash! Task(%h_fileplay).naam = "PlayMid" task(%h_fileplay).cptr = GetProcAddress(GetModuleHandle("g_lib.dll"),"MM_MIDIPLAYER") task(%h_fileplay).freq = 100 taskEX(%h_fileplay).stopcptr = GetProcAddress(GetModuleHandle("g_lib.dll"),"MM_MIDIPLAYERSTOP") ' 2Pi procedures: Task(%Pi2_Scale).cPtr = CODEPTR(Pi2_Scale) Task(%Pi2_Scale).freq = 4 Task(%Pi2_Scale).naam = "2Pi_Scal" Task(%Pi2_Scale).flags = %False Task(%Pi2_Test).cPtr = CODEPTR(Pi2_Test) ' repetitions Task(%Pi2_Test).freq = 2 Task(%Pi2_Test).naam = "Pi2_Reps" Task(%Pi2_Test).flags = %False Task(%Pi2_Lites).cPtr = CODEPTR(Pi2_Lites) Task(%Pi2_Lites).freq = 4 Task(%Pi2_Lites).naam = "Pi2_Lite" Task(%Pi2_Lites).flags = %False ' 3Pi procedures: Task(%Pi3_Scale).cPtr = CODEPTR(Pi3_Scale) Task(%Pi3_Scale).freq = 4 Task(%Pi3_Scale).naam = "3Pi_Scal" Task(%Pi3_Scale).flags = %False Task(%Pi3_Test).cPtr = CODEPTR(Pi3_Test) ' repetitions Task(%Pi3_Test).freq = 2 Task(%Pi3_Test).naam = "Pi3_Reps" Task(%Pi3_Test).flags = %False ' 4Pi procedures: Task(%Pi4_Scale).cPtr = CODEPTR(Pi4_Scale) Task(%Pi4_Scale).freq = 4 Task(%Pi4_Scale).naam = "4Pi_Scal" Task(%Pi4_Scale).flags = %False Task(%Pi4_Test).cPtr = CODEPTR(Pi4_Test) ' repetitions Task(%Pi4_Test).freq = 2 Task(%Pi4_Test).naam = "Pi4_Reps" Task(%Pi4_Test).flags = %False Task(%Pi4_params).cPtr = CODEPTR(Pi4_params) ' controllers Task(%Pi4_params).freq = 20 Task(%Pi4_params).naam = "Pi4params" Task(%Pi4_params).flags = %False Task(%Pi4_lites).cPtr = CODEPTR(Pi4_lites) ' lites Task(%Pi4_lites).freq = 2 Task(%Pi4_lites).naam = "Pi4lites" Task(%Pi4_lites).flags = %False Task(%Pi4_Just).cPtr = CODEPTR(Pi4_Just) Task(%Pi4_Just).freq = 2 Task(%Pi4_Just).naam = "Pi4_JI" Task(%Pi4_Just).flags = %False TaskEX(%Pi4_Just).stopcptr = CODEPTR(Pi4_Just_stop) Task(%Pi4_Pres).cPtr = CODEPTR(Pi4_Pres) Task(%Pi4_Pres).freq = 20 Task(%Pi4_Pres).naam = "Pres" Task(%Pi4_Pres).flags = %False ButnSW(7).tag0 = "PiCtrl tog" ButnSW(7).tag1 = "PiCtrl tog" ButnSW(7).cptr = CODEPTR(Pi_Controlroom) ButnSW(8).tag0 = "Pi4tog" ButnSW(8).tag1 = "Pi4tog" ButnSW(8).cptr = CODEPTR(Pi4_Controlroom) App.id = %IDM_PI m = " & <2Pi> & <3Pi> & <4Pi>" SendMessage gh.Cockpit, %WM_SETTEXT,0, VARPTR(m) FUNCTION = %True END FUNCTION SUB Pi_Test () ' tests repeated notes. ' parameters: repetition rate ' push-time ' release-time ' note STATIC slnr AS DWORD STATIC i,j AS INTEGER LOCAL onoff AS SINGLE LOCAL period AS SINGLE IF ISFALSE Task(%Pi_Test).tog THEN DIM TaskParamLabels(0 TO 4) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" ' repeat rate TaskParamlabels(1) = "On/Off" ' puls-pause proportion TaskParamlabels(2) = "velo" TaskParamlabels(3) = "release" TaskParamLabels(4) = "Note" ' note IF ISFALSE Task(%Pi_Test).hParam THEN slnr = %False MakeTaskParameterDialog %Pi_Test,4,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_Test).SliderNumbers(0) UDctrl(TaskEX(%Pi_Test).UpdownNumbers(0)).cptr = CODEPTR(Pi_Note_UD1) i = 84 UDctrl(TaskEX(%Pi_Test).UpDownNumbers(0)).value = i Task(%Pi_Test).freq = 2 Slider(slnr).value = Task(%Pi_Test).freq SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 64 SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, 64 ' mid position END IF j = %False Controller Pi_.channel, 66, 64 Task(%Pi_Test).tog = %True EXIT SUB END IF OnOff = Slider(slnr+1).value / 128 ' 0- 0.99218 IF OnOff < 0.0078 THEN OnOff = 0.0078125 period = 1! / (32! * ((Slider(slnr).value+1) / 128!)) ' tempo - duur in sekonden. IF ISFALSE j THEN mPlay Pi_.channel, i, Slider(slnr+2).value period = period * OnOff ELSE Release Pi_.channel, i, Slider(slnr+3).value ' allways overrides ctrl #19 i = UDctrl(TaskEX(%Pi_Test).UpDownNumbers(0)).value period = period * (1! - OnOff) END IF Task(%Pi_Test).freq = MAX(MIN(1! / period, 1000),1) INCR j j = j MOD 2 END SUB SUB Pi_Note_UD1 () ' controls the note to be played. LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi_Test).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < 84 THEN UDctrl(udnr).value = 84 : noot = 84 IF noot > 127 THEN UDctrl(udnr).value = 127 : noot = 127 SetDlgItemText Task(%Pi_Test).hparam, %GMT_TEXT0_ID + 16, "n=" & STR$(noot) END SUB SUB Pi_params() STATIC i% STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi_Params).tog THEN i% = Pi_.lowtes ' create a parameter window: DIM TaskParamLabels(6) AS ASCIIZ * 8 'Pi__ControlRoom TaskParamLabels(0) = "Attack" ' duration - ctrl 17 TaskParamLabels(1) = "Decay" ' duration - ctrl 18 TaskParamLabels(2) = "Sustain" ' level - ctrl 7 TaskParamlabels(3) = "Release" ' duration - ctrl. 19 TaskParamLabels(4) = "Wave" ' ctrl 15 TaskParamLabels(5) = "Noise" ' ctrl 1 IF ISFALSE Task(%Pi_Params).hParam THEN MakeTaskParameterDialog %Pi_params,6,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_params).SliderNumbers(0) Slider(slnr).value = 10 ' attack SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 6 ' decay SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 64 'sustain SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 24 ' release SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 100 ' wave duty cycle SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 1 ' noise jitter SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value END IF Task(%Pi_params).tog = %True END IF IF Pi_.ctrl(17) <> Slider(slnr).value THEN ' attack duration Pi_.ctrl(17) = Slider(slnr).value Controller Pi_.channel, 17, Pi_.ctrl(17) END IF IF Pi_.ctrl(18) <> Slider(slnr+1).value THEN ' decay duration Pi_.ctrl(18) = Slider(slnr+1).value Controller Pi_.channel, 18, Pi_.ctrl(18) END IF IF Pi_.ctrl(7) <> Slider(slnr+2).value THEN ' sustain level Pi_.ctrl(7) = Slider(slnr+2).value Controller Pi_.channel, 7, Pi_.ctrl(7) END IF IF Pi_.ctrl(19) <> Slider(slnr+3).value THEN ' release duration Pi_.ctrl(19) = Slider(slnr+3).value Controller Pi_.channel, 19, Pi_.ctrl(19) END IF IF Pi_.ctrl(15) <> Slider(slnr+4).value THEN ' wave shape Pi_.ctrl(15) = Slider(slnr+4).value Controller Pi_.channel, 15, Pi_.ctrl(15) END IF IF Pi_.ctrl(1) <> Slider(slnr+5).value THEN ' wave shape Pi_.ctrl(1) = Slider(slnr+5).value Controller Pi_.channel, 1, Pi_.ctrl(1) END IF END SUB SUB Pi_scale() STATIC i% STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi_scale).tog THEN i% = 72 'Pi_.lowtes ' 84 ' create a parameter window: DIM TaskParamLabels(6) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamlabels(1) = "Velo" TaskParamlabels(2) = "Release" ' can also be done with ctrl. 19 TaskParamLabels(3) = "Attack" ' duration - ctrl 17 TaskParamLabels(4) = "Decay" ' duration - ctrl 18 TaskParamLabels(5) = "Sustain" ' level - ctrl 7 TaskParamLabels(6) = "Wave" ' ctrl 15 IF ISFALSE Task(%Pi_scale).hParam THEN MakeTaskParameterDialog %Pi_scale,7,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_scale).SliderNumbers(1) Slider(slnr).value = 80 ' velo SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = %False ' release SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 5 ' attack SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 10 ' decay SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 68 ' sustain SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 48 ' wave SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value END IF Controller Pi_.channel, 66, 127 Task(%Pi_scale).tog = %True END IF IF Pi_.ctrl(7) <> Slider(slnr+4).value THEN ' level sustain Pi_.ctrl(7) = Slider(slnr+4).value Controller Pi_.channel, 7, Pi_.ctrl(7) END IF IF Pi_.ctrl(17) <> Slider(slnr+2).value THEN ' attack duration Pi_.ctrl(17) = Slider(slnr+2).value Controller Pi_.channel, 17, Pi_.ctrl(17) END IF IF Pi_.ctrl(18) <> Slider(slnr+3).value THEN ' decay duration Pi_.ctrl(18) = Slider(slnr+3).value Controller Pi_.channel, 18, Pi_.ctrl(18) END IF IF Pi_.ctrl(15) <> Slider(slnr+5).value THEN ' wave shape Pi_.ctrl(15) = Slider(slnr+5).value Controller Pi_.channel, 15, Pi_.ctrl(15) END IF IF ISFALSE oldnote THEN mPlay Pi_.channel,i%, Slider(slnr).value oldnote = i% INCR i% IF i% > Pi_.Hightes THEN i% = Pi_.Lowtes ELSE IF ISFALSE slider(slnr+1).value THEN ' release value (duration) NoteOff Pi_.channel, oldnote ELSE Release Pi_.channel, oldnote, slider(slnr+1).value END IF oldnote = %False END IF Task(%Pi_scale).freq = Slider(slnr-1).value / 8 IF Task(%Pi_scale).freq < 0.1 THEN Task(%Pi_scale).freq = 0.1 END SUB SUB pi_controlroom LOCAL i AS LONG LOCAL x AS LONG IF ISFALSE hwCtrlpi THEN DIALOG NEW 0, "pi_ Control",1,1 ,560, 80, %WS_CAPTION OR %WS_POPUP OR %WS_SYSMENU TO hwCtrlpi x = 5 FOR i = pi_.lowtes TO pi_.HighTes SELECT CASE (i MOD 12) CASE 0 CONTROL ADD CHECKBOX, hwCtrlpi, i, "C", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 1 CONTROL ADD CHECKBOX, hwCtrlpi, i, "C#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 2 CONTROL ADD CHECKBOX, hwCtrlpi, i, "D", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 3 CONTROL ADD CHECKBOX, hwCtrlpi, i, "D#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 4 CONTROL ADD CHECKBOX, hwCtrlpi, i, "E", x, 24, 18, 12, %BS_PUSHLIKE x = x + 20 CASE 5 CONTROL ADD CHECKBOX, hwCtrlpi, i, "F", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 6 CONTROL ADD CHECKBOX, hwCtrlpi, i, "F#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 7 CONTROL ADD CHECKBOX, hwCtrlpi, i, "G", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 8 CONTROL ADD CHECKBOX, hwCtrlpi, i, "G#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 9 CONTROL ADD CHECKBOX, hwCtrlpi, i, "A", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 10 CONTROL ADD CHECKBOX, hwCtrlpi, i, "Bb", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 11 CONTROL ADD CHECKBOX, hwCtrlpi, i, "B", x, 24, 18, 12, %BS_PUSHLIKE x = x + 20 END SELECT NEXT CONTROL ADD LABEL, hwCtrlpi, 500, "Wind:", 5, 45, 30, 12 CONTROL ADD "msctls_trackbar32", hwCtrlpi, 501, "Wind", 36, 45, 135, 12, %WS_CHILD OR %WS_VISIBLE OR %TBS_HORZ OR %TBS_BOTTOM CONTROL ADD LABEL, hwCtrlpi, 503, "?", 174, 45, 30, 12 CONTROL ADD LABEL, hwCtrlpi, 510, "Velo:", 5, 60, 30, 12 CONTROL SEND hwCtrlPi, 501, %TBM_SETRANGEMAX, %true,127 CONTROL ADD "msctls_trackbar32", hwCtrlpi, 511, "Velo", 36, 60, 135, 12, %WS_CHILD OR %WS_VISIBLE OR %TBS_HORZ OR %TBS_BOTTOM CONTROL ADD LABEL, hwCtrlpi, 513, "?", 174, 60, 30, 12 ' control send hwCtrlPi, 511, %TBM_SETPOS, %true, 64 CONTROL SEND hwCtrlPi, 511, %TBM_SETRANGEMAX, %true,127 CONTROL ADD BUTTON, hwCtrlpi, 600, "All Off", 206, 45, 30, 12 CONTROL ADD CHECKBOX, hwCtrlPi, 610, "CC66", 206, 60, 30, 12, %BS_PUSHLIKE DIALOG SHOW MODELESS hwCtrlpi CALL CB_pi_Controlroom ELSE DIALOG END hwCtrlpi hwCtrlpi = 0 END IF END SUB CALLBACK FUNCTION CB_pi_Controlroom LOCAL wind AS BYTE LOCAL i AS LONG STATIC hTrackWind AS DWORD STATIC hTrackVelo AS DWORD STATIC velo AS BYTE LOCAL note AS BYTE SELECT CASE CBMSG CASE %WM_COMMAND SELECT CASE CBCTL CASE pi_.Lowtes TO pi_.hightes 'checkboxes CONTROL GET CHECK CBHNDL, CBCTL TO i note = CBCTL mPlay pi_.channel, note, IIF( i, velo, 0) CONTROL SET TEXT gh.cockpit, %GMT_MSG1,"note"+ STR$(note) + STR$(IIF( i, velo, 0) ) CASE 600 FOR i = pi_.lowtes TO pi_.hightes CONTROL SET CHECK CBHNDL, i, 0 DIALOG DOEVENTS NEXT Controller pi_.channel, 123, %False CASE 610 CONTROL GET CHECK CBHNDL, CBCTL TO i Controller Pi_.channel, 66, i * 127 END SELECT CASE %WM_HSCROLL, %WM_VSCROLL 'note: id doesn't correspond at all with the one given at creation 'more then one slider.. so we have to track which one.. CONTROL HANDLE CBHNDL, 501 TO htrackwind CONTROL HANDLE CBHNDL, 511 TO htrackvelo CONTROL SET TEXT gh.cockpit, %GMT_MSG2, STR$(htrackwind) +STR$(htrackvelo) +STR$(CBLPARAM) IF CBLPARAM = htrackWind THEN IF (LOWRD(CBWPARAM) = %TB_THUMBPOSITION) OR (LOWRD(CBWPARAM) = %TB_THUMBTRACK) THEN wind = HIWRD(CBWPARAM) ELSE wind = SendMessage (CBLPARAM, %TBM_GETPOS,%Null, %Null) END IF 'wind = wind * 1.27 CONTROL SET TEXT CBHNDL, 503, STR$(wind) pi_.ctrl(7) = wind Controller Pi_.channel, 7, Pi_.ctrl(7) CONTROL SET TEXT gh.cockpit, %GMT_MSG1, "cc7"+ STR$(Pi_.ctrl(7) ) ELSEIF CBLPARAM = htrackVelo THEN IF (LOWRD(CBWPARAM) = %TB_THUMBPOSITION) OR (LOWRD(CBWPARAM) = %TB_THUMBTRACK) THEN velo = HIWRD(CBWPARAM) ELSE velo = SendMessage (CBLPARAM, %TBM_GETPOS,%Null, %Null) END IF 'velo = velo * 1.27 CONTROL SET TEXT CBHNDL, 513, STR$(velo) END IF CASE %WM_CLOSE, %WM_QUIT hwCtrlpi = 0 FOR i = pi_.lowtes TO pi_.hightes DIALOG DOEVENTS NEXT Controller pi_.channel, 123, %False 'MM_pi_Off %MM_Motor END SELECT END FUNCTION SUB Pi_Lite () ' note 0. yellow light STATIC slnr AS DWORD STATIC cnt AS BYTE IF ISFALSE Task(%Pi_lite).tog THEN ' create a parameter window: DIM TaskParamLabels(1) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamlabels(1) = "Level" IF ISFALSE Task(%Pi_lite).hParam THEN MakeTaskParameterDialog %Pi_lite,2,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_lite).SliderNumbers(1) Slider(slnr).value = 127 ' velo SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value END IF Controller Pi_.channel, 66, 127 Task(%Pi_lite).tog = %True END IF IF ISFALSE cnt THEN mPlay Pi_.channel,0, Slider(slnr).value ELSE Release Pi_.channel, 0, 64 END IF INCR cnt IF cnt > 1 THEN cnt = %False Task(%Pi_lite).freq = Slider(slnr-1).value / 8 IF Task(%Pi_lite).freq < 0.1 THEN Task(%Pi_lite).freq = 0.1 END SUB SUB Pi_Tune () ' test for ctrl's 72 to 116, microtuning for the notes ' needs 1 U/D controller for the note and 1 slider for tuning ' microtuning controllers use the range 72 to 116 STATIC slnr, udnr AS DWORD STATIC noot AS INTEGER IF ISFALSE Task(%Pi_Tune).tog THEN DIM TaskParamLabels(0 TO 1) AS ASCIIZ * 8 TaskParamLabels(0) = "Tune" ' microtuning slider TaskParamLabels(1) = "Note" ' note UD IF ISFALSE Task(%Pi_Tune).hParam THEN slnr = %False MakeTaskParameterDialog %Pi_Tune,1,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_Tune).SliderNumbers(0) udnr = TaskEX(%Pi_tune).UpDownNumbers(0) UDctrl(TaskEX(%Pi_Tune).UpdownNumbers(0)).cptr = CODEPTR(Pi_Tune_UD1) UDctrl(TaskEX(%Pi_Tune).UpDownNumbers(0)).value = 84 Task(%Pi_Tune).freq = 20 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, 64 FOR noot = 84 TO 127 Pi_.ctrl(noot - 12) = 64 ' defaults NEXT noot END IF Controller Pi_.channel, 66, 64 Task(%Pi_Tune).tog = %True END IF noot = UDctrl(udnr).value IF noot >= 84 THEN IF Pi_.ctrl(noot-12) <> Slider(slnr).value THEN Controller Pi_.channel, noot - 12, Slider(slnr).value Pi_.ctrl(noot-12) = slider(slnr).value END IF END IF END SUB SUB Pi_Tune_UD1 () ' controls the note to be microtuned. LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi_Tune).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < 84 THEN UDctrl(udnr).value = 84 : noot = 84 IF noot > 127 THEN UDctrl(udnr).value = 127 : noot = 127 SetDlgItemText Task(%Pi_Tune).hparam, %GMT_TEXT0_ID + 16, "n=" & STR$(noot) END SUB SUB Pi_Tune_Stop () LOCAL i AS INTEGER Logfile "Microtuning settings for " Logfile DATE$ Logfile TIME$ FOR i = 72 TO 116 Logfile "Note = " & STR$(i+12) & " tuning= " & STR$(Pi_.ctrl(i)- 64) NEXT i END SUB SUB Pi_Just () ' test for ctrl 21 EQ or Just intonation tunings ' needs 1 U/D controller for the basenote STATIC slnr, udnr AS DWORD STATIC noot, oldnoot AS INTEGER IF ISFALSE Task(%Pi_Just).tog THEN DIM TaskParamLabels(0 TO 1) AS ASCIIZ * 8 TaskParamLabels(0) = "---" TaskParamLabels(1) = "Tun" ' note IF ISFALSE Task(%Pi_Just).hParam THEN slnr = %False MakeTaskParameterDialog %Pi_Just,1,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_Just).SliderNumbers(0) udnr = TaskEx(%Pi_Just).UpDownNumbers(0) UDctrl(TaskEX(%Pi_Just).UpdownNumbers(0)).cptr = CODEPTR(Pi_Just_UD1) UDctrl(TaskEX(%Pi_Just).UpDownNumbers(0)).value = 0 Task(%Pi_Just).freq = 4 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, 0 Pi_.ctrl(21) = 0 ' defaults END IF Controller Pi_.channel, 21, 0 RESET oldnoot Task(%Pi_Just).tog = %True END IF noot = UDctrl(udnr).value IF noot <> oldnoot THEN oldnoot = noot SELECT CASE noot CASE 0 Controller Pi_.channel, 21, noot Pi_.ctrl(21) = noot CASE 12 TO 23 Controller Pi_.channel, 21, noot Pi_.ctrl(21) = noot END SELECT END IF END SUB SUB Pi_Just_UD1 () ' controls the base note for just intonation LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi_Just).UpDownNumbers(0) noot = UDCtrl(udnr).value 'IF noot < 12 THEN UDctrl(udnr).value = 0 : noot = 0 ' resets to EQ IF noot > 23 THEN UDctrl(udnr).value = 23 : noot = 23 SetDlgItemText Task(%Pi_Just).hparam, %GMT_TEXT0_ID + 16, "JI" & STR$(noot) END SUB SUB Pi_Just_Stop () Controller Pi_.channel, 21, 0 ' reset to EQ Pi_.ctrl(21) = 0 END SUB SUB Pi_Poly () ' Written to test polyphonic limits of the hardware. ' parameters: speed ' nr of notes ' legato/staccato STATIC slnr AS DWORD STATIC j AS DWORD STATIC i AS INTEGER LOCAL onoff AS SINGLE LOCAL period AS SINGLE LOCAL n AS INTEGER IF ISFALSE Task(%Pi_Poly).tog THEN DIM TaskParamLabels(0 TO 2) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" ' playing speed TaskParamlabels(1) = "On/Off" ' legato-staccato proportion TaskParamLabels(2) = "Nr" ' nr of notes IF ISFALSE Task(%Pi_Poly).hParam THEN slnr = %False MakeTaskParameterDialog %Pi_Poly,2,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi_Poly).SliderNumbers(0) UDctrl(TaskEX(%Pi_Poly).UpdownNumbers(0)).cptr = CODEPTR(Pi_NrNotes_UD1) ' aantal noten i = 4 UDctrl(TaskEX(%Pi_Poly).UpDownNumbers(0)).value = 4 j = 0 Task(%Pi_Poly).freq = 2 Slider(slnr).value = Task(%Pi_Poly).freq SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 64 SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, 64 ' mid position END IF j = %False Task(%Pi_Poly).tog = %True Controller Pi_.channel, 66, 64 Pi_.ctrl(66) = 64 EXIT SUB END IF OnOff = Slider(slnr+1).value / 128 ' 0- 0.99218 IF OnOff < 0.0078 THEN OnOff = 0.0078125 period = 1! / (8! * ((Slider(slnr).value+1) / 128!)) ' tempo - duur in sekonden. IF ISFALSE j THEN Pi_.Har(1).vel = STRING$(128,0) i = MAX(UDctrl(TaskEX(%Pi_Poly).UpDownNumbers(0)).value , 1) DO n = 84 + (RND(1) * 43) IF IsNoteInHar( Pi_.Har(1), n) THEN ITERATE DO ' avoiding twice the same note AddNote2Har Pi_.Har(1),n , 64 LOOP UNTIL GetNrNotesInHar (Pi_.Har(1)) = i InstrumPlay Pi_ period = period * OnOff ELSE 'NoteOff Pi_.Har(1).vel = STRING$(128,0) InstrumPlay Pi_ period = period * (1! - OnOff) END IF Task(%Pi_Poly).freq = MAX(MIN(1! / period, 1000),1) INCR j j = j MOD 2 END SUB SUB Pi_NrNotes_UD1 () ' controls the number of notes to be played. LOCAL n AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi_Poly).UpDownNumbers(0) n = UDCtrl(udnr).value IF n < 1 THEN UDctrl(udnr).value = 1 : n = 1 IF n > 44 THEN UDctrl(udnr).value = 44 : n = 44 SetDlgItemText Task(%Pi_Poly).hparam, %GMT_TEXT0_ID + 16, "Nr=" & STR$(n) END SUB ' *************************************************************************** SUB Pipi_Intro () ' 11.03.2017: first coding ' to do: moet versnellen en volumes voor board 2 moeten naar beneden. ' done 12.03.2017 ' should restart at the point it was stopped, so that we can ' use the sounds at different points in the piece. ' 12.03.2017: Now 3 minutes STATIC noot, oldnoot, ofnoot, level, i AS INTEGER STATIC j , rise, fall, nrnotes, init, lite, nv AS INTEGER ' BYTE STATIC tfakt AS SINGLE STATIC cnt AS LONG IF ISFALSE Task(%Pipi_Intro).tog THEN Controller Pi_.channel, 66, 83 Controller Pi_.channel, 21, 0 Controller Pi_.channel, 17, 12 Controller Pi_.Channel, 18, 4 Controller Pi_.channel, 19, 20 Controller Pi_.channel, 15, 127 '100 Controller Pi_.channel, 1, 0 Pi_.ctrl(7) = 126 Controller Pi_.channel, 7, 126 IF cnt THEN logfile "Pipi Intro restart at:" & TIME$ & STR$(cnt) END IF Task(%Pipi_Intro).tog = %True END IF ' proc. to make restart possible at the point the task was interrupted IF ISFALSE init THEN RESET cnt Pi_.Har(1).vel = NUL$(128) i = 0 oldnoot = 0 noot = 127 ofnoot = 127 rise = %True fall = %False logfile "Pipi Intro start at:" & TIME$ & STR$(cnt) IF ISFALSE lite THEN mPlay Pi_.channel, 0, 100 ' lite lite = %True END IF Task(%Pipi_Intro).freq = 4 ' 24 '32 init = %True END IF ' musical coding: IF noot <> oldnoot THEN Controller Pi_.channel, 7, Pi_.ctrl(7) mPlay Pi_.channel, noot, 127 - Pi_.ctrl(7) oldnoot = noot AddNote2Har Pi_.Har(1), noot, 127 - Pi_.ctrl(7) INCR nrnotes END IF IF rise = %True THEN INCR i IF i <= 127 THEN Pi_.ctrl(1) = MIN(MAX(i,0),127) Controller Pi_.channel, 1, Pi_.ctrl(15) ' noise ELSE rise = %False fall = %True END IF END IF IF fall = %True THEN DECR i 'i = i - 2 IF i >= 0 THEN Pi_.ctrl(1) = MIN(MAX(i,0),127) Controller Pi_.channel, 1, Pi_.ctrl(1) ' noise ELSE rise = %True fall = %False DO noot = noot - RND(1,3) '(1 + (cnt MOD 2)) LOOP UNTIL noot < oldnoot IF noot < 84 THEN logfile "Pipi Intro full stop at :" & TIME$ RESET init stoptask %Pipi_Intro END IF END IF END IF IF nrnotes > 4 THEN nv = GetHighestNote (Pi_.Har(1), 0, 127) NoteOff Pi_.channel, HIBYT(nv) ',LOBYT(nv) DelNote2Har Pi_.Har(1), HIBYT(nv) DECR nrnotes END IF ' volume decrescendo in functie van de toonhoogte: 'level = 20 + ((noot - 84) * 2) ' noot - 84: loopt van 43 naar 0 ' * 2 = van 83 naar 0 ' + 20 = van 103 naar 20 'level = 44 + (( noot - 84) *2) ' van 127 naar 44 'level = 44 + (( noot - 84) *2) ' van 127 naar 44 IF noot > 97 THEN ' decrescendo level = MIN(106 + ((noot - 84) /2), 126) ' 127 tot 113 'level = 44 + (( noot - 84) *2) ' van 127 naar 44 ELSE ' crescendo level = 44 + ((1.0 - ((noot-84)/ 13.0))* 13.0) ' noot -84: loopt van 13 naar 0 ' / 13: loopt van 1 naar 0 ' 1 - : loopt van 0 naar 1 ' * 13: loopt van 0 naar 13 level = MIN(level, 126) END IF IF level <> Pi_.ctrl(7) THEN Pi_.ctrl(7) = level END IF INCR cnt ' accellerando: tfakt = 1.0 + (((noot - 84)/ 43.0) * (Pi * 2)) Task(%Pipi_Intro).freq = 10 * tfakt '24 * tfakt ' tfakt: 1- pi/2, float END SUB SUB Pipi_Intro_stop () logfile "Pipi Intro interrupted at: " & TIME$ controller Pi_.channel, 123, 0 starttask %Pipi_Perc END SUB SUB Pipi_Triads () ' 12.03.2017 ' should play triads where the lowest note makes a downslide ' the highest note an upslide and the middle note always stays stable ' based on - the complete catalogue of different chords, each chord having a different interval ' constellation. Ordering is in increasing level of dissonance. cfr. Belly_Cat in belly testcode ' 13.03.2017: restart bug to be solved. STATIC i, j, cnt, trans AS LONG STATIC init AS BYTE STATIC tog AS INTEGER STATIC Akk() AS INTEGER STATIC n AS INTEGER STATIC lownote, highnote AS INTEGER 'LOCAL zandloper AS ASCIIZ PTR ' silly !!! (caused by declaration of WinApi) 'LOCAL hCursor AS LONG IF ISFALSE Task(%Pipi_Triads).tog THEN IF ISFALSE init THEN REDIM Akk(&HFFF) AS STATIC INTEGER ' hCursor = GetCursor () ' zandloper = %IDC_WAIT ' SetCursor LoadCursor (%Null, BYVAL(zandloper)) ' cfr. declaration PB WinApi SortChordsOnDissonance Akk(), &HF33C, 127 ' dll procedure ' parameters: %SortNoIsomorphs OR %SortPsyChord, only chords with 3-notes 'MSGBOX "Chords sorted. Ubound Akk = " & STR$(UBOUND(Akk)) ' 19 chords! as chordnumbers init = %True ' SetCursor hCursor 'EXIT SUB END IF Controller Pi_.channel, 123, 0 ' controllers: Controller Pi_.channel, 66, 83 Controller Pi_.channel, 21, 0 Controller Pi_.channel, 17, 1 Controller Pi_.Channel, 18, 1 Controller Pi_.channel, 19, 1 Controller Pi_.channel, 15, 83 Controller Pi_.channel, 1, 0 Pi_.ctrl(7) = 127 Controller Pi_.channel, 7, Pi_.ctrl(7) RESET cnt tog = 1 logfile "Pipi_Triads start at: " & TIME$ Task(%Pipi_Triads).tog = %True END IF ' now we can start playing the iterated chords... ' and play with the controllers 72 to 116 IF tog = 1 THEN Task(%Pipi_Triads).Har.vel = STRING$(128,0) ' mPlay all those 19 triads on all possible pipes... ' Akk(cnt) = TransChordNum (Akk(cnt), trans) ' chordnumber transposition ' trans = (trans + 5) MOD 12 AddCnr2Har Task(%Pipi_Triads).Har , Akk(cnt), 84,127, 120 Pi_.Har(1) = Task(%Pipi_Triads).Har InstrumPlay Pi_ lownote = GetLowestNote (Task(%Pipi_Triads).Har, 0, 127) lownote = HIBYT(lownote) highnote = GetHighestNote (Task(%Pipi_Triads).Har, 0, 127) highnote = HIBYT(Highnote) Controller Pi_.channel, lownote -12, 64 Pi_.ctrl(lownote -12) = 64 ' reset Controller Pi_.channel, highnote - 12, 64 Pi_.ctrl(highnote - 12) = 64 INCR cnt RESET tog RESET j ELSE ' slides: Pi_.Har(1).vel = NUL$(128) InstrumPlay Pi_ Controller Pi_.Channel, lownote - 12, 64 - j Controller Pi_.Channel, highnote - 12, 64 + j Pi_.Har(1) = Task(%Pipi_Triads).Har InstrumPlay Pi_ INCR j IF j >= 63 THEN tog = 1 END IF END IF IF tog = 0 THEN IF cnt > 19 THEN ' UBOUND(Akk) then IF j >= 63 THEN stoptask %Pipi_Triads EXIT SUB END IF END IF END IF IF tog = 1 THEN Task(%Pipi_Triads).freq = 8 + (cnt/4.0) ELSE Task(%Pipi_Triads).freq = 10.0 + (cnt/4.0) - (j/8.0) ' slowdown to 2 END IF SetDlgItemText gh.Cockpit, %GMT_MSG1, "Count= " & STR$(cnt) IF cnt > 19 THEN Stoptask %Pipi_Triads ' to make sure it does not restart END IF END SUB SUB Pipi_Triads_Stop () LOCAL i AS BYTE controller Pi_.channel, 123, 0 FOR i = 72 TO 115 '84 -12 TO 127 - 12 Controller Pi_.channel, i, 64 Pi_.ctrl(i) = 64 NEXT i starttask %Pipi_Burst END SUB SUB Pipi_Perc () ' 12.03.2017 ' very short clouds of pitches ' needs further refinement. ' 13.03.2017: improved. STATIC note, velo AS INTEGER STATIC t, krono, duur AS LONG STATIC prop AS SINGLE ' normalised 0-1 timer IF ISFALSE Task(%Pipi_Perc).tog THEN Controller Pi_.channel, 17, 2 Controller Pi_.channel, 18, 0 Controller Pi_.channel, 7, 2 ' very low sustain velo = 127 t = TimeGetTime ' in ms RESET krono RESET note duur =30 ' 30 seconds duration Logfile "Pipi_Perc start at " & TIME$ Task(%Pipi_perc).tog = %True END IF IF note THEN noteoff Pi_.channel, note krono = (TimeGetTime - t)/ 1000 ' in seconds prop = krono / duur ' 0-1 IF krono >= duur THEN Logfile "Pipi_Perc stop at " & TIME$ Logfile "Duration was : " & STR$(krono) stoptask %Pipi_Perc EXIT SUB END IF note = RND(83,127) IF note >=84 THEN mPlay Pi_.channel, note, velo ELSE mPlay Pi_.channel, 0, 127 ' yellow LED flashes END IF Task(%Pipi_Perc).freq = 4 + RND(0,64 * prop) END SUB SUB Pipi_Perc_Stop () Controller Pi_.channel, 123, 0 starttask %Pipi_Triads END SUB SUB Pipi_Burst () ' very short clouds of noises ' needs further refinement. STATIC note, velo AS INTEGER STATIC t, krono, duur AS LONG STATIC prop AS SINGLE ' normalised 0-1 timer IF ISFALSE Task(%Pipi_Burst).tog THEN Controller Pi_.channel, 17, 10 Controller Pi_.channel, 18, 4 Controller Pi_.channel, 19, 64 Controller Pi_.channel, 7, 90 Controller Pi_.channel, 1, 120 ' noise velo = 127 t = TimeGetTime ' in ms RESET krono RESET note duur =30 ' 30 seconds duration Logfile "Pipi_Burst start at " & TIME$ Task(%Pipi_burst).tog = %True END IF IF note THEN noteoff Pi_.channel, note krono = (TimeGetTime - t)/ 1000 ' in seconds prop = krono / duur ' 0-1 IF krono >= duur THEN Logfile "Pipi_Burst stop at " & TIME$ Logfile "Duration was : " & STR$(krono) stoptask %Pipi_Burst EXIT SUB END IF note = RND(83,127) IF note >=84 THEN mPlay Pi_.channel, note, velo ELSE mPlay Pi_.channel, 0, 127 ' yellow LED flashes END IF Task(%Pipi_Burst).freq = 2 + RND(1,48 * prop) END SUB SUB Pipi_Burst_Stop () Controller Pi_.channel, 123, 0 starttask %Pipi END SUB SUB PiPi () ' demostukje voor solo ' based on: ' - the complete catalogue of different chords, each chord having a different interval ' constellation. Ordering is in increasing level of dissonance. ' chords are followed by their solutions. ' adapted from Melodrama for Melauton. (06.02.2017) STATIC i AS WORD ' akkoordenteller 0-350 STATIC temposlnr AS BYTE STATIC ppslnr AS BYTE STATIC levelslnr, veloslnr AS BYTE STATIC Ritmeteller% STATIC init AS BYTE STATIC Akk() AS INTEGER STATIC tc AS INTEGER GLOBAL Mh AS harmtype LOCAL tiks! LOCAL zandloper AS ASCIIZ PTR ' silly !!! (caused by declaration of WinApi) LOCAL hCursor AS LONG IF (Task(%Pipi).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB IF ISFALSE init THEN REDIM Akk(0 TO &HFFF) AS STATIC INTEGER hCursor = GetCursor () zandloper = %IDC_WAIT SetCursor LoadCursor (%Null, BYVAL(zandloper)) ' cfr. declaration PB WinApi SortChordsOnDissonance Akk(), &HFC1C, 127 ' dll procedure ' parameters: %SortNoIsomorphs OR %SortPsyChord ' MSGBOX "Chords sorted. Ubound Akk = " & STR$(UBOUND(Akk)) ' = 350 ' since this takes pretty long, it would be better to save the lookup to a diskfile init = %True DIM TaskParamLabels(0 TO 3) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamLabels(1) = "0/1 rit" TaskParamLabels(2) = "#7" TaskParamLabels(3) = "velo" IF Task(%Pipi).hParam = %Null THEN MakeTaskParameterDialog BYVAL %Pipi,4,Slider(),0,UDctrl(),TaskParamLabels() END IF temposlnr = TaskEX(%Pipi).SliderNumbers(0) ppslnr = TaskEX(%Pipi).SliderNumbers(1) levelslnr = TaskEX(%Pipi).SliderNumbers(2) veloslnr = TaskEX(%Pipi).SliderNumbers(3) Controller Pi_.channel, 66, 0 ' power off - reset controllers Slider(temposlnr).value = 22 ' starttempo SendMessage Slider(temposlnr).h, %TBM_SETPOS,%True,Slider(temposlnr).value SendMessage Slider(ppslnr).h, %TBM_SETPOS,%True, 127 ' legato Slider(ppslnr).value = 127 ' full legato SendMessage Slider(levelslnr).h, %TBM_SETPOS,%True, 42 ' ctrl7 Slider(levelslnr).value = 42 Slider(veloslnr).value = 120 SendMessage Slider(veloslnr).h, %TBM_SETPOS,%True, 120 ' velocity SetDlgItemText gh.Cockpit, %GMT_TEXT_TEMPO, STR$(App.tempo) Task(%Pipi).freq = App.tempo / 60! SetCursor hCursor Task(%Pipi).tog = %False Controller Pi_.channel, 66, 65 ' power on 'Stoptask %Pipi - would cause ending to start... EXIT SUB END IF '------------------------------------------------- IF ISFALSE Task(%Pipi).tog THEN Task(%Pipi).tog = %True SetDlgItemText gh.Cockpit, %GMT_MSG1, "350 chords and progressions" SetDlgItemText gh.Cockpit, %GMT_TITLE, "PiPi" SetDlgItemText gh.Cockpit, %GMT_AUTHOR, $gwr Controller Pi_.channel, 17, 60 Controller Pi_.Channel, 18, 10 Controller Pi_.channel, 19, 110 Controller Pi_.channel, 15, 100 Controller Pi_.channel, 1, 0 Controller Pi_.channel, 7, 46 i = %False ' reset akkoordenteller logfile "'Pipi' starttime = " & TIME$ END IF IF Task(%Pipi).tempo <> Slider(temposlnr).value THEN Task(%Pipi).tempo = Slider(temposlnr).value IF ISFALSE Task(%Pipi).tempo THEN Task(%Pipi).tempo = %True SetDlgItemText gh.Cockpit, %GMT_TEXT_TEMPO, STR$(Task(%Pipi).tempo) ' tempo display END IF IF ISFALSE Task(%Pipi).Rit.pattern(Ritmeteller%) THEN Ritmeteller% = %False ' select case i ' case < 12 ' Task(%Pipi).Rit.pattern(0)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pipi).Rit.pattern(1)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pipi).Rit.pattern(2)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pipi).Rit.pattern(3)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pipi).Rit.pattern(4)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pipi).Rit.pattern(5)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pipi).Rit.pattern(6)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pipi).Rit.pattern(7)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pipi).Rit.pattern(8)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pipi).Rit.pattern(9)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pipi).Rit.pattern(10)= %False Task(%Pipi).Rit.pattern(0)= (Slider(ppslnr).value + 1)*2 ' ON time Task(%Pipi).Rit.pattern(1)= Slider(ppslnr).value + 1 ' ON time Task(%Pipi).Rit.pattern(2)= Slider(ppslnr).value + 1 ' ON time Task(%Pipi).Rit.pattern(3)= Slider(ppslnr).value + 1 ' ON time Task(%Pipi).Rit.pattern(4)= Slider(ppslnr).value + 1 ' ON time Task(%Pipi).Rit.pattern(5)= -(128 - Slider(ppslnr).value) ' OFF time Task(%Pipi).Rit.pattern(6)= %False ' end select END IF tiks! = RitmSigma!(Task(%Pipi).Rit) IF tiks! < 1 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(%Pipi).freq = (tiks! * Task(%Pipi).tempo ) / (60 * ABS(Task(%Pipi).Rit.pattern(Ritmeteller%))) IF Task(%Pipi).Rit.pattern(Ritmeteller%) > 0 THEN SELECT CASE Ritmeteller% CASE %False AddCnr2Har Task(%Pipi).Har, Akk(i) OR &HF000, 84, 127, Slider(veloslnr).value ' velo from slider IF tc > 0 THEN TransHarm Task(%Pipi).Har, tc IF tc + 12 <> Pi_.ctrl(21) THEN Controller Pi_.channel, 21, tc + 12 ' set just intonation tuning base Pi_.ctrl(21) = tc + 12 END IF FillHarType Task(%Pipi).Har , %use_fuzzypsy SetDlgItemText gh.Cockpit, %GMT_MSG1, "Solve "& STR$(i) mH = Task(%Pipi).Har Pi_.Har(1) = Task(%Pipi).Har Instrumplay Pi_ INCR i ' akkoordenteller CASE 1 'ELSE ' solve the chord Task(%Pipi).har = mH IF tc > 0 THEN TransHarm Task(%Pipi).Har, tc IF tc + 12 <> Pi_.ctrl(21) THEN Controller Pi_.channel, 21, tc + 12 ' set just intonation tuning base Pi_.ctrl(21) = tc + 12 END IF Task(%Pipi).har.vel = SolveHar$ (Task(%Pipi).Har, -1, 0) Pi_.Har(1) = Task(%Pipi).Har SELECT CASE GetNrNotesInHar (Pi_.Har(1)) CASE 0 Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi_.Har(1) Task(%Pipi).Rit.pattern(Ritmeteller%+1)= - Task(%Pipi).Rit.pattern(Ritmeteller%) Task(%Pipi).Rit.pattern(Ritmeteller%+2)= %False InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE ELSE mH = Pi_.Har(1) InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) END SELECT CASE 2 ' further solve step: Task(%Pipi).har = mH IF tc > 0 THEN TransHarm Task(%Pipi).har, tc IF tc + 12 <> Pi_.ctrl(21) THEN Controller Pi_.channel, 21, tc + 12 ' set just intonation tuning base Pi_.ctrl(21) = tc + 12 END IF Pi_.Har(1).vel = SolveHar$ (Task(%Pipi).Har, -1, 0) Task(%Pipi).Har = Pi_.Har(1) mH = Pi_.Har(1) SELECT CASE GetNrNotesInHar (Pi_.Har(1)) CASE 0 Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi_.Har(1) Task(%Pipi).Rit.pattern(Ritmeteller%+1)= - Task(%Pipi).Rit.pattern(Ritmeteller%) Task(%Pipi).Rit.pattern(Ritmeteller%+2)= %False 'Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE ELSE mH = Pi_.Har(1) InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) END SELECT 'InstrumPlay Pi_ 'tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE 3 ' further solve step: Task(%Pipi).har = mH IF tc > 0 THEN TransHarm Task(%Pipi).har, tc IF tc + 12 <> Pi_.ctrl(21) THEN Controller Pi_.channel, 21, tc + 12 ' set just intonation tuning base Pi_.ctrl(21) = tc + 12 END IF Pi_.Har(1).vel = SolveHar$ (Task(%Pipi).Har, -1, 0) Task(%Pipi).Har = Pi_.Har(1) mH = Pi_.Har(1) SELECT CASE GetNrNotesInHar (Pi_.Har(1)) CASE 0 Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi_.Har(1) Task(%Pipi).Rit.pattern(Ritmeteller%+1)= - Task(%Pipi).Rit.pattern(Ritmeteller%) Task(%Pipi).Rit.pattern(Ritmeteller%+2)= %False 'Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE ELSE mH = Pi_.Har(1) InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) END SELECT 'InstrumPlay Pi_ 'tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE 4 ' further solve step: Task(%Pipi).har = mH IF tc > 0 THEN TransHarm Task(%Pipi).har, tc IF tc + 12 <> Pi_.ctrl(21) THEN Controller Pi_.channel, 21, tc + 12 ' set just intonation tuning base Pi_.ctrl(21) = tc + 12 END IF Pi_.Har(1).vel = SolveHar$ (Task(%Pipi).Har, -1, 0) Task(%Pipi).Har = Pi_.Har(1) mH = Pi_.Har(1) SELECT CASE GetNrNotesInHar (Pi_.Har(1)) CASE 0 Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi_.Har(1) Task(%Pipi).Rit.pattern(Ritmeteller%+1)= - Task(%Pipi).Rit.pattern(Ritmeteller%) Task(%Pipi).Rit.pattern(Ritmeteller%+2)= %False 'Task(%Pipi).Rit.pattern(Ritmeteller%+1)= %False InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) CASE ELSE mH = Pi_.Har(1) InstrumPlay Pi_ tc = QuestTcHar (Task(%Pipi).Har, 0.3) END SELECT 'InstrumPlay Pi_ 'tc = QuestTcHar (Task(%Pipi).Har, 0.3) END SELECT ELSEIF Task(%Pipi).Rit.pattern(Ritmeteller%) < 0 THEN ' rust Task(%Pipi).Har.vel = NUL$(128) Pi_.Har(1).vel = NUL$(128) Pi_.Har(0).vel = NUL$(128) Controller Pi_.channel, 123, 0 ' voortijdig einde na akoord 47: IF i = 48 THEN Task(%Pipi_end).Har = mH Stoptask %Pipi StartTask %Pipi_end END IF ' voor de volledige versie...: IF i > UBOUND(Akk) THEN Task(%Pipi_end).Har = mH Stoptask %Pipi StartTask %Pipi_end END IF END IF INCR Ritmeteller% IF Slider(levelslnr).value <> Task(%Pipi).level THEN Task(%Pipi).level = Slider(levelslnr).value Controller Task(%Pipi).channel, 7 , Task(%Pipi).level ' changes sustain, but these values are used for velo as well... END IF END SUB SUB pipi_ending () STATIC levelslnr AS LONG IF ISFALSE Task(%Pipi_end).tog THEN levelslnr = TaskEX(%Pipi).SliderNumbers(2) Task(%Pipi_end).freq = 1 Pi_.ctrl(7) = Slider(levelslnr).value Controller Pi_.channel, 7, Pi_.ctrl(7) Pi_.har(1) = mH ' mH is global InstrumPlay Pi_ Task(%Pipi_end).freq = Pi_.ctrl(7) / 10 '30 ' so duration will be 30 seconds Task(%Pipi_end).tog = %True END IF DECR Pi_.ctrl(7) INCR Pi_.ctrl(1) Pi_.har(1) = mH Instrumplay Pi_ IF Pi_.ctrl(1) > 127 THEN Pi_.Ctrl(1) = 127 IF Pi_.ctrl(7) <= 0 THEN Controller Pi_.channel, 123, %False Controller Pi_.channel, 66, %False logfile "'Pipi' endtime = " & TIME$ stoptask %Pipi_end ELSE Controller Pi_.channel, 7, Pi_.ctrl(7) Controller Pi_.channel, 1, Pi_.ctrl(1) END IF END SUB SUB Pi2_scale() STATIC i% STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi2_scale).tog THEN i% = 72 ' create a parameter window: DIM TaskParamLabels(6) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamlabels(1) = "Velo" TaskParamlabels(2) = "Release" ' can also be done with ctrl. 19 TaskParamLabels(3) = "Attack" ' duration - ctrl 17 TaskParamLabels(4) = "Decay" ' duration - ctrl 18 TaskParamLabels(5) = "Sustain" ' level - ctrl 7 TaskParamLabels(6) = "Wave" ' ctrl 15 IF ISFALSE Task(%Pi2_scale).hParam THEN MakeTaskParameterDialog %Pi2_scale,7,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi2_scale).SliderNumbers(1) Slider(slnr).value = 80 ' velo SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = %False ' release SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 5 ' attack SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 10 ' decay SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 68 ' sustain SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 48 ' wave SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value END IF Controller Pi2_.channel, 66, 127 ' same as Pi Task(%Pi2_scale).tog = %True END IF IF Pi2_.ctrl(7) <> Slider(slnr+4).value THEN ' level sustain Pi2_.ctrl(7) = Slider(slnr+4).value Controller Pi2_.channel, 7, Pi2_.ctrl(7) END IF IF Pi2_.ctrl(17) <> Slider(slnr+2).value THEN ' attack duration Pi2_.ctrl(17) = Slider(slnr+2).value Controller Pi2_.channel, 17, Pi2_.ctrl(17) END IF IF Pi2_.ctrl(18) <> Slider(slnr+3).value THEN ' decay duration Pi2_.ctrl(18) = Slider(slnr+3).value Controller Pi2_.channel, 18, Pi2_.ctrl(18) END IF IF Pi2_.ctrl(15) <> Slider(slnr+5).value THEN ' wave shape Pi2_.ctrl(15) = Slider(slnr+5).value Controller Pi2_.channel, 15, Pi2_.ctrl(15) END IF IF ISFALSE oldnote THEN mPlay Pi2_.channel,i%, Slider(slnr).value oldnote = i% INCR i% IF i% > 101 THEN i% = 72 ' 2Pi range ELSE IF ISFALSE slider(slnr+1).value THEN ' release value (duration) NoteOff Pi2_.channel, oldnote ELSE Release Pi2_.channel, oldnote, slider(slnr+1).value END IF oldnote = %False END IF Task(%Pi2_scale).freq = Slider(slnr-1).value / 8 IF Task(%Pi2_scale).freq < 0.1 THEN Task(%Pi2_scale).freq = 0.1 END SUB SUB Pi2_Lites () ' notes 1 and 2 blue light STATIC slnr AS DWORD STATIC cnt AS BYTE IF ISFALSE Task(%Pi2_lites).tog THEN ' create a parameter window: DIM TaskParamLabels(0) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" IF ISFALSE Task(%Pi2_lites).hParam THEN MakeTaskParameterDialog %Pi2_lites,1,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi2_lites).SliderNumbers(0) Slider(slnr).value = 10 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value END IF Controller Pi2_.channel, 66, 127 Task(%Pi2_lites).tog = %True END IF IF ISFALSE cnt THEN NoteOff Pi2_.channel, 1 mPlay Pi2_.channel,2, 127 ELSE NoteOff Pi2_.channel,2 mPlay Pi2_.channel, 1, 127 END IF INCR cnt IF cnt > 1 THEN cnt = %False Task(%Pi2_lites).freq = Slider(slnr).value / 8 IF Task(%Pi2_lites).freq < 0.1 THEN Task(%Pi2_lites).freq = 0.1 END SUB SUB Pi2_Test () ' tests repeated notes. ' parameters: repetition rate ' push-time ' release-time ' note STATIC slnr AS DWORD STATIC i,j AS INTEGER LOCAL onoff AS SINGLE LOCAL period AS SINGLE IF ISFALSE Task(%Pi2_Test).tog THEN DIM TaskParamLabels(0 TO 4) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" ' repeat rate TaskParamlabels(1) = "On/Off" ' puls-pause proportion TaskParamlabels(2) = "velo" TaskParamlabels(3) = "release" TaskParamLabels(4) = "Note" ' note IF ISFALSE Task(%Pi2_Test).hParam THEN slnr = %False MakeTaskParameterDialog %Pi2_Test,4,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi2_Test).SliderNumbers(0) UDctrl(TaskEX(%Pi2_Test).UpdownNumbers(0)).cptr = CODEPTR(Pi2_Note_UD1) i = 72 UDctrl(TaskEX(%Pi2_Test).UpDownNumbers(0)).value = i Task(%Pi2_Test).freq = 2 Slider(slnr).value = Task(%Pi2_Test).freq SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 64 SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, 64 ' mid position END IF j = %False Controller Pi2_.channel, 66, 64 Task(%Pi2_Test).tog = %True EXIT SUB END IF OnOff = Slider(slnr+1).value / 128 ' 0- 0.99218 IF OnOff < 0.0078 THEN OnOff = 0.0078125 period = 1! / (32! * ((Slider(slnr).value+1) / 128!)) ' tempo - duur in sekonden. IF ISFALSE j THEN mPlay Pi2_.channel, i, Slider(slnr+2).value period = period * OnOff ELSE Release Pi2_.channel, i, Slider(slnr+3).value ' allways overrides ctrl #19 i = UDctrl(TaskEX(%Pi2_Test).UpDownNumbers(0)).value period = period * (1! - OnOff) END IF Task(%Pi2_Test).freq = MAX(MIN(1! / period, 1000),1) INCR j j = j MOD 2 END SUB SUB Pi2_Note_UD1 () ' controls the note to be played. LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi2_Test).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < 72 THEN UDctrl(udnr).value = 72 : noot = 72 IF noot > 101 THEN UDctrl(udnr).value = 101 : noot = 101 SetDlgItemText Task(%Pi2_Test).hparam, %GMT_TEXT0_ID + 16, "n=" & STR$(noot) END SUB '---------------------------------------------- SUB Pi3_scale() STATIC i% STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi3_scale).tog THEN i% = 60 '72 ' create a parameter window: DIM TaskParamLabels(6) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamlabels(1) = "Velo" TaskParamlabels(2) = "Release" ' can also be done with ctrl. 19 TaskParamLabels(3) = "Attack" ' duration - ctrl 17 TaskParamLabels(4) = "Decay" ' duration - ctrl 18 TaskParamLabels(5) = "Sustain" ' level - ctrl 7 TaskParamLabels(6) = "Wave" ' ctrl 15 IF ISFALSE Task(%Pi3_scale).hParam THEN MakeTaskParameterDialog %Pi3_scale,7,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi3_scale).SliderNumbers(1) Slider(slnr).value = 80 ' velo SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = %False ' release SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 5 ' attack SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 10 ' decay SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 68 ' sustain SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 48 ' wave SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value END IF Controller Pi3.channel, 66, 127 ' same as Pi Task(%Pi3_scale).tog = %True END IF IF Pi3.ctrl(7) <> Slider(slnr+4).value THEN ' level sustain Pi3.ctrl(7) = Slider(slnr+4).value Controller Pi3.channel, 7, Pi3.ctrl(7) END IF IF Pi3.ctrl(17) <> Slider(slnr+2).value THEN ' attack duration Pi3.ctrl(17) = Slider(slnr+2).value Controller Pi3.channel, 17, Pi3.ctrl(17) END IF IF Pi3.ctrl(18) <> Slider(slnr+3).value THEN ' decay duration Pi3.ctrl(18) = Slider(slnr+3).value Controller Pi3.channel, 18, Pi3.ctrl(18) END IF IF Pi3.ctrl(15) <> Slider(slnr+5).value THEN ' wave shape Pi3.ctrl(15) = Slider(slnr+5).value Controller Pi3.channel, 15, Pi3.ctrl(15) END IF IF ISFALSE oldnote THEN mPlay Pi3.channel,i%, Slider(slnr).value oldnote = i% INCR i% IF i% > 89 THEN i% = 60 ' 3Pi range ELSE IF ISFALSE slider(slnr+1).value THEN ' release value (duration) NoteOff Pi3.channel, oldnote ELSE Release Pi3.channel, oldnote, slider(slnr+1).value END IF oldnote = %False END IF Task(%Pi3_scale).freq = Slider(slnr-1).value / 8 IF Task(%Pi3_scale).freq < 0.1 THEN Task(%Pi3_scale).freq = 0.1 END SUB SUB Pi3_Test () ' tests repeated notes. ' parameters: repetition rate ' push-time ' release-time ' note STATIC slnr AS DWORD STATIC i,j AS INTEGER LOCAL onoff AS SINGLE LOCAL period AS SINGLE IF ISFALSE Task(%Pi3_Test).tog THEN DIM TaskParamLabels(0 TO 4) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" ' repeat rate TaskParamlabels(1) = "On/Off" ' puls-pause proportion TaskParamlabels(2) = "velo" TaskParamlabels(3) = "release" TaskParamLabels(4) = "Note" ' note IF ISFALSE Task(%Pi3_Test).hParam THEN slnr = %False MakeTaskParameterDialog %Pi3_Test,4,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi3_Test).SliderNumbers(0) UDctrl(TaskEX(%Pi3_Test).UpdownNumbers(0)).cptr = CODEPTR(Pi3_Note_UD1) i = 60 UDctrl(TaskEX(%Pi3_Test).UpDownNumbers(0)).value = i Task(%Pi3_Test).freq = 2 Slider(slnr).value = Task(%Pi3_Test).freq SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 64 SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, 64 ' mid position END IF j = %False Controller Pi3.channel, 66, 64 Task(%Pi3_Test).tog = %True EXIT SUB END IF OnOff = Slider(slnr+1).value / 128 ' 0- 0.99218 IF OnOff < 0.0078 THEN OnOff = 0.0078125 period = 1! / (32! * ((Slider(slnr).value+1) / 128!)) ' tempo - duur in sekonden. IF ISFALSE j THEN mPlay Pi3.channel, i, Slider(slnr+2).value period = period * OnOff ELSE Release Pi3.channel, i, Slider(slnr+3).value ' allways overrides ctrl #19 i = UDctrl(TaskEX(%Pi3_Test).UpDownNumbers(0)).value period = period * (1! - OnOff) END IF Task(%Pi3_Test).freq = MAX(MIN(1! / period, 1000),1) INCR j j = j MOD 2 END SUB SUB Pi3_Note_UD1 () ' controls the note to be played. LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi3_Test).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < 60 THEN UDctrl(udnr).value = 60 : noot = 60 IF noot > 89 THEN UDctrl(udnr).value = 89 : noot = 89 SetDlgItemText Task(%Pi3_Test).hparam, %GMT_TEXT0_ID + 16, "n=" & STR$(noot) END SUB SUB Pi4_scale() STATIC i% STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi4_scale).tog THEN i% = 43 ' create a parameter window: DIM TaskParamLabels(7) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" TaskParamlabels(1) = "Velo" TaskParamlabels(2) = "Release" ' can also be done with ctrl. 19 TaskParamLabels(3) = "Attack" ' duration - ctrl 17 TaskParamLabels(4) = "Decay" ' duration - ctrl 18 TaskParamLabels(5) = "Sustain" ' level - ctrl 16 TaskParamLabels(6) = "Wave" ' ctrl 15 TaskParamLabels(7) = "Volume" ' ctrl 7 IF ISFALSE Task(%Pi4_scale).hParam THEN MakeTaskParameterDialog %Pi4_scale,8,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_scale).SliderNumbers(1) Slider(slnr).value = 80 ' velo SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = %False ' release SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 5 ' attack SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 10 ' decay SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 68 ' sustain SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 48 ' wave SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value Slider(slnr+6).value = 127 ' volume SendMessage Slider(Slnr+6).h, %TBM_SETPOS,%True, Slider(Slnr+6).value END IF Controller Pi4.channel, 66, 127 Task(%Pi4_scale).tog = %True END IF IF Pi4.ctrl(16) <> Slider(slnr+4).value THEN ' level sustain Pi4.ctrl(16) = Slider(slnr+4).value Controller Pi4.channel, 16, Pi4.ctrl(16) END IF IF Pi4.ctrl(17) <> Slider(slnr+2).value THEN ' attack duration Pi4.ctrl(17) = Slider(slnr+2).value Controller Pi4.channel, 17, Pi4.ctrl(17) END IF IF Pi4.ctrl(18) <> Slider(slnr+3).value THEN ' decay duration Pi4.ctrl(18) = Slider(slnr+3).value Controller Pi4.channel, 18, Pi4.ctrl(18) END IF IF Pi4.ctrl(15) <> Slider(slnr+5).value THEN ' wave shape Pi4.ctrl(15) = Slider(slnr+5).value Controller Pi4.channel, 15, Pi4.ctrl(15) END IF IF Pi4.ctrl(7) <> Slider(slnr+6).value THEN ' global volume, new on Pi4 Pi4.ctrl(7) = Slider(slnr+6).value Controller Pi4.channel, 7, Pi4.ctrl(7) END IF IF ISFALSE oldnote THEN mPlay Pi4.channel,i%, Slider(slnr).value oldnote = i% INCR i% IF i% > 96 THEN i% = 43 ' 4Pi range ELSE IF ISFALSE slider(slnr+1).value THEN ' release value (duration) NoteOff Pi4.channel, oldnote ELSE Release Pi4.channel, oldnote, slider(slnr+1).value END IF oldnote = %False END IF Task(%Pi4_scale).freq = Slider(slnr-1).value / 8 IF Task(%Pi4_scale).freq < 0.1 THEN Task(%Pi4_scale).freq = 0.1 END SUB SUB Pi4_Test () ' tests repeated notes. ' parameters: repetition rate ' push-time ' release-time ' note STATIC slnr AS DWORD STATIC i,j AS INTEGER LOCAL onoff AS SINGLE LOCAL period AS SINGLE IF ISFALSE Task(%Pi4_Test).tog THEN DIM TaskParamLabels(0 TO 4) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" ' repeat rate TaskParamlabels(1) = "On/Off" ' puls-pause proportion TaskParamlabels(2) = "velo" TaskParamlabels(3) = "release" TaskParamLabels(4) = "Note" ' note IF ISFALSE Task(%Pi4_Test).hParam THEN slnr = %False MakeTaskParameterDialog %Pi4_Test,4,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_Test).SliderNumbers(0) UDctrl(TaskEX(%Pi4_Test).UpdownNumbers(0)).cptr = CODEPTR(Pi4_Note_UD1) i = 43 UDctrl(TaskEX(%Pi4_Test).UpDownNumbers(0)).value = i Task(%Pi4_Test).freq = 2 Slider(slnr).value = Task(%Pi4_Test).freq SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 64 SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, 64 ' mid position END IF j = %False Controller Pi4.channel, 66, 64 Task(%Pi4_Test).tog = %True EXIT SUB END IF OnOff = Slider(slnr+1).value / 128 ' 0- 0.99218 IF OnOff < 0.0078 THEN OnOff = 0.0078125 period = 1! / (32! * ((Slider(slnr).value+1) / 128!)) ' tempo - duur in sekonden. IF ISFALSE j THEN mPlay Pi4.channel, i, Slider(slnr+2).value period = period * OnOff ELSE Release Pi4.channel, i, Slider(slnr+3).value ' allways overrides ctrl #19 i = UDctrl(TaskEX(%Pi4_Test).UpDownNumbers(0)).value period = period * (1! - OnOff) END IF Task(%Pi4_Test).freq = MAX(MIN(1! / period, 1000),1) INCR j j = j MOD 2 END SUB SUB Pi4_Note_UD1 () ' controls the note to be played. LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi4_Test).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < 43 THEN UDctrl(udnr).value = 43 : noot = 43 IF noot > 96 THEN UDctrl(udnr).value = 96 : noot = 96 SetDlgItemText Task(%Pi4_Test).hparam, %GMT_TEXT0_ID + 16, "n=" & STR$(noot) END SUB SUB Pi4_params() STATIC i AS INTEGER STATIC oldnote AS INTEGER STATIC slnr, udnr AS DWORD IF ISFALSE Task(%Pi4_Params).tog THEN i = Pi4.lowtes ' create a parameter window: DIM TaskParamLabels(6) AS ASCIIZ * 8 ' 7 sliders TaskParamLabels(0) = "Attack" ' duration - ctrl 17 TaskParamLabels(1) = "Decay" ' duration - ctrl 18 TaskParamLabels(2) = "Sustain" ' level - ctrl 16 TaskParamlabels(3) = "Release" ' duration - ctrl. 19 TaskParamLabels(4) = "Wave" ' ctrl 15 TaskParamLabels(5) = "Noise" ' ctrl 1 TaskParamlabels(6) = "Level" ' ctrl 7 IF ISFALSE Task(%Pi4_Params).hParam THEN MakeTaskParameterDialog %Pi4_params,7,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_params).SliderNumbers(0) Slider(slnr).value = 10 ' attack SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value Slider(slnr+1).value = 6 ' decay SendMessage Slider(Slnr+1).h, %TBM_SETPOS,%True, Slider(Slnr+1).value Slider(slnr+2).value = 64 'sustain - ctrl.16 SendMessage Slider(Slnr+2).h, %TBM_SETPOS,%True, Slider(Slnr+2).value Slider(slnr+3).value = 24 ' release SendMessage Slider(Slnr+3).h, %TBM_SETPOS,%True, Slider(Slnr+3).value Slider(slnr+4).value = 100 ' wave duty cycle SendMessage Slider(Slnr+4).h, %TBM_SETPOS,%True, Slider(Slnr+4).value Slider(slnr+5).value = 8 ' noise jitter SendMessage Slider(Slnr+5).h, %TBM_SETPOS,%True, Slider(Slnr+5).value Slider(slnr+6).value = 127 ' volume = level SendMessage Slider(Slnr+6).h, %TBM_SETPOS,%True, Slider(Slnr+6).value Controller Pi4.channel, 66, 127 ' power ON Pi4.ctrl(66) = 127 END IF Task(%Pi4_params).tog = %True END IF IF ISFALSE Pi4.ctrl(66) THEN Controller Pi4.channel, 66, 127 Pi4.ctrl(66) = 127 END IF IF Pi4.ctrl(17) <> Slider(slnr).value THEN ' attack duration Pi4.ctrl(17) = Slider(slnr).value Controller Pi4.channel, 17, Pi4.ctrl(17) END IF IF Pi4.ctrl(18) <> Slider(slnr+1).value THEN ' decay duration Pi4.ctrl(18) = Slider(slnr+1).value Controller Pi4.channel, 18, Pi4.ctrl(18) END IF IF Pi4.ctrl(16) <> Slider(slnr+2).value THEN ' sustain level Pi4.ctrl(16) = Slider(slnr+2).value Controller Pi4.channel, 16, Pi4.ctrl(16) END IF IF Pi4.ctrl(19) <> Slider(slnr+3).value THEN ' release duration Pi4.ctrl(19) = Slider(slnr+3).value Controller Pi4.channel, 19, Pi4.ctrl(19) END IF IF Pi4.ctrl(15) <> Slider(slnr+4).value THEN ' wave shape Pi4.ctrl(15) = Slider(slnr+4).value Controller Pi4.channel, 15, Pi4.ctrl(15) END IF IF Pi4.ctrl(1) <> Slider(slnr+5).value THEN ' noise Pi4.ctrl(1) = Slider(slnr+5).value Controller Pi4.channel, 1, Pi4.ctrl(1) END IF IF Pi4.ctrl(7) <> Slider(slnr+6).value THEN ' volume Pi4.ctrl(7) = Slider(slnr+6).value Controller Pi4.channel, 7, Pi4.ctrl(7) END IF END SUB SUB Pi4_Lites () ' 29.04.2022 - gwr ' notes 12, 13, 14 STATIC slnr AS DWORD STATIC cnt AS BYTE IF ISFALSE Task(%Pi4_lites).tog THEN ' create a parameter window: DIM TaskParamLabels(0) AS ASCIIZ * 8 TaskParamLabels(0) = "Tempo" IF ISFALSE Task(%Pi4_lites).hParam THEN MakeTaskParameterDialog %Pi4_lites,1,Slider(),0,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_lites).SliderNumbers(0) Slider(slnr).value = 10 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, Slider(Slnr).value END IF IF ISFALSE Pi4.ctrl(66) THEN Controller Pi4.channel, 66, 127 Pi4.ctrl(66) = 127 END IF Task(%Pi4_lites).tog = %True END IF SELECT CASE cnt CASE 0 NoteOff Pi4.channel, 14 NoteOff Pi4.channel, 13 mPlay Pi4.channel,12,127 CASE 1 NoteOff Pi4.channel, 14 NoteOff Pi4.channel, 12 mPlay Pi4.channel,13,127 CASE 2 NoteOff Pi4.channel, 12 NoteOff Pi4.channel, 13 mPlay Pi4.channel,14,127 END SELECT INCR cnt IF cnt > 2 THEN cnt = %False Task(%Pi4_lites).freq = Slider(slnr).value / 8 IF Task(%Pi4_lites).freq < 0.1 THEN Task(%Pi4_lites).freq = 0.1 END SUB SUB Pi4_controlroom () ' 29.04.2022 - for 4Pi, gwr/. LOCAL i AS LONG LOCAL x AS LONG IF ISFALSE hwCtrlpi THEN DIALOG NEW 0, "4Pi_Ctrl",1,1 ,820, 80, %WS_CAPTION OR %WS_POPUP OR %WS_SYSMENU TO hwCtrl4pi x = 5 FOR i = pi4.lowtes TO 108 'pi4.HighTes SELECT CASE (i MOD 12) CASE 0 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "C", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 1 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "C#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 2 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "D", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 3 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "D#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 4 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "E", x, 24, 18, 12, %BS_PUSHLIKE x = x + 20 CASE 5 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "F", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 6 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "F#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 7 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "G", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 8 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "G#", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 9 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "A", x, 24, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 10 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "Bb", x, 12, 18, 12, %BS_PUSHLIKE x = x + 10 CASE 11 CONTROL ADD CHECKBOX, hwCtrl4pi, i, "B", x, 24, 18, 12, %BS_PUSHLIKE x = x + 20 END SELECT NEXT CONTROL ADD LABEL, hwCtrl4pi, 500, "Level:", 5, 45, 30, 12 CONTROL ADD "msctls_trackbar32", hwCtrl4pi, 501, "Level", 36, 45, 135, 12, %WS_CHILD OR %WS_VISIBLE OR %TBS_HORZ OR %TBS_BOTTOM CONTROL ADD LABEL, hwCtrl4pi, 503, "?", 174, 45, 30, 12 CONTROL ADD LABEL, hwCtrl4pi, 510, "Velo:", 5, 60, 30, 12 CONTROL SEND hwCtrl4Pi, 501, %TBM_SETRANGEMAX, %true,127 CONTROL ADD "msctls_trackbar32", hwCtrl4pi, 511, "Velo", 36, 60, 135, 12, %WS_CHILD OR %WS_VISIBLE OR %TBS_HORZ OR %TBS_BOTTOM CONTROL ADD LABEL, hwCtrl4pi, 513, "?", 174, 60, 30, 12 ' control send hwCtrl4Pi, 511, %TBM_SETPOS, %true, 64 CONTROL SEND hwCtrl4Pi, 511, %TBM_SETRANGEMAX, %true,127 CONTROL ADD BUTTON, hwCtrl4pi, 600, "All Off", 206, 45, 30, 12 CONTROL ADD CHECKBOX, hwCtrl4Pi, 610, "CC66", 206, 60, 30, 12, %BS_PUSHLIKE DIALOG SHOW MODELESS hwCtrl4pi CALL CB_Pi4_Controlroom ELSE DIALOG END hwCtrl4pi hwCtrl4pi = 0 END IF END SUB CALLBACK FUNCTION CB_Pi4_Controlroom LOCAL level AS BYTE LOCAL i AS LONG STATIC hTrackWind AS DWORD STATIC hTrackVelo AS DWORD STATIC velo AS BYTE LOCAL note AS BYTE SELECT CASE CBMSG CASE %WM_COMMAND SELECT CASE CBCTL CASE pi4.Lowtes TO 108 'pi4.hightes 'checkboxes CONTROL GET CHECK CBHNDL, CBCTL TO i note = CBCTL mPlay pi4.channel, note, IIF( i, velo, 0) CONTROL SET TEXT gh.cockpit, %GMT_MSG1,"note"+ STR$(note) + STR$(IIF( i, velo, 0) ) CASE 600 FOR i = pi4.lowtes TO 108 'pi4.hightes CONTROL SET CHECK CBHNDL, i, 0 DIALOG DOEVENTS NEXT Controller pi4.channel, 123, %False CASE 610 CONTROL GET CHECK CBHNDL, CBCTL TO i Controller Pi4.channel, 66, i * 127 Pi4.ctrl(66) = i * 127 END SELECT CASE %WM_HSCROLL, %WM_VSCROLL 'note: id doesn't correspond at all with the one given at creation 'more then one slider.. so we have to track which one.. CONTROL HANDLE CBHNDL, 501 TO htrackwind CONTROL HANDLE CBHNDL, 511 TO htrackvelo CONTROL SET TEXT gh.cockpit, %GMT_MSG2, STR$(htrackwind) +STR$(htrackvelo) +STR$(CBLPARAM) IF CBLPARAM = htrackWind THEN IF (LOWRD(CBWPARAM) = %TB_THUMBPOSITION) OR (LOWRD(CBWPARAM) = %TB_THUMBTRACK) THEN level = HIWRD(CBWPARAM) ELSE level = SendMessage (CBLPARAM, %TBM_GETPOS,%Null, %Null) END IF CONTROL SET TEXT CBHNDL, 503, STR$(level) pi4.ctrl(7) = level Controller Pi4.channel, 7, Pi4.ctrl(7) CONTROL SET TEXT gh.cockpit, %GMT_MSG1, "cc7"+ STR$(Pi4.ctrl(7)) ELSEIF CBLPARAM = htrackVelo THEN IF (LOWRD(CBWPARAM) = %TB_THUMBPOSITION) OR (LOWRD(CBWPARAM) = %TB_THUMBTRACK) THEN velo = HIWRD(CBWPARAM) ELSE velo = SendMessage (CBLPARAM, %TBM_GETPOS,%Null, %Null) END IF 'velo = velo * 1.27 CONTROL SET TEXT CBHNDL, 513, STR$(velo) END IF CASE %WM_CLOSE, %WM_QUIT hwCtrl4pi = 0 FOR i = pi4.lowtes TO 108 'pi4.hightes DIALOG DOEVENTS NEXT Controller pi4.channel, 123, %False END SELECT END FUNCTION SUB Pi4_Just () ' test for ctrl 21 EQ or Just intonation tunings ' needs 1 U/D controller for the basenote STATIC slnr, udnr AS DWORD STATIC noot, oldnoot AS INTEGER IF ISFALSE Task(%Pi4_Just).tog THEN DIM TaskParamLabels(0 TO 1) AS ASCIIZ * 8 TaskParamLabels(0) = "---" TaskParamLabels(1) = "Tun" ' note IF ISFALSE Task(%Pi4_Just).hParam THEN slnr = %False MakeTaskParameterDialog %Pi4_Just,1,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_Just).SliderNumbers(0) udnr = TaskEx(%Pi4_Just).UpDownNumbers(0) UDctrl(TaskEX(%Pi4_Just).UpdownNumbers(0)).cptr = CODEPTR(Pi4_Just_UD1) UDctrl(TaskEX(%Pi4_Just).UpDownNumbers(0)).value = 0 Task(%Pi4_Just).freq = 4 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, 0 Pi4.ctrl(21) = 0 ' defaults END IF Controller Pi4.channel, 21, 0 RESET oldnoot Task(%Pi4_Just).tog = %True END IF noot = UDctrl(udnr).value IF noot <> oldnoot THEN oldnoot = noot SELECT CASE noot CASE 0 Controller Pi4.channel, 21, noot Pi4.ctrl(21) = noot CASE 12 TO 23 Controller Pi4.channel, 21, noot Pi4.ctrl(21) = noot END SELECT END IF END SUB SUB Pi4_Just_UD1 () ' controls the base note for just intonation LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi4_Just).UpDownNumbers(0) noot = UDCtrl(udnr).value 'IF noot < 12 THEN UDctrl(udnr).value = 0 : noot = 0 ' resets to EQ IF noot > 23 THEN UDctrl(udnr).value = 23 : noot = 23 SetDlgItemText Task(%Pi4_Just).hparam, %GMT_TEXT0_ID + 16, "JI" & STR$(noot) END SUB SUB Pi4_Just_Stop () Controller Pi4.channel, 21, 0 ' reset to EQ Pi4.ctrl(21) = 0 END SUB SUB Pi4_Pres () ' test for key pressure support ' needs 1 U/D controller for the note STATIC slnr, udnr AS DWORD STATIC noot, oldnoot, oldkp AS INTEGER IF ISFALSE Task(%Pi4_Pres).tog THEN DIM TaskParamLabels(0 TO 1) AS ASCIIZ * 8 TaskParamLabels(0) = "Pres" TaskParamLabels(1) = "Note" ' note IF ISFALSE Task(%Pi4_Pres).hParam THEN slnr = %False MakeTaskParameterDialog %Pi4_Pres,1,Slider(),1,UDctrl(),TaskParamLabels() END IF IF ISFALSE slnr THEN slnr = TaskEX(%Pi4_Pres).SliderNumbers(0) udnr = TaskEx(%Pi4_Pres).UpDownNumbers(0) UDctrl(TaskEX(%Pi4_Pres).UpdownNumbers(0)).cptr = CODEPTR(Pi4_Pres_UD1) UDctrl(TaskEX(%Pi4_Pres).UpDownNumbers(0)).value = Pi4.lowtes Task(%Pi4_Pres).freq = 30 SendMessage Slider(Slnr).h, %TBM_SETPOS,%True, 64 END IF RESET oldnoot RESET oldkp controller Pi4.channel, 123, %False Task(%Pi4_Pres).tog = %True END IF noot = UDctrl(udnr).value IF noot <> oldnoot THEN NoteOff Pi4.channel, oldnoot mPlay Pi4.channel, noot, 127 oldnoot = noot END IF IF oldkp <> Slider(slnr).value THEN oldkp = Slider(slnr).value KeyPress Pi4.channel, noot, Slider(slnr).value END IF END SUB SUB Pi4_Pres_UD1 () ' controls the note for key pressure LOCAL noot AS BYTE LOCAL udnr AS DWORD udnr = TaskEX(%Pi4_Pres).UpDownNumbers(0) noot = UDCtrl(udnr).value IF noot < Pi4.lowtes THEN UDctrl(udnr).value = Pi4.lowtes : noot = Pi4.lowtes IF noot > Pi4.hightes THEN UDctrl(udnr).value = Pi4.hightes : noot = Pi4.hightes SetDlgItemText Task(%Pi4_Pres).hparam, %GMT_TEXT0_ID + 16, "note" & STR$(noot) END SUB ' *************************************************************************** ' 01.08.2022: stukje voor Pi aangepast voor 4Pi: ' 02.08.2022: Min of meer afgewerkt nu... SUB Pi4_Intro () ' 11.03.2017: first coding ' to do: moet versnellen en volumes voor board 2 moeten naar beneden. ' done 12.03.2017 ' should restart at the point it was stopped, so that we can ' use the sounds at different points in the piece. ' 12.03.2017: Now 3 minutes ' 01.08.2022: start adapting to 4Pi ' 02.08.2022: Pi4 steely added. STATIC noot, oldnoot, ofnoot, level, i AS INTEGER STATIC j , rise, fall, nrnotes, init, lite, nv AS INTEGER ' BYTE STATIC tfakt AS SINGLE STATIC cnt, tel AS LONG IF ISFALSE Task(%Pi4_Intro).tog THEN RESET tel Controller Pi4.channel, 66, 83 Controller Pi4.channel, 21, 0 Controller Pi4.channel, 16, 127 '110 Pi4.ctrl(16) = 127 ' sustain Controller Pi4.channel, 17, 12 Controller Pi4.Channel, 18, 4 Controller Pi4.channel, 19, 20 Controller Pi4.channel, 15, 100 Controller Pi4.channel, 1, 2 Pi4.ctrl(7) = 127 Controller Pi4.channel, 7, 127 IF cnt THEN logfile "Pi4 Intro restart at:" & TIME$ & STR$(cnt) END IF Task(%Pi4_Intro).tog = %True END IF ' proc. to make restart possible at the point the task was interrupted IF ISFALSE init THEN RESET cnt RESET tel Pi4.Har(1).vel = NUL$(128) i = 0 oldnoot = 0 noot = Pi4.hightes '108 ofnoot = noot rise = %True fall = %False logfile "Pi4 Intro start at:" & TIME$ & STR$(cnt) IF ISFALSE lite THEN mPlay Pi4.channel, 12, 127 ' blue mPlay Pi4.channel, 13, 127 ' orange lite mPlay Pi4.channel, 14, 127 ' blue lite = %True END IF Task(%Pi4_Intro).freq = 4 ' 24 '32 init = %True END IF ' musical coding: IF noot <> oldnoot THEN Controller Pi4.channel, 16, Pi4.ctrl(16) ' mPlay Pi4.channel, noot, 127 - Pi4.ctrl(16) ' changed for 4Pi mPlay Pi4.channel, noot, 127 oldnoot = noot AddNote2Har Pi4.Har(1), noot, Pi4.ctrl(16) INCR nrnotes INCR tel END IF IF rise = %True THEN INCR i ' i = i + 2 to double speed IF i <= 127 THEN Pi4.ctrl(1) = MIN(MAX(i,0),127) Controller Pi4.channel, 1, Pi4.ctrl(1) ' noise ELSE rise = %False fall = %True END IF END IF IF fall = %True THEN DECR i 'i = i - 2 IF i >= 0 THEN Pi4.ctrl(1) = MIN(MAX(i,0),127) Controller Pi4.channel, 1, Pi4.ctrl(1) ' noise ELSE rise = %True fall = %False DO noot = noot - RND(1,3) ' this is what makes it move! LOOP UNTIL noot < oldnoot IF noot < Pi4.lowtes THEN logfile "Pi4 Intro full stop at :" & TIME$ RESET init stoptask %Pi4_Intro END IF END IF END IF IF nrnotes > 4 THEN nv = GetHighestNote (Pi4.Har(1), Pi4.lowtes, Pi4.hightes) NoteOff Pi4.channel, HIBYT(nv) ',LOBYT(nv) DelNote2Har Pi4.Har(1), HIBYT(nv) DECR nrnotes END IF IF tel < 16 THEN level = 127 - (tel * 3) ' decrescendo ELSE 'level = 82 + (tel - 16) level = 66 + (tel * 1.2) IF level > 127 THEN level = 127 END IF ' ' volume decrescendo in functie van de toonhoogte: ' IF noot > 79 THEN ' ' decrescendo ' ' level = MIN(106 + ((noot - Pi4.lowtes) /2), 126) ' 127 tot 113 ' 'level = 44 + (( noot - 84) *2) ' van 127 naar 44 ' DECR level ' IF level < 82 THEN level = 82 ' ELSE ' ' crescendo ' 'level = 44 + ((1.0 - ((noot- Pi4.lowtes)/ 13.0))* 13.0) ' noot -84: loopt van 13 naar 0 ' ' / 13: loopt van 1 naar 0 ' ' 1 - : loopt van 0 naar 1 ' ' * 13: loopt van 0 naar 13 ' ' to checked for 4Pi ' INCR level ' level = MIN(level, 127) ' END IF IF level <> Pi4.ctrl(16) THEN Pi4.ctrl(16) = level END IF INCR cnt ' accellerando: 'tfakt = 1.0 + (((noot - Pi4.lowtes)/ 65.0) * Pi2) 'tfakt = 1.0 + (((noot - Pi4.lowtes)/ 65.0) * 12) 'tfakt = 1.0 + ((cnt / 8500.0) * 24.0 ) tfakt = 1.0 + ((tel / 30.0) * 24) Task(%Pi4_Intro).freq = 10 * tfakt ' for debug. SetDlgItemText gh.Cockpit, %GMT_MSG1, "Tel= " & STR$(tel) ' cnt loopt tot 8223, 8994 (variabel!) ' tel loopt tot 30, in teorie kan het tot 65 gaan END SUB SUB Pi4_Intro_stop () logfile "Pi4 Intro interrupted at: " & TIME$ controller Pi4.channel, 123, 0 starttask %Pi4_Perc END SUB SUB Pi4_Triads () ' 12.03.2017 ' should play triads where the lowest note makes a downslide ' the highest note an upslide and the middle note always stays stable ' based on - the complete catalogue of different chords, each chord having a different interval ' constellation. Ordering is in increasing level of dissonance. cfr. Belly_Cat in belly testcode ' 13.03.2017: restart bug to be solved. ' 01.08.2022: adapted to 4Pi ' 02.08.2022: there must be a bug, as the sliding pitches are not working... ' we may skip this one for now. ' when this works, it can become a separate demo piece in its own. STATIC i, j, cnt, trans AS LONG STATIC init AS BYTE STATIC tog AS INTEGER STATIC Akk() AS INTEGER STATIC n AS INTEGER STATIC lownote, highnote AS INTEGER 'LOCAL zandloper AS ASCIIZ PTR ' silly !!! (caused by declaration of WinApi) 'LOCAL hCursor AS LONG IF ISFALSE Task(%Pi4_Triads).tog THEN Controller Pi4.channel, 66, %False IF ISFALSE init THEN REDIM Akk(&HFFF) AS STATIC INTEGER ' hCursor = GetCursor () ' zandloper = %IDC_WAIT ' SetCursor LoadCursor (%Null, BYVAL(zandloper)) ' cfr. declaration PB WinApi SortChordsOnDissonance Akk(), &HF33C, 127 ' dll procedure ' parameters: %SortNoIsomorphs OR %SortPsyChord, only chords with 3-notes 'MSGBOX "Chords sorted. Ubound Akk = " & STR$(UBOUND(Akk)) ' 19 chords! as chordnumbers init = %True ' SetCursor hCursor 'EXIT SUB END IF 'Controller Pi4.channel, 123, 0 ' controllers: Controller Pi4.channel, 66, 83 Controller Pi4.channel, 21, 0 controller Pi4.channel, 16, 110 Controller Pi4.channel, 17, 2 Controller Pi4.Channel, 18, 1 Controller Pi4.channel, 19, 10 Controller Pi4.channel, 15, 83 Controller Pi4.channel, 1, 0 Pi4.ctrl(7) = 127 Controller Pi4.channel, 7, Pi4.ctrl(7) RESET cnt tog = 1 logfile "Pi4_Triads start at: " & TIME$ Task(%Pi4_Triads).tog = %True END IF ' now we can start playing the iterated chords... ' and play with the controllers 69-120 IF tog = 1 THEN Task(%Pi4_Triads).Har.vel = STRING$(128,0) ' mPlay all those 19 triads on all possible pipes... ' Akk(cnt) = TransChordNum (Akk(cnt), trans) ' chordnumber transposition ' trans = (trans + 5) MOD 12 AddCnr2Har Task(%Pi4_Triads).Har , Akk(cnt), Pi4.lowtes, 96, 127 ' AddCnr2Har LIB "g_har.dll" (H AS HarmType, BYVAL Cnr%, BYVAL l%, BYVAL h%, BYVAL v%) Pi4.Har(1) = Task(%Pi4_Triads).Har InstrumPlay Pi4 lownote = GetLowestNote (Task(%Pi4_Triads).Har,Pi4.lowtes, Pi4.Hightes) lownote = HIBYT(lownote) highnote = GetHighestNote (Task(%Pi4_Triads).Har, Pi4.lowtes, Pi4.hightes) highnote = HIBYT(Highnote) Controller Pi4.channel, lownote + 24, 64 Pi4.ctrl(lownote + 24) = 64 ' reset Controller Pi4.channel, highnote + 24, 64 Pi4.ctrl(highnote + 24) = 64 INCR cnt RESET tog RESET j ELSE ' slides: Pi4.Har(1).vel = NUL$(128) InstrumPlay Pi4 ' notes off Controller Pi4.Channel, lownote + 24, 64 - j ' send pitch shifts Pi4.ctrl(lownote+24) = 64 - j Controller Pi4.Channel, highnote + 24, 64 + j Pi4.ctrl(highnote+24) = 64 + j Pi4.Har(1) = Task(%Pi4_Triads).Har InstrumPlay Pi4 ' this may not work if the velo's are the same... INCR j IF j >= 63 THEN tog = 1 END IF END IF IF tog = 0 THEN IF cnt > UBOUND(Akk) THEN ' UBOUND(Akk) = 19 IF j >= 63 THEN stoptask %Pi4_Triads EXIT SUB END IF END IF END IF IF tog = 1 THEN Task(%Pi4_Triads).freq = 8 + (cnt/4.0) ELSE Task(%Pi4_Triads).freq = 10.0 + (cnt/4.0) - (j/8.0) ' slowdown to 2 END IF SetDlgItemText gh.Cockpit, %GMT_MSG1, "Count= " & STR$(cnt) IF cnt > UBOUND(Akk) THEN Stoptask %Pi4_Triads ' to make sure it does not restart END IF END SUB SUB Pi4_Triads_Stop () LOCAL i AS BYTE controller Pi4.channel, 123, 0 FOR i = 69 TO 120 Controller Pi4.channel, i, 64 Pi4.ctrl(i) = 64 NEXT i ' starttask %Pi4_Burst END SUB SUB Pi4_Perc () ' 12.03.2017 ' very short clouds of pitches ' needs further refinement. ' 13.03.2017: improved. ' 01.08.2022: works very well on 4Pi. STATIC note, velo, li1, li2 AS INTEGER STATIC t, krono, duur AS LONG STATIC prop AS SINGLE ' normalised 0-1 timer IF ISFALSE Task(%Pi4_Perc).tog THEN Controller Pi4.channel, 16, 6 ' very low sustain Controller Pi4.channel, 17, 2 Controller Pi4.channel, 18, 0 Controller Pi4.channel, 7, 127 velo = 127 t = TimeGetTime ' in ms RESET krono RESET note duur = 40 ' 40 seconds duration Logfile "Pi4_Perc start at " & TIME$ Task(%Pi4_perc).tog = %True END IF IF note THEN noteoff Pi4.channel, note krono = (TimeGetTime - t)/ 1000 ' in seconds prop = krono / duur ' 0-1 IF krono >= duur THEN Logfile "Pi4_Perc stop at " & TIME$ Logfile "Duration was : " & STR$(krono) stoptask %Pi4_Perc EXIT SUB END IF note = RND(Pi4.lowtes,Pi4.hightes) IF note >=Pi4.lowtes THEN mPlay Pi4.channel, note, velo END IF IF RND(1) > prop THEN mPlay Pi4.channel, 12, 127 ' blue LED flashes li1 = 12 ELSE IF li1 THEN NoteOff Pi4.channel, 12 : RESET li1 END IF IF RND(1) > prop THEN mPlay Pi4.channel, 14, 127 ' blue LED flashes li2 = 14 ELSE IF li2 THEN NoteOff Pi4.channel, 14 : RESET li2 END IF 'Task(%Pi4_Perc).freq = 4 + RND(0,64 * prop) Task(%Pi4_Perc).freq = 6 + RND(0,32 * prop) ' denser END SUB SUB Pi4_Perc_Stop () Controller Pi4.channel, 123, 0 ' starttask %Pi4_Triads - skip this one as long as it is not working properly starttask %Pi4_Burst END SUB SUB Pi4_Burst () ' very short clouds of noises ' needs further refinement. ' 01.08.2022: level raised - works well STATIC note, velo, li AS INTEGER STATIC t, krono, duur AS LONG STATIC prop AS SINGLE ' normalised 0-1 timer IF ISFALSE Task(%Pi4_Burst).tog THEN Controller Pi4.channel, 15, 86 Controller Pi4.channel, 16, 110 Controller Pi4.channel, 17, 10 Controller Pi4.channel, 18, 4 Controller Pi4.channel, 19, 64 Controller Pi4.channel, 7, 127 Controller Pi4.channel, 1, 120 ' noise velo = 127 t = TimeGetTime ' in ms RESET krono RESET note duur = 30 ' 30 seconds duration Logfile "Pi4_Burst start at " & TIME$ Task(%Pi4_burst).tog = %True END IF IF note THEN noteoff Pi4.channel, note krono = (TimeGetTime - t)/ 1000 ' in seconds prop = krono / duur ' 0-1 IF krono >= duur THEN Logfile "Pi4_Burst stop at " & TIME$ Logfile "Duration was : " & STR$(krono) stoptask %Pi4_Burst EXIT SUB END IF note = RND(Pi4.lowtes,Pi4.hightes) ' IF note >=Pi4.lowtes THEN mPlay Pi4.channel, note, velo ' END IF IF RND(1) > prop THEN mPlay Pi4.channel, 13, 127 ' orange LED flashes li = 13 ELSE IF li THEN NoteOff Pi4.channel, 13 : RESET li END IF Task(%Pi4_Burst).freq = 2 + RND(1,48 * prop) END SUB SUB Pi4_Burst_Stop () Controller Pi4.channel, 123, 0 starttask %Pi4 ' = Pipi4 END SUB SUB Pipi4 () ' demostukje voor <4Pi> solo ' based on: ' - the complete catalogue of different chords, each chord having a different interval ' constellation. Ordering is in increasing level of dissonance. ' chords are followed by their solutions. ' adapted from Melodrama for Melauton. (06.02.2017) ' adapted to 4Pi, 01.08.2022 ' sliders removed/disabled as they crashed anyway... ' number of chords limited to 48 ' 02.08.2022: steely part added. (optional) STATIC i AS WORD ' akkoordenteller 0-350 STATIC temposlnr, ppslnr, levelslnr, veloslnr AS BYTE STATIC tempo, pupo, level, velo AS INTEGER STATIC Ritmeteller% STATIC init AS BYTE STATIC Akk() AS INTEGER STATIC tc AS INTEGER GLOBAL Mh AS harmtype LOCAL tiks! IF (Task(%Pi4).swit AND %TASK_BUSY) = %d1 THEN EXIT SUB IF ISFALSE init THEN Controller Steely.channel, 30, 110 mPlay Steely.channel, 72, 24 REDIM Akk(0 TO &HFFF) AS STATIC INTEGER SortChordsOnDissonance Akk(), &HFC1C, 127 ' dll procedure ' parameters: %SortNoIsomorphs OR %SortPsyChord ' MSGBOX "Chords sorted. Ubound Akk = " & STR$(UBOUND(Akk)) ' = 350 ' since this takes pretty long, it would be better to save the lookup to a diskfile Controller Pi4.channel, 66, 0 ' power off - reset controllers tempo = 22 pupo = 127 level = 127 velo = 127 SetDlgItemText gh.Cockpit, %GMT_TEXT_TEMPO, STR$(App.tempo) Task(%Pi4).freq = App.tempo / 60! Task(%Pi4).tog = %False Controller Pi4.channel, 66, 65 ' power on init = 255 EXIT SUB END IF '------------------------------------------------- IF ISFALSE Task(%Pi4).tog THEN Task(%Pi4).tog = %True SetDlgItemText gh.Cockpit, %GMT_MSG1, "350 chords and progressions" SetDlgItemText gh.Cockpit, %GMT_TITLE, "Pi4" SetDlgItemText gh.Cockpit, %GMT_AUTHOR, $gwr Controller Pi4.channel, 16, 105 Controller Pi4.channel, 17, 60 Controller Pi4.Channel, 18, 10 Controller Pi4.channel, 19, 110 Controller Pi4.channel, 15, 100 Controller Pi4.channel, 1, 0 Controller Pi4.channel, 7, 127 i = %False ' reset akkoordenteller Controller Steely.channel, 30, %False Controller Steely.channel, 123, %False logfile "'Pi4' starttime = " & TIME$ END IF IF Task(%Pi4).tempo <> tempo THEN 'Slider(temposlnr).value THEN Task(%Pi4).tempo = tempo ' Slider(temposlnr).value IF ISFALSE Task(%Pi4).tempo THEN Task(%Pi4).tempo = %True SetDlgItemText gh.Cockpit, %GMT_TEXT_TEMPO, STR$(Task(%Pi4).tempo) ' tempo display END IF IF ISFALSE Task(%Pi4).Rit.pattern(Ritmeteller%) THEN Ritmeteller% = %False ' select case i ' case < 12 ' Task(%Pi4).Rit.pattern(0)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pi4).Rit.pattern(1)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pi4).Rit.pattern(2)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pi4).Rit.pattern(3)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pi4).Rit.pattern(4)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pi4).Rit.pattern(5)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pi4).Rit.pattern(6)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pi4).Rit.pattern(7)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pi4).Rit.pattern(8)= Slider(ppslnr).value + 1 ' ON time ' Task(%Pi4).Rit.pattern(9)= -(128 - Slider(ppslnr).value) ' OFF time ' Task(%Pi4).Rit.pattern(10)= %False Task(%Pi4).Rit.pattern(0)= (pupo + 1) * 2 '(Slider(ppslnr).value + 1)*2 ' ON time Task(%Pi4).Rit.pattern(1)= pupo + 1 'Slider(ppslnr).value + 1 ' ON time Task(%Pi4).Rit.pattern(2)= pupo + 1 'Slider(ppslnr).value + 1 ' ON time Task(%Pi4).Rit.pattern(3)= pupo + 1 'Slider(ppslnr).value + 1 ' ON time Task(%Pi4).Rit.pattern(4)= pupo + 1 'Slider(ppslnr).value + 1 ' ON time Task(%Pi4).Rit.pattern(5)= -(128 - pupo) ' -(128 - Slider(ppslnr).value) ' OFF time Task(%Pi4).Rit.pattern(6)= %False ' end select END IF tiks! = RitmSigma!(Task(%Pi4).Rit) IF tiks! < 1 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(%Pi4).freq = (tiks! * Task(%Pi4).tempo ) / (60 * ABS(Task(%Pi4).Rit.pattern(Ritmeteller%))) IF Task(%Pi4).Rit.pattern(Ritmeteller%) > 0 THEN SELECT CASE Ritmeteller% CASE %False AddCnr2Har Task(%Pi4).Har, Akk(i) OR &HF000, Pi4.lowtes, Pi4.hightes, velo 'Slider(veloslnr).value ' velo from slider IF tc > 0 THEN TransHarm Task(%Pi4).Har, tc IF tc + 12 <> Pi4.ctrl(21) THEN Controller Pi4.channel, 21, tc + 12 ' set just intonation tuning base Pi4.ctrl(21) = tc + 12 Pi4_Steely tc, 80 ' 110 END IF FillHarType Task(%Pi4).Har , %use_fuzzypsy SetDlgItemText gh.Cockpit, %GMT_MSG1, "Solve "& STR$(i) mH = Task(%Pi4).Har Pi4.Har(1) = Task(%Pi4).Har Instrumplay Pi4 INCR i ' akkoordenteller CASE 1 ' solve the chord Task(%Pi4).har = mH IF tc > 0 THEN TransHarm Task(%Pi4).Har, tc IF tc + 12 <> Pi4.ctrl(21) THEN Controller Pi4.channel, 21, tc + 12 ' set just intonation tuning base Pi4.ctrl(21) = tc + 12 Pi4_Steely tc, 75 ' 100 END IF Task(%Pi4).har.vel = SolveHar$ (Task(%Pi4).Har, -1, 0) Pi4.Har(1) = Task(%Pi4).Har SELECT CASE GetNrNotesInHar (Pi4.Har(1)) CASE 0 Task(%Pi4).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi4.Har(1) Task(%Pi4).Rit.pattern(Ritmeteller%+1)= - Task(%Pi4).Rit.pattern(Ritmeteller%) Task(%Pi4).Rit.pattern(Ritmeteller%+2)= %False InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) CASE ELSE mH = Pi4.Har(1) InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) END SELECT CASE 2 ' further solve step: Task(%Pi4).har = mH IF tc > 0 THEN TransHarm Task(%Pi4).har, tc IF tc + 12 <> Pi4.ctrl(21) THEN Controller Pi4.channel, 21, tc + 12 ' set just intonation tuning base Pi4.ctrl(21) = tc + 12 Pi4_Steely tc, 72 '90 END IF Pi4.Har(1).vel = SolveHar$ (Task(%Pi4).Har, -1, 0) Task(%Pi4).Har = Pi4.Har(1) mH = Pi4.Har(1) SELECT CASE GetNrNotesInHar (Pi4.Har(1)) CASE 0 Task(%Pi4).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi4.Har(1) Task(%Pi4).Rit.pattern(Ritmeteller%+1)= - Task(%Pi4).Rit.pattern(Ritmeteller%) Task(%Pi4).Rit.pattern(Ritmeteller%+2)= %False 'Task(%Pi4).Rit.pattern(Ritmeteller%+1)= %False InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) CASE ELSE mH = Pi4.Har(1) InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) END SELECT CASE 3 ' further solve step: Task(%Pi4).har = mH IF tc > 0 THEN TransHarm Task(%Pi4).har, tc IF tc + 12 <> Pi4.ctrl(21) THEN Controller Pi4.channel, 21, tc + 12 ' set just intonation tuning base Pi4.ctrl(21) = tc + 12 Pi4_Steely tc, 67 END IF Pi4.Har(1).vel = SolveHar$ (Task(%Pi4).Har, -1, 0) Task(%Pi4).Har = Pi4.Har(1) mH = Pi4.Har(1) SELECT CASE GetNrNotesInHar (Pi4.Har(1)) CASE 0 Task(%Pi4).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi4.Har(1) Task(%Pi4).Rit.pattern(Ritmeteller%+1)= - Task(%Pi4).Rit.pattern(Ritmeteller%) Task(%Pi4).Rit.pattern(Ritmeteller%+2)= %False InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) CASE ELSE mH = Pi4.Har(1) InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) END SELECT CASE 4 ' further solve step: Task(%Pi4).har = mH IF tc > 0 THEN TransHarm Task(%Pi4).har, tc IF tc + 12 <> Pi4.ctrl(21) THEN Controller Pi4.channel, 21, tc + 12 ' set just intonation tuning base Pi4.ctrl(21) = tc + 12 Pi4_Steely tc, 60 END IF Pi4.Har(1).vel = SolveHar$ (Task(%Pi4).Har, -1, 0) Task(%Pi4).Har = Pi4.Har(1) mH = Pi4.Har(1) SELECT CASE GetNrNotesInHar (Pi4.Har(1)) CASE 0 Task(%Pi4).Rit.pattern(Ritmeteller%+1)= %False CASE 1 mH = Pi4.Har(1) Task(%Pi4).Rit.pattern(Ritmeteller%+1)= - Task(%Pi4).Rit.pattern(Ritmeteller%) Task(%Pi4).Rit.pattern(Ritmeteller%+2)= %False InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) CASE ELSE mH = Pi4.Har(1) InstrumPlay Pi4 tc = QuestTcHar (Task(%Pi4).Har, 0.3) END SELECT END SELECT ELSEIF Task(%Pi4).Rit.pattern(Ritmeteller%) < 0 THEN ' rust Task(%Pi4).Har.vel = NUL$(128) Pi4.Har(1).vel = NUL$(128) Pi4.Har(0).vel = NUL$(128) Controller Pi4.channel, 123, 0 ' voortijdig einde na akoord 47: IF i = 48 THEN Task(%Pi4_end).Har = mH Stoptask %Pi4 StartTask %Pi4_end END IF ' voor de volledige versie...: IF i > UBOUND(Akk) THEN Task(%Pi4_end).Har = mH Stoptask %Pi4 StartTask %Pi4_end END IF END IF INCR Ritmeteller% IF Pi4.ctrl(7) <> level THEN Controller Pi4.channel, 7, level Pi4.ctrl(7) = level Task(%Pi4).level = level END IF END SUB SUB pi4_ending () ' decrescendo. STATIC tc AS LONG IF ISFALSE Task(%Pi4_end).tog THEN Pi4.ctrl(7) = 127 Controller Pi4.channel, 7, Pi4.ctrl(7) Pi4.har(1) = mH ' mH is global Task(%Pi4).har = mH tc = QuestTcHar (Task(%Pi4).Har, 0.3) InstrumPlay Pi4 Task(%Pi4_end).freq = 4.2 ' so duration will be 30 seconds Task(%Pi4_end).tog = %True END IF DECR Pi4.ctrl(7) INCR Pi4.ctrl(1) Pi4.har(1) = mH Instrumplay Pi4 Pi4_Steely tc+ 12, Pi4.ctrl(7) / 2 IF Pi4.ctrl(1) > 127 THEN Pi4.Ctrl(1) = 127 IF Pi4.ctrl(7) <= 0 THEN Controller Pi4.channel, 123, %False Controller Pi4.channel, 66, %False Controller Steely.channel, 123, %False ' licht uit. logfile "'Pipi4' endtime = " & TIME$ stoptask %Pi4_end ELSE Controller Pi4.channel, 7, Pi4.ctrl(7) Controller Pi4.channel, 1, Pi4.ctrl(1) END IF END SUB SUB Pi4_Steely (BYVAL note AS INTEGER, BYVAL velo AS BYTE) ' 02.08.2022: added as optional extra in the 'Pi four Steely' piece. STATIC oldnoot, led AS INTEGER note = note MOD 24 note = note + 60 IF note < 65 THEN note = note + 12 SELECT CASE note CASE 65,67,69,72,74,77,79,81 ' dit zijn de steely noten mPlay Steely.channel, note, velo oldnoot = note IF led THEN NoteOff Steely.channel, 122 led = %False END IF CASE ELSE IF ISFALSE led THEN mPlay Steely.channel, 122, 127 ' wit licht led = %True END IF IF oldnoot THEN NoteOff Steely.channel, oldnoot oldnoot = %False END IF END SELECT END SUB '[eof]