SendLater not available in gig scripts?

I need to modify messages sent by a hardware controller, so that that is instead of

key is pressed CC goes with value 127
key is released CC goes with value 0

I get something like

key is pressed nothing happens
key is released 2 CCs go with values 127 and 0

It’s easy to do except the messages are fired almost simultaneously, so some plugins don’t process them correctly. So I need a slight delay of a few milliseconds.

All of this is happening in a gig script that intercepts messages from a hardware controller and rewrites them

My first instinct was to use SendLater but it doesn’t work - during compiling I get an error saying it’s an unrecognized command.

So is this function not available in gig scripts or am I missing something?

Thanks!

I think SendNow and SendLater are for use in Scriplets and Rackspace scripts only. It sends a message to a block, which you’d need to define as a variable----but you can’t define that kind of variable in a gig script.

Ouch… :frowning:

Well, thanks for your reply anyway!

If the plugins are receiving the CC’s from a MIDI In Block, you can intercept the messages in the rackspaces themselves and then SendLater will work for you.

Rack scripts won’t work because the script is rewriting input from a footswitch, changing what it controls. Racks change, footswitch is the same.

Perhaps someone else will have a solution. My powers of ‘oracling’ are limited. :slight_smile:

What controller are you using?
Why do you need this different behavior of CC messages?

I use iRig Bluboard on this case as a footswitch

But the controller doesn’t matter

I’m trying to solve the same problem I raised in another thread - creating controller “banks” so that a limited number of buttons can control many different things. This particular script switches banks on long press, and I either change song parts (which I use as presets) or control loopers.

It all works except one problem - when I initiate the long press, it goes through. Say my bank 1 CC is 20, bank 2 is 115. So when I do a long press, I get CC20 127 and then CC 115 0.

None of these messages are needed really because a long press isn’t meant to send anything, it’s just switching “banks”. The last one is easy to filter out, but the first one I’m struggling with - the script doesn’t know whether the press willl be long or not when it starts.

So my idea is to not any of the messages go out until the key is released. And then when the key is up, send both 127 and 0 values one after another. That’s also easy but I need a small delay between these events.

Here’s the script in case someone’s interested

Const
    CCA: Integer = 20 //Footswitch button A
    CCB: Integer = 21 //Footswitch button B
    CCC: Integer = 22 //Footswitch button C
    CCD: Integer = 23 //Footswitch button D
    
    FSChan: Integer = 1 //Footswitch MIDI channel

    BankUpCCA: Integer = 115 //CC# for bank up button A
    BankUpCCB: Integer = 116 //CC# for bank up button B
    BankUpCCC: Integer = 117 //CC# for bank up button C
    BankUpCCD: Integer = 118 //CC# for bank up button D
    
    BankUpChannel: Integer = 16 //MIDI channel for bank up
    
    ControlCC: Integer = 127 //CC# to send to notify racks for bank change
    
    LPSidle: Integer = 0 //status before long press is registered
    LPSover: Integer = 1 //status after long press is registered
    LongTime: Integer = 1000 //time to wait to register long press

Var
    SWITCH: MidiInDevice //Rig Manager alias for the footswitch
    SWITCHOUT: String = "iRig BlueBoard Bluetooth" //text name of the footswitch to blink LEDs

    LongPress: Ramp //timer for the footswitch
    LongPressState: Integer = LPSidle //initialization of status
    
    IsBankUp: Boolean = false //initialization of bank up or down flag

    LEDOn: Ramp //timer for LED blinking

Function BlinkFS (time: Integer) //this function blinks LEDs when bank change happens

    SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCA, 127, FSChan)) //turning LEDs on
    SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCB, 127, FSChan))
    SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCC, 127, FSChan))
    SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCD, 127, FSChan))
    TriggerOneShotRamp(LEDOn, time, 10) //starting timer

End
    
On ControlChangeEvent (m: ControlChangeMessage) from SWITCH //intercepting key presses

    Var
        OldCC: Integer = GetCCNumber(m)
        OldValue: Integer = GetCCValue(m)
        OldChannel: Integer = GetChannel(m)
   
    If OldValue > 64 Then //detecting button down
        
        LongPressState = LPSidle
        TriggerOneShotRamp(LongPress, LongTime, 10) //starting timer when the button goes down
        
    Else
        StopOneShotRamp(LongPress)
    End
    Print("lps is " + LongPressState)
    If IsBankUp == true And LongPressState == LPSidle Then //checking if the upper bank is on to rewrite messages
        Select
            OldCC == CCA Do
                InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(BankUpCCA, OldValue, BankUpChannel)) //reassigning to new channel and CC#
            OldCC == CCB Do
                InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(BankUpCCB, OldValue, BankUpChannel))
            OldCC == CCC Do
                InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(BankUpCCC, OldValue, BankUpChannel))
            OldCC == CCD Do
                InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(BankUpCCD, OldValue, BankUpChannel))
        End
    Else
        If LongPressState == LPSidle Then
            Print("lps idle and in long press is, injecting original message")
            InjectMidiEventViaRigManager (SWITCH, m) //if no reassignment is needed, sending the message as is
        Else
            Print("lps not idle, suppressing original message")
        End
    End

End


On GeneratorEndCycle (timeX: Integer) from LongPress //checking the timer, changing state, blinking LEDs to indicate bank change 
    Print("long cycle end event triggered")
    If LongPressState == LPSidle Then
        LongPressState = LPSover //changing state if button is pressed for long enough 
        Print("changing state to over" + LongPressState)
        If IsBankUp == false Then
            BlinkFS (200) //blinking LEDs long
        Else
            BlinkFS (15) //blinking LEDs short
        End
    Else
        StopOneShotRamp(LongPress)
        LongPressState = LPSidle
        Print("changing state to idle" + LongPressState)
    End
End

On GeneratorEndCycle (timeX: Integer) from LEDOn //turning LEDs off, sending control message to racks, toggling bank flag 

       SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCA, 0, FSChan))
       SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCB, 0, FSChan))
       SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCC, 0, FSChan))
       SendNowToMidiOutDevice (SWITCHOUT, MakeControlChangeMessageEx(CCD, 0, FSChan))

       If IsBankUp == false Then
            InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(ControlCC, 127, BankUpChannel)) //sending control message
            //BlinkFS (500) //blinking LEDs long
            Notify("Footswitch Bank 2")
       Else
            InjectMidiEventViaRigManager (SWITCH, MakeControlChangeMessageEx(ControlCC, 0, BankUpChannel))
            Notify("Footswitch Bank 1")
            //BlinkFS (15) //blinking LEDs short
       End
       IsBankUp = !IsBankUp //changing bank flag

End
    
// Called when you switch to another song
On Song(oldSongIndex : integer, newSongIndex : integer)
    OSC_SendStringSpecific("/GP/Song", GetSongName(newSongIndex), "127.0.0.1", OSC_GetGPListeningPort())
End

I suppose you could you could use a Ramp function generator with a TriggerOneShotRamp call and respond to OnGeneratorEndCycle but you’d have to do your own buffering

I thought about it, but wanted to avoid, this whole Ramp thing is a bit cumbersome to do to inject a 5ms delay :slight_smile:

Also I read somewhere that the OnGeneratorEndCycle event isn’t realtime, which would delay triggering what I need to do with the footswitch