Transpose with Note Persist (Scriptlet)

There are already many topics about seamless switching. The approach depends on the use case:

  1. For seamless switching of rackspaces while maintaining the held notes there is the built-in MIDI Patch Persist.
  2. For preserving held notes while switching to a different plugin/channel using variations, it’s best to filter the note-ons only in different MIDI In Blocks or even more advanced options.

Still I couldn’t find the one suitable for my specific need concerning transposing:
I sometimes simply need to transpose the MIDI going to one plugin in the middle of the song (for the last chorus, for example). While both the integrated transposer and the MIDI In Blocks send notes off when adjusting the transposition, I need a simple transposer plugin that preserves the held notes.

I created a scriptlet for this case making use of the note tracker functions. It works on all channels and has a simple on/off switch (intended to be linked to a widget) and a transposition slider.

I must admit, after writing the code, I discovered a similar functionality hidden inside this pretty complex gig file (except for multiple channels). I wanted to share it anyways if one wants only this simple functionality.

This is the scriptlet preset:
Transpose with Note Persist.gpp_internal.zip (2.3 KB)

As an alternative, here’s the code:

var
    TransposeSwitch : Discrete Parameter "off", "on" = "off"
    Transpose : Subrange Parameter -64..64 = 7
    Tracker1, Tracker2 : MultiChannelNoteTracker
    NoteNumber, Channel : integer = 0
    
Initialization
    SetDisplayMessage("Preserves notes when switching on/off. Sends all notes off when adjusting transpose.")
    For Channel = 1; Channel <= 16; Channel = Channel+1 do
        MultiChannelNoteTracker_Clear(Tracker1, Channel)
        MultiChannelNoteTracker_Clear(Tracker2, Channel)
    End
End

On NoteEvent(m : NoteMessage)
    NoteNumber = GetNoteNumber(m)
    Channel = GetChannel(m)
    If GetVelocity(m) > 0 then // note-on
        If TransposeSwitch == "off" then
            If MultiChannelNoteTracker_IsNoteOffPending(Tracker1,NoteNumber,Channel) == false then // If this note isn't already registered
                MultiChannelNoteTracker_GotNoteOn(Tracker1,NoteNumber,Channel) // Register it
            End            
            SendNow(m) // Send it
        Else
            If MultiChannelNoteTracker_IsNoteOffPending(Tracker2,NoteNumber+Transpose,Channel) == false then // If this transposed note isn't already registered
                MultiChannelNoteTracker_GotNoteOn(Tracker2,NoteNumber+Transpose,Channel) // Register it
            End
            SendNow(WithTranspose(m,Transpose)) // Send it transposed
        End
    Else // note-off
        If TransposeSwitch == "off" then
            If MultiChannelNoteTracker_IsNoteOffPending(Tracker2,NoteNumber+Transpose,Channel) then // If this transposed note is pending
                SendNow(WithTranspose(m,Transpose)) // Send it transposed
                MultiChannelNoteTracker_GotNoteOff(Tracker2,NoteNumber+Transpose,Channel) // Deregister it
            End
            SendNow(m) // Send it
            MultiChannelNoteTracker_GotNoteOff(Tracker1,NoteNumber,Channel) // Deregister it
        Else 
            If MultiChannelNoteTracker_IsNoteOffPending(Tracker1,NoteNumber,Channel) then // If this note off is pending
                SendNow(m) // Send it
                MultiChannelNoteTracker_GotNoteOff(Tracker1,NoteNumber,Channel) // Deregister it
            End
            SendNow(WithTranspose(m,Transpose)) // Send it transposed
            MultiChannelNoteTracker_GotNoteOff(Tracker2,NoteNumber+Transpose,Channel) // Deregister it
        End
    End
End

On ParameterValueChanged matching Transpose
    For Channel = 1; Channel <= 16; Channel = Channel+1 do
        If MultiChannelNoteTracker_NoteOnCount(Tracker1,Channel) > 0 then
            SendNow(MakeControlChangeMessageEx(123,127,Channel))
            MultiChannelNoteTracker_Clear(Tracker1,Channel)
        End
        If MultiChannelNoteTracker_NoteOnCount(Tracker2,Channel) > 0 then
            SendNow(MakeControlChangeMessageEx(123,127,Channel))
            MultiChannelNoteTracker_Clear(Tracker2,Channel)
        End
    End
End

Rather this one :wink::

Come on, it is not that complex :stuck_out_tongue_winking_eye:

1 Like