Cantabile Community

Introducing Binding Expressions

Binding expressions are a new, advanced way to create mappings between source and target binding points.  The let you use mathematical and logical expressions to control not only the value sent to the target, but also under what conditions it's sent.

This is a companion discussion topic for the original entry at


Wow! :slight_smile:

Can see lots of possibilities with these, and I am sure that the power users like Dave and Torsten will think of even more! :slight_smile:

1 Like

oooooooh - I’m sensing a rabbit hole full of possibilities…


I’m curious to see what you guys come up with using this :slight_smile:

1 Like

I’ve started exercising these new features and have some questions about results I’m seeing. I began by testing and experimenting as in the video using the Master In and out sliders and the Expression option in mapping. All worked as expected. It also worked with any sliders using 0.000 to 1.000 scaling like rack and plugin sliders.

Next I tried binding a pop up slider from the Controller Bar which sent a MIDI continuous value (0~127) as the Source in the binding. I bound it to the Master input slider which uses 0.000 to 1.000. This gave a wild result. When I moved the controller bar slider from value 0 to value 1 the Master input slider I bound to jumped from minimum gain to 0db and went i moved it to value 2 it sent the master input slider to +6db. After that the value displayed by the slider jumps of the scale and starts gradually increasing from +9.5db to +42.1db.


controller slider = value 1

controller slider = value 2

controller slider = value 3

So, is what I’m doing against the rules or is there a conversion filter missing to scale the MIDI 0~127 values to the 0.000 to 1.000 scaling of the log sliders?

I also wasn’t able to bind one controller bar slider to another using the simple expression formula.

The binding does not connect, is this type of MIDI slider to MIDI slider arrangement verboten when using expressions?

Any help or direction appreciated. :slight_smile:


I tried using Input / 127 * 2, which gives me “correct” values for 0 = -oo and 64 == 0dB, but moving the slider to 127 just gave me +6 dB. I had to drive up the multiplier to 8 instead of 2, in order to reach maximum level, but then the 0 dB level drifts down to cc values around 19 or so, which is unusable.

When using tha standard “Automatic (Range)” Mapping, I get correct mapping of CC values to volume, from 0 to (max). Looks like something is broken when feeding the output slider my calculated values, which ought to be 0…2. The mapping from calculated values to the output sliders seems off. I checked by using the formula Input / 1000 + 2 - this reliably ended up around +6 dB instead at (max). So: what is the numerical equivalent to (max) and how can I get Cantabile to map my values according to the MIDI control curve, as the Automatic mapping seems to do?

Next, I tried the reverse: used Output Gain as the source of the binding and tried to generate MIDI data from it:

This didn’t generate any MIDI data at all when moving the output gain slider. But when changing the Mapping to “Automatic (Range)”, I got wonderful MIDI data for CC11 from 0 to 127 when moving the output slider.

Next, a super-simple MIDI mapping: get input CC 11 from a pedal and output a simple mathematical calculation: Input / 2 - no output at all.

I even tried round(Input / 2) to make sure I created integer numbers, but nothing.

Something seems broken…

Sounds like you’re getting tripped up on dB vs gain multiplier.

Cantabile’s gain sliders display dB values which go from -oo to +7ish. But that’s just how they’re displayed. Internally they’re stored as a gain multiplier where -oo is 0 and 0dB is 1 and it’s these gain multipliers you need to use when using expression bindings.

If you’re trying to manipulate gain values with expression bindings, you might find the toDb and fromDb functions helpful. See here.

Also, don’t forget the sliders use a control curve that varies things. Perhaps I should expose these curves as functions as well? Let me know if that would be helpful.


Yes, in order to convert gain or dB values to MIDI or vice-versa, we’ll definitely need the control curves. Re-building that logic within an expression “by hand” would be a bit of overkill.

Just re-capping: in order to convert from a MIDI CC value to a correct gain value (control gain via pedal), we’d need to use

  • control curve to get from MIDI value (0…127) to a dB value
  • some fancy processing at dB level to do what we want
  • from dB to get a correct gain value

Is that correct? Or does the control curve work output gain values directly, so we’d only need the “control curve” function to get from MIDI to gain - and do our processing in the “gain values” domain?

Next question: how would we get MIDI output from binding expressions? So far, I haven’t found a way to use the output of an expression to generate MIDI CC values.

OK, quick addendum - had a look at the custom control curves section of the guides. It appears that control curves convert directly between “gain” and “position” values. Positions range from 0…1, so a position should be the result of Input/127 for MIDI CCs.

