ArrayArrayArrayArrayArrayArrayArrayArrayArrayArrayArrayArrayArrayArray
Statistics: Posted by Charlie O. — 13 Oct 2025, 15:34 Statistics: Posted by oli_lab — 12 Oct 2025, 23:57 Statistics: Posted by Charlie O. — 12 Oct 2025, 17:46 Statistics: Posted by oli_lab — 12 Oct 2025, 16:26 Statistics: Posted by Charlie O. — 12 Oct 2025, 14:38 Statistics: Posted by Charlie O. — 12 Oct 2025, 02:59 CODE: Statistics: Posted by oli_lab — 06 Oct 2025, 21:10 Statistics: Posted by Charlie O. — 05 Oct 2025, 14:18 Statistics: Posted by shawnb — 18 Jun 2016, 01:37
i've tested with two midi pedals, sustain and sostenuto together, everything works as expected.
Thank's a lot, a lot, a lot !!
]]>
Neither am I, for sure. That's extremely kind of you to try !
Can you test it and tell us how it goes ?
Olivar
]]>
Neither am I, for sure. That's extremely kind of you to try !
]]>
Olivar
]]>
procedure init;
var i : integer;
for i := 0 to 127 do KeyPressed := 0;
et là ça bloque : "Can't assign "Int64" to array [0..127] of Single" at line 84
]]>
I will try it asap.
]]>// SostenutoSustain//// This script provides true Sostenuto & Sustain and their// corresponding interactions with each other. The goal is// to make them behave like true grand piano middle &// right pedals.//// Sostenuto: Basically holds notes whose dampers were up// at the time the Sostenuto pedal was pressed. They will// sustain until the Sostenuto pedal is released. (CC66)// Other notes will release normally. I.e., some notes hold// and some don't...//// Sustain: All notes are held & dampers are up until the// pedal is released.(CC64)//// In both cases, if keys are being pressed at the time the// pedal is released, they will not be affected - their// dampers are still up.//// CC64 & CC66 are not passed downstream so they wont get// confused with any VSTi logic.//// Parameters:// Channel - Only works on the channel specified here// BlockIfHeld - If a held note is repeated,// this will prevent retrigger of the note//// 6/2016, by shawnb////////////////////////////////////////////////////////// Parameters//////////////////////////////////////////////////////var pMidiIn : Tparameter;var pMidiOut : Tparameter;var pChannel : Tparameter;var pBlockIfHeld : Tparameter;//////////////////////////////////////////////////////// Global Variables//////////////////////////////////////////////////////var iSostPedalPressed : single; // sostenuto pedal statevar iSustPedalPressed : single; // sustain pedal statevar inputIX : integer; // always current record just readvar outputIX : integer; // always current record about to be writtenvar iChannel : single; // holds parameter valuevar iBlockIfHeld : single; // holds parameter valuevar KeyPressed : array [0..127] of Integer; // reflects keyboard statevar MonkeyBar : array [0..127] of integer; // reflects dampers held by sostenuto barvar NoteHeld : array [0..127] of integer; // reflects if note is being heldvar MidiTmp : TMidi; // current midi message buffer//////////////////////////////////////////////////////// initialization procedure//////////////////////////////////////////////////////procedure init;var i : integer;beginpMidiIn := CreateParam('MidiIn',ptMidi);SetIsOutput(pMidiIn,false);pMidiOut := CreateParam('MidiOut',ptMidi);SetIsInput(pMidiOut,false);pChannel := CreateParam('Channel',ptDataField);SetIsOutput(pChannel,false);SetMin(pChannel,1);SetMax(pChannel,16);SetDefaultValue(pChannel,1);pBlockIfHeld := CreateParam('BlockIfHeld',ptDataField);SetIsOutput(pBlockIfHeld,false);SetMin(pBlockIfHeld,0);SetMax(pBlockIfHeld,1);SetDefaultValue(pBlockIfHeld,0);iSostPedalPressed := 0;iSustPedalPressed := 0;inputIX := 0;outputIX := 0;iChannel := 1;iBlockIfHeld := 0;for i := 0 to 127 do KeyPressed[i] := 0;for i := 0 to 127 do MonkeyBar[i] := 0;for i := 0 to 127 do NoteHeld[i] := 0;end;//////////////////////////////////////////////////////// Send_Msg// Just write what's in the buffer...//////////////////////////////////////////////////////procedure Send_Msg;beginSetMidiArrayValue(pMidiOut,outputIX,MidiTmp);outputIX := outputIX + 1;end;//////////////////////////////////////////////////////// Send_Note_Off//////////////////////////////////////////////////////procedure Send_Note_Off(note:integer);beginMidiTmp.Channel := trunc(iChannel);MIdiTmp.Msg := 128;MIdiTmp.Data1 := note;MIdiTmp.Data2 := 0;SetMidiArrayValue(pMidiOut,outputIX,MidiTmp);outputIX := outputIX + 1;end;//////////////////////////////////////////////////////// Sost_Press//////////////////////////////////////////////////////procedure Sost_Press;var i : integer;beginfor i := 0 to 127 do beginif (KeyPressed[i]= 1) or (iSustPedalPressed = 1) thenMonkeyBar[i]:= 1;end;end;//////////////////////////////////////////////////////// Sost_Release//////////////////////////////////////////////////////procedure Sost_Release;var i,j : integer;beginfor i := 0 to 127 do beginif (KeyPressed [i]= 0) and (iSustPedalPressed = 0) and (NoteHeld [i]= 1) then beginSend_Note_Off(i);NoteHeld[i] := 0;end;MonkeyBar [i]:= 0;end;end;//////////////////////////////////////////////////////// Sost_Pedal// Trigger pressed or released logic when CC values change// Note no Send_Msg, as we eat all CC64 & CC66 Msgs// so downstream VSTis don't get confused...//////////////////////////////////////////////////////procedure Sost_Pedal;beginif iSostPedalPressed = 0 then beginif MidiTmp.Data2 > 63 then beginSost_Press;iSostPedalPressed := 1;end;endelse beginif MidiTmp.Data2 <= 63 then beginSost_Release;iSostPedalPressed := 0;end;end;end;//////////////////////////////////////////////////////// Sust_Release// Release held notes//////////////////////////////////////////////////////procedure Sust_Release;var i : integer;beginfor i := 0 to 127 do beginif (KeyPressed[i] = 0) and (MonkeyBar[i] = 0) and (NoteHeld[i] = 1) then beginSend_Note_Off(i);NoteHeld[i] := 0;end;end;end;//////////////////////////////////////////////////////// Sust_Pedal// Trigger pressed or released logic when CC values change// Note no Send_Msg, as we eat all CC64 & CC66 Msgs// so downstream VSTis don't get confused...//////////////////////////////////////////////////////procedure Sust_Pedal;beginif iSustPedalPressed = 0 then beginif MidiTmp.Data2 > 63 then beginiSustPedalPressed := 1;end;endelse beginif MidiTmp.Data2 <= 63 then beginSust_Release;iSustPedalPressed := 0;end;end;end;//////////////////////////////////////////////////////// Note_On//////////////////////////////////////////////////////procedure Note_On;begin// Maintain picture of actual keyboard...KeyPressed[MidiTmp.Data1] := 1;// Honor iBlockIfHeld... Only pass note on if appropriateif (iBlockIfHeld = 0) or (NoteHeld[MidiTmp.Data1] = 0) thenSend_Msg;end;//////////////////////////////////////////////////////// Note_Off//////////////////////////////////////////////////////procedure Note_Off;begin// Maintain picture of actual keyboard...KeyPressed[MidiTmp.Data1] := 0;// Pass note off Msg if note is not sustained...if (MonkeyBar[MidiTmp.Data1] = 0) and (iSustPedalPressed = 0) then beginSend_Msg;endelse begin// Note is being sustained, flag in NoteHeld.// Note that you've eaten the 'Note Off'// by not doing a Send_MsgNoteHeld[MidiTmp.Data1] := 1;end;end;//////////////////////////////////////////////////////// Do_My_Channel//////////////////////////////////////////////////////procedure Do_My_Channel;beginif MidiTmp.Msg = 144 then Note_Onelse if MidiTmp.Msg = 128 then Note_Offelse if (MidiTmp.Msg = 176) and (MidiTmp.Data1 = 64) then Sust_Pedalelse if (MidiTmp.Msg = 176) and (MidiTmp.Data1 = 66) then Sost_Pedalelse Send_Msg; // pass everything elseend;//////////////////////////////////////////////////////// DoMidiProc//////////////////////////////////////////////////////procedure DoMidiProc;var len : integer;beginoutputIX := 0;len := GetLength(pMidiIn);if len > 0 then beginfor inputIX := 0 to len-1 do beginGetMidiArrayValue(pMidiIn, inputIX, MidiTmp);// Only work on selected channel, pass everything else thruif MidiTmp.Channel = iChannel thenDo_My_ChannelelseSend_Msg;end;end;// Always properly close out the midi output stream...SetLength(pMidiOut,outputIX);end;//////////////////////////////////////////////////////// Main procedure//////////////////////////////////////////////////////procedure Process;begin//Do it all in the Callback...end;//////////////////////////////////////////////////////// Callback//////////////////////////////////////////////////////Procedure Callback(n:integer);begincase n ofpMidiIn : DoMidiProc;pChannel : iChannel := GetValue(n);pBlockIfHeld : iBlockIfHeld := GetValue(n);end;end
]]>
Or even better as a script ?
Thank's a lot !
]]>
I dropped the SostenutoSustain.fastscript into my patch but I can't get it to work.
Can someone tell me how to set this up?
Thanks.
Input is all MIDI traffic, including notes and pedal messages for sostenuto (CC66) & sustain (CC64).
Send the output to your sound module/VSTi.
This module interprets the pedal messages for you, and will sustain notes by eating Note OFF messages. The Note OFFs will be sent when the appropriate pedal is released.
CC64 and CC66 messages are not passed downstream, as this may confuse your VSTi (if it has similar logic).
Make sure to specify your MIDI channel; this is an input parameter which defaults to channel 1.
Hope this helps. Any further questions let me know,
]]>
Statistics: Posted by shawnb — 04 Jun 2016, 22:15
Statistics: Posted by nay-seven — 04 Jun 2016, 21:08
Statistics: Posted by shawnb — 04 Jun 2016, 19:11
Statistics: Posted by shawnb — 04 Jun 2016, 19:05
Statistics: Posted by Charlie O. — 13 Oct 2025, 15:34
Statistics: Posted by oli_lab — 12 Oct 2025, 23:57
Statistics: Posted by Charlie O. — 12 Oct 2025, 17:46
Statistics: Posted by oli_lab — 12 Oct 2025, 16:26
Statistics: Posted by Charlie O. — 12 Oct 2025, 14:38
Statistics: Posted by Charlie O. — 12 Oct 2025, 02:59
CODE:
// SostenutoSustain//// This script provides true Sostenuto & Sustain and their// corresponding interactions with each other. The goal is// to make them behave like true grand piano middle &// right pedals.//// Sostenuto: Basically holds notes whose dampers were up// at the time the Sostenuto pedal was pressed. They will// sustain until the Sostenuto pedal is released. (CC66)// Other notes will release normally. I.e., some notes hold// and some don't...//// Sustain: All notes are held & dampers are up until the// pedal is released.(CC64)//// In both cases, if keys are being pressed at the time the// pedal is released, they will not be affected - their// dampers are still up.//// CC64 & CC66 are not passed downstream so they wont get// confused with any VSTi logic.//// Parameters:// Channel - Only works on the channel specified here// BlockIfHeld - If a held note is repeated,// this will prevent retrigger of the note//// 6/2016, by shawnb////////////////////////////////////////////////////////// Parameters//////////////////////////////////////////////////////var pMidiIn : Tparameter;var pMidiOut : Tparameter;var pChannel : Tparameter;var pBlockIfHeld : Tparameter;//////////////////////////////////////////////////////// Global Variables//////////////////////////////////////////////////////var iSostPedalPressed : single; // sostenuto pedal statevar iSustPedalPressed : single; // sustain pedal statevar inputIX : integer; // always current record just readvar outputIX : integer; // always current record about to be writtenvar iChannel : single; // holds parameter valuevar iBlockIfHeld : single; // holds parameter valuevar KeyPressed : array [0..127] of Integer; // reflects keyboard statevar MonkeyBar : array [0..127] of integer; // reflects dampers held by sostenuto barvar NoteHeld : array [0..127] of integer; // reflects if note is being heldvar MidiTmp : TMidi; // current midi message buffer//////////////////////////////////////////////////////// initialization procedure//////////////////////////////////////////////////////procedure init;var i : integer;beginpMidiIn := CreateParam('MidiIn',ptMidi);SetIsOutput(pMidiIn,false);pMidiOut := CreateParam('MidiOut',ptMidi);SetIsInput(pMidiOut,false);pChannel := CreateParam('Channel',ptDataField);SetIsOutput(pChannel,false);SetMin(pChannel,1);SetMax(pChannel,16);SetDefaultValue(pChannel,1);pBlockIfHeld := CreateParam('BlockIfHeld',ptDataField);SetIsOutput(pBlockIfHeld,false);SetMin(pBlockIfHeld,0);SetMax(pBlockIfHeld,1);SetDefaultValue(pBlockIfHeld,0);iSostPedalPressed := 0;iSustPedalPressed := 0;inputIX := 0;outputIX := 0;iChannel := 1;iBlockIfHeld := 0;for i := 0 to 127 do KeyPressed[i] := 0;for i := 0 to 127 do MonkeyBar[i] := 0;for i := 0 to 127 do NoteHeld[i] := 0;end;//////////////////////////////////////////////////////// Send_Msg// Just write what's in the buffer...//////////////////////////////////////////////////////procedure Send_Msg;beginSetMidiArrayValue(pMidiOut,outputIX,MidiTmp);outputIX := outputIX + 1;end;//////////////////////////////////////////////////////// Send_Note_Off//////////////////////////////////////////////////////procedure Send_Note_Off(note:integer);beginMidiTmp.Channel := trunc(iChannel);MIdiTmp.Msg := 128;MIdiTmp.Data1 := note;MIdiTmp.Data2 := 0;SetMidiArrayValue(pMidiOut,outputIX,MidiTmp);outputIX := outputIX + 1;end;//////////////////////////////////////////////////////// Sost_Press//////////////////////////////////////////////////////procedure Sost_Press;var i : integer;beginfor i := 0 to 127 do beginif (KeyPressed[i]= 1) or (iSustPedalPressed = 1) thenMonkeyBar[i]:= 1;end;end;//////////////////////////////////////////////////////// Sost_Release//////////////////////////////////////////////////////procedure Sost_Release;var i,j : integer;beginfor i := 0 to 127 do beginif (KeyPressed [i]= 0) and (iSustPedalPressed = 0) and (NoteHeld [i]= 1) then beginSend_Note_Off(i);NoteHeld[i] := 0;end;MonkeyBar [i]:= 0;end;end;//////////////////////////////////////////////////////// Sost_Pedal// Trigger pressed or released logic when CC values change// Note no Send_Msg, as we eat all CC64 & CC66 Msgs// so downstream VSTis don't get confused...//////////////////////////////////////////////////////procedure Sost_Pedal;beginif iSostPedalPressed = 0 then beginif MidiTmp.Data2 > 63 then beginSost_Press;iSostPedalPressed := 1;end;endelse beginif MidiTmp.Data2 <= 63 then beginSost_Release;iSostPedalPressed := 0;end;end;end;//////////////////////////////////////////////////////// Sust_Release// Release held notes//////////////////////////////////////////////////////procedure Sust_Release;var i : integer;beginfor i := 0 to 127 do beginif (KeyPressed[i] = 0) and (MonkeyBar[i] = 0) and (NoteHeld[i] = 1) then beginSend_Note_Off(i);NoteHeld[i] := 0;end;end;end;//////////////////////////////////////////////////////// Sust_Pedal// Trigger pressed or released logic when CC values change// Note no Send_Msg, as we eat all CC64 & CC66 Msgs// so downstream VSTis don't get confused...//////////////////////////////////////////////////////procedure Sust_Pedal;beginif iSustPedalPressed = 0 then beginif MidiTmp.Data2 > 63 then beginiSustPedalPressed := 1;end;endelse beginif MidiTmp.Data2 <= 63 then beginSust_Release;iSustPedalPressed := 0;end;end;end;//////////////////////////////////////////////////////// Note_On//////////////////////////////////////////////////////procedure Note_On;begin// Maintain picture of actual keyboard...KeyPressed[MidiTmp.Data1] := 1;// Honor iBlockIfHeld... Only pass note on if appropriateif (iBlockIfHeld = 0) or (NoteHeld[MidiTmp.Data1] = 0) thenSend_Msg;end;//////////////////////////////////////////////////////// Note_Off//////////////////////////////////////////////////////procedure Note_Off;begin// Maintain picture of actual keyboard...KeyPressed[MidiTmp.Data1] := 0;// Pass note off Msg if note is not sustained...if (MonkeyBar[MidiTmp.Data1] = 0) and (iSustPedalPressed = 0) then beginSend_Msg;endelse begin// Note is being sustained, flag in NoteHeld.// Note that you've eaten the 'Note Off'// by not doing a Send_MsgNoteHeld[MidiTmp.Data1] := 1;end;end;//////////////////////////////////////////////////////// Do_My_Channel//////////////////////////////////////////////////////procedure Do_My_Channel;beginif MidiTmp.Msg = 144 then Note_Onelse if MidiTmp.Msg = 128 then Note_Offelse if (MidiTmp.Msg = 176) and (MidiTmp.Data1 = 64) then Sust_Pedalelse if (MidiTmp.Msg = 176) and (MidiTmp.Data1 = 66) then Sost_Pedalelse Send_Msg; // pass everything elseend;//////////////////////////////////////////////////////// DoMidiProc//////////////////////////////////////////////////////procedure DoMidiProc;var len : integer;beginoutputIX := 0;len := GetLength(pMidiIn);if len > 0 then beginfor inputIX := 0 to len-1 do beginGetMidiArrayValue(pMidiIn, inputIX, MidiTmp);// Only work on selected channel, pass everything else thruif MidiTmp.Channel = iChannel thenDo_My_ChannelelseSend_Msg;end;end;// Always properly close out the midi output stream...SetLength(pMidiOut,outputIX);end;//////////////////////////////////////////////////////// Main procedure//////////////////////////////////////////////////////procedure Process;begin//Do it all in the Callback...end;//////////////////////////////////////////////////////// Callback//////////////////////////////////////////////////////Procedure Callback(n:integer);begincase n ofpMidiIn : DoMidiProc;pChannel : iChannel := GetValue(n);pBlockIfHeld : iBlockIfHeld := GetValue(n);end;endStatistics: Posted by oli_lab — 06 Oct 2025, 21:10
Statistics: Posted by Charlie O. — 05 Oct 2025, 14:18
Statistics: Posted by shawnb — 18 Jun 2016, 01:37
Statistics: Posted by shawnb — 04 Jun 2016, 22:15
Statistics: Posted by nay-seven — 04 Jun 2016, 21:08
Statistics: Posted by shawnb — 04 Jun 2016, 19:11
Statistics: Posted by shawnb — 04 Jun 2016, 19:05