Controlling Hardware from a MIDI Controller

Subject: Controlling Hardware from a MIDI Controller

I am struggling with what I feel (after 3+ years with Cantabile) should be straightforward: how to reliably control hardware parameters from a MIDI controller.

I’ve been using a system (now in close to 1000 Cantabile song files) that works 95% of the time, but when it doesn’t, I can get (as happened yesterday) a BIG jump in the parameter (it was Volume yesterday) and the results (as happened yesterday) can be unpleasent.

Hoping someone might suggest a more robust approach …

Here’s my current strategy:

  • I’m controlling a Yamaha VL70-m from a FaderFox EC4 with endless, 2’s complement rotary encoders.

  • The VL70 takes parameter changes as 0-127 MIDI absolute values in CC’s or SysEx commands.

  • The MIDI stream is one-way - from Cantabile to the VL70.

  • I issue patch changes from Cantabile which changes the HW values (and I know those values).

  • I show (what I believe to be) the current state of the HW parameter on the Controller Bar.

My long-standing approach has been to:

  1. Create a Named Route (that goes nowhere important) for each parameter I want to control. Here are the 10 Named Routes I currently have for the VL70, between do-nothing embedded racks ZZ-A and ZZ-B:

  1. Use the Gain value associated with the Named Route to hold the values of the associated parameter.

  2. Have a binding that accepts internal CC’s with 0-127 absolute values for the parameter, converts them to Gain values, and writes them to the Gain of the Named Route.

  3. Have another binding that accepts input from a 2’s complement rotary encoder, and updates the Gain value of the Named Route using a Relative Value Encoder mapping.

  4. Have a binding that triggers on changes in the Gain of the Named Route and informs the Controller Bar on a CC.

  5. Have another binding that also triggers on changes in the Gain of the Name Route and sends the appropriate CC or SysEx to the VL70. (The SysEx commands can be gnarly, since the conversion must be done as an expression … for example: 0xF0 0x43 0x10 0x57 0x02 0x01 0x56 clamp( ((log(value,10)*20>=-6) ? ((log(value,10)20 + 26.8235294118) * 31.1666666641) : (826-Sqrt(-34869-220660log(value,10)))) / 8.05511811024, 0, 127) 0xF7)

Typical bindings for #3 to #6 above look like this:

This system works well in most cases. Parameters get written to the VL70 reliably and the encoder controls the hardware parameter and Controller Bar display appropriately

However, the crux of the issue seems to be that Bindings from #5 and #6 above do not fire unless that Gain value has changed.

One failure scenario is when I issue a patch change:

  • The VL70 loads a “PATCH” value for my parameter.
  • If I want a different “INITIAL” value from the “PATCH” value, I can trigger it using the CC for absolute values (Binding #3 above).
  • However, if my “INITIAL” value happens to be the same value as was last set for the prior patch, Bindings #5 and #6 will not fire. My INITIAL value is never sent to the hardware.
  • When I start playing and later turn the EC4 encoder, the VL70 hardware value jumps from its PATCH value (set by the patch change) to something near my INITIAL value (saved in the Gain value of the Named Route), which can be a BIG jump.

Things I have tried:

  • Conditionally sending CC’s. In other words, setting a flag in a CC that says “Don’t send CCs”. However, I have no way to conditionally send CC from bindings.

  • Temporarily Disabling the bindings that send CC’s, so that I can issue the Patch as well as the Initial values in pairs of bindings without overloading the VL70 hardware. However, I have no way to disable and enable bindings from other bindings.

(Both of these restrictions have been discussed elsewhere on this forum).

I hesitate to set everything to an “absurd” value, then back to “real” values because:

  • The CCs are rather slow to execute on the hardware, and I need delays all over the place to get all the 10 parameters to be set just one time.

  • There really is no parameter in the 0-127 range that is “absurd” for all parameters on the VL70.

Is there a better approach?? Any thoughts, advice, commiseration, rants, etc. are welcome …

Hi Clint,

Have you tried the “Send Bound Objects” function in bindings? Basically in your case if you had a patch change where the gain was not changed you’d have the bound value sent anyway regardless of whether the gain was changed. It might be part of a solution.

Dave

Thanks Dave … I can’t locate anything on “Send Bound Objects” … it’s a function? used as part of an expression??

Might there be a pointer to info on this?

Hi Clint,

Yes, it’s a target point in the bindings area. You can apply it directly at song level to the song level bindings or to the racks but to apply it to racks you need to have the trigger for it originate at a song level

and a receiving binding in the rack that does the Resend

In your case the patch change could act as the song level trigger that started the Resend Bound Values actions.

Dave

1 Like

Looks like “Re-send Bound Values” might be useful! … However …

  • In the vast majority of cases, duplicate MIDI commands will be sent, which given the delay that I use will take “a while”.

  • “Re-send Bound Values” sends all the MIDI commands sequentially with no delay control. I had carefully built in delays after each CC and SysEx based on lots of testing to ensure that the VL70 is not overloaded and that the commands “take”. Without these delays, I doubt if things will work …

I was thinking that I could execute “Re-send Bound Values” on a given route - forcing the bound value for just that route to be sent … but “Re-send Bound Values” only works at the whole-rack level.

Hmmmmm.

Tying Encoder knobs to hardware parameters does seem (to me, at least) to be kind of a bread-and-butter thing … wondering how others handle this …

Well, sorry that wasn’t a good fit. I also thought that maybe you could have a binding that bumped the gain when a state or song unloaded so that the value of the gain would be forced to change on the patch change because you made sure it wouldn’t ever be the same as the previous value. That should preserve your delay hierarchy. Thoughts?

I’m looking into 10 embedded racks inside my Linked rack … I can then execute [Re-send Bound Values] on each rack in turn, with appropriate delays …

“Onward Through the Fog” (motto of Oat Willie’s in Austin)

Thanks for the assistance!!

1 Like

I’d build the rack and one embedded and check that all your bindings links work from the song level down (since you would be 2 levels down)

My solution: Bome MIDI Translator

BMT is already part of my system, but I simply forgot about it (at the expense of many hours of screwing around and bothering folks on this forum - thanks @dave_dore).

BMT is designed for this type of processing … I use it for things like:

  • handling and filtering traffic between Cantabile and Ableton Live (I have several virtual ports into Ableton with different Remote Scripts),

  • Converting single foot pedal presses into a string of operations in Ableton (like “move to the next scene and fire that clip”)

  • Integration with TotalMix (so I can control TotalMix from my EC4, alongside direct control of Cantabile from my EC4). This lets me take advantage of Direct Monitoring in TotalMix for reduced latency.

  • eliminating drum pad bounces on pads that I am using for loop control (I use the top row of a 4x4 MPD-218 to control looping - a double-hit on a pad that controls looping is a bad thing)

… and now …

  • Control parameters on the VL70 from the EC4 and Cantabile.
1 Like