How to use MIDI translator to quantize MIDI inputs for looper functionality

Hello,

Completely new to Bome MIDI Translator here but I need help with this specific usage. I use FL Studio in it’s performance mode for what will be my eventual live setup. It works perfectly for what I need it to do, however in my setup I also have a guitar with a MIDI pickup allowing me to play whatever VST instruments I have in FL Studio. I want to be able to have the ability to live loop these instruments, as well as the guitar’s output, with a looper VST. But I’ve encountered many problems finding something that meets my needs which are: 1) I play music in a variety of odd & switching time signatures. Most VST live loopers seem to not sync properly to the grid of FL in these odd groupings thinking that the pulse it’s receiving is in 4/4 causing it to start and stop at random times, since it seems to only process bar quantization and not via smaller subdivisions (in my test example I’m in a 7/8 meter) and 2) most of these loopers seem to function in an anticipatory looping fashion where when set to sync, you press the trigger, it doesn’t start to record until the bar after you hit it, and same for playing as well. I don’t want this because it feels extremely unnatural as a guitar player. I want to hit the trigger from my MIDI controller on the downbeat, have it immediately start recording, and then when I hit the trigger on the downbeat again where I finish it immediately plays it back while still synced to the grid.

Now the looper VST I am using is MSuperLooper, and when it’s set to not sync it works in that immediate fashion, just it’s not quantized the grid which is where MIDI Translator Pro comes into play. I want to be able to quantize the MIDI inputs of my foot switch controller to FL Studio’s clock before it goes into MSuperLooper, effectively making the inputs synced via 8th/16th notes, or possibly work per bar of whatever time signature the DAW is set to. I’m not familiar with the coding language that the software uses or anything like that but I got this far with my project in MIDI Translator:

I have the input ports in the project set to: my footswitch controller & the virtual input. The outputs are set to: the virtual output. In FL Studio I have the virtual output synced to it’s clock and it looks to be taking in activity from both the MIDI clock messages of FL & my footswitch controller. Now I have 4 translators. 1 set as the “time clock” taking the MIDI message from the time clock of the virtual in port with no outgoing, 2 translators capturing the on/off (127/0) of the MIDI CC message from my footswitch, both with no outgoing messages, and the last one set to be the quantized output. I’ve tried messing around with the rules area but I’m unsure of where to go from here and how to make all these translators function in the way that achieves the outcome I want. Is there anyone who can help me get this running and working? Any help would be greatly appreciated!!

Hi and welcome to the Bome community!

So in essense it looks like you want to take any note-on or note-off message and store for up to 6 beats (1/16 note) and release it at the next 1/16th not intervale, Is this correct?

If so you would need to determine the possibility of how many note events might occur during that interval and then have enough global variables to use to store them before release.

The release translator would need to quickly determine what notes are queued (stored in global variables) and then quickly send them all at once at the next 1/16th inteval and then clear the global variable for the next cycle.

You would need to capture the note type event (on or off) note number and velocity for each note. In order to do this quickly, hopefully the number of likely notes would be 3 (6 events since both note-on and note off need to be captured), so you would need 6 global variables and allocate storage dynamically as they come in. Then when the next quantize interval (based on a counter of clock pulses) happens, quickly iterate through the queued notes and play them.

The tricky part is both capturing and releasing and the timing involved in iteration through global variables do handle this very quickly.

This is something I have not done before but let me know if this is the type of logic you are looking for.

The capture logic would use rules to allocate and store variables and the release logic would be to iterate through these variables (stored events), play them and release the variables.

A global variable stores 32 bits so you could pack the information into one variable, maybe the LSB (velocity ) in bits 0-7, the not number in bits 9-15 and the note and channel number in bits 16-23. You would set the value of the variable to -1 upon release. This would help you determine which are pending notes for release.

If this looks like the right path, let me know and I will give it more thought or maybe this is enough to get you started.

Steve Caldwell
Bome Customer Care


Also available for paid consulting services: bome@sniz.biz

Essentially! But not via 16th notes in my instance, rather 8th notes, and I don’t want to store it for a specific number of “beats” per se (unless it might need to function that way? I think by 6 you don’t mean the actual “beats” in the DAW but rather the ticks that make up a 16th note in the clock of the DAW; so 12 ticks instead of 6, I’d imagine?) I just want to have it send the trigger out to align via any 8th note on the grid so if I hit the trigger early or late it immediately comes back out on the next 8th note of the grid.

Now that I think about it, I dunno if the off message really needs to be quantized as it’s really just that initial on value that triggers the on and off of MSuperLooper (since it works in a latching type function which is something I can just set in FL Studio’s parameter functions regardless of the off value of the footswitch). So quantizing the off might not be needed however I do want that “off” to still register so it’s not perpetually just on. The MIDI message is a MIDI CC message (specifically channel 1, CC3). For whatever other CC messages I’d imagine I just copy the process if I want to have more than one button synced.

As for everything else…. I’m very lost on the terminology that you’re using. I’m somewhat new to understanding the rules and what any of the coding means. Can you explain to me, in very beginner language, how to maybe achieve something like this?

Since we can’t go back in time it would need to trigger on the next availble 1/8th note.

I have mull this over a bit because it would be a bit complex to implement in Bome MIDI Translator Pro.