I fiddled with the formula from the control curve file, but didn’t really get anywhere. I eliminated the issue of a log(0) crashing Cantabile by using Input/127+0.00001 (didn’t want to complicate further by having to use Input=0? : ) ; and in theory the formula should work:

pow(10, (log(Input / 127 + 0.00001, 10) * 60 - (log( 64 / 127, 10) * 60)) / 20)

At least, translated to Excel, this calculation provides values between (close to) 0 and 7.8 (which is correct for max gain in this curve), with 64 calculating roughly 1 equalling 0 dB, also correct.

But using this formula in Cantabile simply makes the slider position marker disappear at +oo, so there must be something wrong with the formula - I just can’t find the mistake (yet). Someone needs to check the math…

Still - all too complicated to be useful - so we definitely need the “control curve” function…


Checked the math and came up with this… not sure if it helps explain but does work.

This worked for mating a controller bar pop up MIDI slider (0~127) to a logarithmic Cantabile slider on a rack and it observes the control curve. It gives the basis for other conditional fun. Note that your rig would use 64 instead of 96 for the 0 position.

pow(10, (log(Input, 10) * 60 - (log(96, 10) * 60)) / 20)

Also got the log slider to MIDI figured out in the test environment of using the log messages but it will not send the numbers it produces as a result to a MIDI target as a CC message.

formatNumber(pow(10, (log(Input, 10) * 20 + (log(96, 10) * 60)) / 60),"N0")

Besides the issue of not being able to route to MIDI objects I still can’t figure out how to bind MIDI to MIDI with the expression though. I hope @brad can explain the MIDI related issues for us.

Hmmm, that’s interesting - according to the Control Curves documentation, the values of x in the formula are supposed to be 0…1, not 0…127. But if it works…

Also: how are you not getting issues with controller values of 0? log(0) is definitely not defined…

Well, I looked at the documentation and it didn’t explicitly say that. It did associate “x” with the 2 functions (scalar and position) but didn’t specify the range of “x”. I assumed that since zeroDbPos was defined as a portion of 127 below in the script that it must expect a 0 to 127 variable for the “x” in the first part of the equation.

The document could better define “x” IMO.

On the log value of 0 I’m not sure why that doesn’t crater the app but my theory is that your equation attempted to divide zero by 127 and possibly that operation didn’t digest well. Again, just a theory.

Hmm, my math says 0/127 = 0. Just the reverse isn’t defined…

Sorry, I got it wrong, even stranger now … :slightly_frowning_face:

Hey Guys,

I’ll add some functions for the control curves and the velocity curves and put together some examples.

Is there anything specific you’d like to see how to do? Seems like at least MIDI value (0-127) -> Gain and Gain -> MIDI value.


Yes, in addition to what you described I like to see how to do a MIDI value > MIDI value binding that uses the Expression and actually produces a MIDI out. I tried this simple style of binding to do it and while it recieves the source input it doesn’t produce messages to the target.

1 Like

+1 on MIDI as target of expression bindings working - currently, it is just not producing any MIDI output

1 Like

Experimental Build 4152 is up now with some new functions

These are also documented in the Function reference.

scalarToPosition and positionToScalar

These functions use the user-selected control curves to map a value between a position and a scalar gain value.

  • The first parameter is the name of the control curve to use and can be “gain”, “midi” or “levels”.
  • The second parameter is the value to convert.
  • Scalar means a gain multiplier where 0 = -oo and 1 = 0db.
  • Position means a position on a slider from 0.0 to 1.0

eg: to convert a MIDI CC value (0-127) to a gain value using the MIDI control curve:

positionToScalar("midi", Input / 127)

eg: to convert a gain level to a MIDI CC Value:

int(scalarToPosition("midi", Input) * 127)

GainToCC and CCToGain

Because the above is a bit verbose, the following functions perform the equivalent:




GainToFineCC and and FineCCToGain

If you’re using a fine controller (0-16383), these functions are available:




Velocity Curves

I’ve also made available a function to calculate velocity curves:

curve(curveName, curveAmount, value)


  • curveName - one of "enhance", "expand", "enhance-1" or "expand-1" (where -1 denotes the inverse version of the curve).
  • curveAmount - the curve amount (from -1.0 to 1.0 and where 0.0 = linear mapping)
  • value - the value to convert (0.0 to 1.0) (the x-axis of the graph)
  • The result is the value of the curve at that position (0.0 to 1.0) (the y-axis of the graph)

A Couple of Examples

Mapping a CC to a gain setting:

Mapping a gain setting to a CC:

You can do this by using a build of Cantabile where it works :slight_smile: Build 4152 should address this.