Intentional mid lag to smooth pitch bend or breath controller

Here is a scriptlet that may be what you are looking for. It provides an exponential output from the incoming MIDI CC message. Using the defaults will allow this to just be inserted into the midi input chain to the VST.

image

var
    delay ("Delay/Lag") : Subrange Parameter 0..127 = 0;
    cc_input ("Input from CC#") :  Subrange Parameter 0..127 = 2    // Breath controller input
    cc_coarse ("Output coarse CC#") : Subrange Parameter 0..127 = 2 // Breath controller coarse
    cc_fine ("Output fine CC#") : Subrange Parameter 0..127 = 0     // Breath controller fine

    filter : double = 0.0
    ratio : double = 0.0
    target : integer = 0
    
Initialization
    SetInfoMessage("Delay/Lag a CC message from an input CC message to an output CC message. " +
        "The output message can be a MIDI 7 or 14 bit value defined as coarse and fine messages. " +
        "For 7 bit only messages, the fine output should be set to zero." )
    SetDisplayMessage("Delay/Lag v1.00 - @Spav")

    // Set the filter ratio
    ratio = (128.0 - delay) / 128.0
    SetTimersRunning(true)
End

// Called when a parameter value has changed
On ParameterValueChanged matching delay
    ratio = (128.0 - delay) / 128.0
    //Print("Ratio " + ratio)
End

//Called when a CC message is received
On ControlChangeEvent(m : ControlChangeMessage)
    
    // Check the CC input is the assigned one
    If cc_input <> 0 and cc_input == GetCCNumber(m) then
        target = GetCCValue(m)
        target = target + (target << 7)
        //Print("Target " + target)
        
    End
End

// Run Delay/Lag Processing
var lastF : integer = -1
    lastMs : double = 0
On TimerTick(ms : double)    
    var f : integer
    
    if ms > (lastMs + 1.0) then
        lastMs = ms
        
        filter = filter - (filter * ratio)
        if filter < 0 then 
            filter = 0 
        end
    
        filter = filter + (IntToFloat(target) * ratio)        
        f = Round(filter)

        if lastF <> target then

            // Only send midi messages when the value changes 
            if lastF <> f then
                if cc_fine <> 0 then
                    SendNow(MakeControlChangeMessage(cc_fine,(f and 0x7F)))
                end
            
                if (cc_coarse <> 0) and (lastF >> 7) <> (f >> 7) then 
                    SendNow(MakeControlChangeMessage(cc_coarse,(f >> 7))) 
                end
                lastF = f
            end
        end
        //Print("Input "+ms)
    end
End

filtered control .zip (1013 Bytes)

To use this, add a scriptlet to the rackspace and load the script above.

The plugin has four parameters, they should be fairly self explanatory. The default values are already defined for MIDI breath controllers. The output can be sent to other CC# pairs.

image

This is the test rackspace I used. From the knob widgets you can set the four parameters of the scriplet. The slider allows me to send test data. Practically just the delay widget should be the only one required.

I added a switch to the test to apply a change of 5 to mimic a small step change the monitor output shows the intervening steps being applied. However the filtering is limited to the On TickTimer callback, this seems to be 100mS on my PC.

2 Likes