I DO have a project I did years ago that evaluated chords and if the users fingers are not exact we would wait some milleseconds before we would trigger a chord. If I remember, it also determined the low note but I don’t remember what we did with it. It has been a while since I looked at it. It is attached here and uses a technique similar to what I discribed earlier.

Maybe you can look at it and see if you could figure out how to alter it for your needs. I did not do bit stuffing rather just looked at the note number and ignored the MIDI channel and velocity.

Clock-Syn-Notes-2021-11-22.bmtp (6.9 KB)

Yes 24 ticks is a quarter note so 12 ticks would be an eighth note. We would have to determine the beat by the start signal for counting ticks.

Steve Caldwell
Bome Customer Care


Also available for paid consulting services: bome@sniz.biz

I’ve been developing something along similar lines to use Ableton to do live looping. I have a timer that uses the midi clock stop start and pulses from ableton. It counts in pulses and I also have it quantising to set loop lengths for triggering. That way I can hold triggers for my effect units and other peripherals to the correct times

x] Preset 4: Timer Ableton Ctrl In
Default MIDI IN ports: ABLETON

Translator 4.0: Song Position
Incoming: On DAW stop/start capture Song position Pointer. Allow pass through, on port ABLETON
Rules: “Update Song Pointer Pulses x Song Position Pointer”
// Log ‘%pp%’
pa=sp*pp

Outgoing: Perform ‘Timing’ with 0 parameters

Translator 4.1: Timing
Incoming: On Perform ‘Timing’ with 0 parameters
Rules: “Position: Bar,Note,Ticks,Loop Quamtized”
// Active Calc Pulse since start of loop
pl=pa%lp

// check against trigger point for switching and effects
if pl==tp then Perform ‘End Of Loop’

// Arm Transport at loop start after a short delay (on second pulse)
if pl!=2 then exit rules, skip Outgoing Action

// Additional Trigger Points can be added here
// pa for absolute
// pl for loop etc
// use the timing constants to generate repeated events by modulo divides

// if pl==ze then Perform ‘Start of Loop’
// every beat
// need pulses per beat nb/nd (qw= quarters per whole note)
// pp=pqqw/nd pulses per beat - use as mudulo divisor
// every bar
// pp=pp
nb pulses per bar
Outgoing: activate preset ‘Transport’

There’s also an increment preset which handles the clock pulses.

Preset 6: Clock Increment (always active)
Comments: This should be placed after Transport preset, so Song Position isn;t immediately updated before transport happens
Default MIDI IN ports: ABLETON

Translator 6.0: Clock Pulse
Options: swallow
Incoming: Increment The Clock Pulse Count, trigger ‘Timing’ for calcs
Rules:
// Increment pulse (absolute) clock
pa=pa+1
Outgoing: Perform ‘Timing’ with 0 parameters

Hope this helps. 24 pulses per quarter note (PPQN) is standard

I’ve been developing something along similar lines to use Ableton to do live looping. I have a timer that uses the midi clock stop start and pulses from ableton. It counts in pulses and I also have it quantising to set loop lengths for triggering. That way I can hold triggers for my effect units and other peripherals to the correct times

Hope this helps. 24 pulses per quarter note (PPQN) is standard

I use a lot of pre-declared constants and variables (pp is 6 pulse per midi song position pointer count). TP is a predefined trigger point count in a loop…

x] Preset 4: Timer Ableton Ctrl In
Default MIDI IN ports: ABLETON

Translator 4.0: Song Position
Incoming: On DAW stop/start capture Song position Pointer. Allow pass through, on port ABLETON
Rules: “Update Song Pointer Pulses x Song Position Pointer”
// Log ‘%pp%’
pa=sp*pp

Outgoing: Perform ‘Timing’ with 0 parameters

Translator 4.1: Timing
Incoming: On Perform ‘Timing’ with 0 parameters
Rules: “Position: Bar,Note,Ticks,Loop Quamtized”
// Active Calc Pulse since start of loop
pl=pa%lp

// check against trigger point for switching and effects
if pl==tp then Perform ‘End Of Loop’

// Arm Transport at loop start after a short delay (on second pulse)
if pl!=2 then exit rules, skip Outgoing Action

// Additional Trigger Points can be added here
// pa for absolute
// pl for loop etc
// use the timing constants to generate repeated events by modulo divides

Outgoing: activate preset ‘Transport’

There’s also an increment preset which handles the clock pulses.

Preset 6: Clock Increment (always active)
Comments: This should be placed after Transport preset, so Song Position isn’t immediately updated before transport happens
Default MIDI IN ports: ABLETON

Translator 6.0: Clock Pulse
Options: swallow
Incoming: Increment The Clock Pulse Count, trigger ‘Timing’ for calcs
Rules:
// Increment pulse (absolute) clock
pa=pa+1
Outgoing: Perform ‘Timing’ with 0 parameters

Although I didn’t thouroughly review your code, translator 4.0 has a problem. You used the variable pp which is not a global variable and so the value is not defined anywhere.

In summary oo,pp,qq,rr,ss,tt,uu,vv,ww, and xx are local varaibles. Everyhing else is global. Local variables are handy for being private for a given incoming trigger so you don’t have to worry much about name collision. However you do have to initialize them and their value does not carry across other translators.

Go to the help menu or press F1 from within Bome MIDI Translator Pro to read about variables.

Steve Caldwell
Bome Customer Care


Also available for paid consulting services: bome@sniz.biz