Math in binding expressions

I’m trying to revive a discussion I had back in January with Brad and Dave Dore. My goal is to have pitch bend and channel pressure add together to produce an extended pitch bend My use case is pitch bend form a midi ring control for vibrato and pitch bend from aftertouch for larger bends. If I simply use a controller map for channel pressure to pitch bend, then the ring and aftertouch are fighting each other. I can bend a note with pressure but the slightest movement of the ring sets pitch back to zero or near zero. Slight movements of the ring are impossible to avoid. Same thing happens if I use pitch wheel and ring.

So Brad suggested something about using the on-screen keyboard to somehow buffer the aftertouch and make that an offset to pitch bend. Dave said he tried it and it worked. I promised to try it myself in “a few days” which has now become 6 months.

I made a very simple song and copied Dave’s binding but it doesn’t seem to work. Pitch bend works normally form the wheel or the ring. Pressure does nothing at all

I’m doing this with absolutely no understanding of Dave’s binding. Perhaps Dave or Brad can enlighten me.

What is going on with “Source”? I’m sure it has something to do with buffering the aftertouch, but the actual mechanism id unclear.

“Target” seems straightforward

“mapping”, not so clear. What is “Input” - pitch bend? Why is it multiplied by 20? I think finecc(0) is somehow related to onscreen keyboard and pressure, but not clear on that.

Hey Ray,

Could you post a link to the former discussion please?

Dave

Buried deep in here.

Thanks Ray,

I will refresh my memory on this and post later. Busy for a while so I’ll get back to you.

Dave

Thanks, Dave!

Hi Ray,

I got back up to speed and checked the old thread. It appears I used 3 bindings to achieve the task in that posting. I did some experimenting today and got it going with 2. In reply to your questions.

The onscreen keyboard source was from my testing example and in your case would be your actual controller keyboard not the onscreen keyboard.

No, Input in this case is the channel pressure. “Input” is derived from the Source box parameters you set in the binding.

I did that arbitrarily because the range of the channel pressure is small so for there to be any movement of consequence I needed to increase it’s range by multiplying it. You would set this multiplier value to your own taste or needs.

finecc(0) was the stored fine cc value for cc0 that was stored in the onscreen buffer. The fine CC number was chosen arbitrarily and can be any number from 0 to 31. It was derived by converting the pitch bend input to a finecc value that stayed in the onscreen keyboard buffer as Brad suggested.

The 2 bindings I have set up for testing use the onscreen keyboard so the source would need to be changed to your source when you make your own bindings.

binding to convert pitch bend to fine cc and store in onscreen keyboard buffer

binding to add channel pressure values to the fine cc buffer value that is stored and send it to the plugin’s pitch bend.

for this scenario I came up with to work the pitch bend data from the keyboard itself has to be also be sent directly to the plugin. This should happen with the input route to the plugin so no binding is needed for this.

so a breakdown of the logic is

  • send pitch bend direct to the plugin

  • convert the same pitch bend data to fine cc data and store in the onscreen keyboard buffer.

  • add the channel pressure value to the stored fine cc value

  • send the resulting value to the plugin as pitch bend data

I hope this helps get it going, as I said before it works in my testing setup here.

I’m due for a nap after being out in the sun all day, but I did mess with this a little bit. If I leave out the “+ ccfine(0)” in the expression, I have pressure being converted to pitch bend and I am able to tweak it for a useful range - (input * 64) + 4192 gives me a semitone up bend to a vst set for +/- 2 semitone bend range with my physical controller. However “+ ccfine(0)” gives me an error.

I’m not sure if the intent is to change this one from onscreen to my physical controller, but I can’t. onscreen keyboard is my only choice in the pull-down.

I was also going to try exactly duplicating your bindings using onscreen keyboard throughout but I don’t know how to get channel pressire or pitch bend from onscreen.

Thanks for spending time on this.

Hi Ray,

I might have misunderstood what you wanted to do. My impression was that you wanted to use the physical controller to:

  • accept pitch bend from the controller and route it to the VST plugin
  • allow the after touch (channel pressure) from the keyboard controller to add to the pitch bend that was already set by the pitch bend as manual vibrato and send to the same VST plugin.

Is that right?

Dave

That’s right. In my case pitch bend is coming from the Genki ring, not the wheel, but it’s still a pitch bend message.

Think of it as PBout = PBin + CPin.

In a more general sense, a binding should be able to do simple math on PB. PBout = PBin1 + PBin2 + PBin3 + …

And not just PBin. CCin, CPin, ATin , etc.

OK, that is what I thought. I still think my solution would work but don’t know why it is not at your end of the world. Would a step by step setup tutorial help? I sort of did that above but it may have been confusing how it was laid out.

My apologies. I stared at mine vs yours a dozen times but I still managed “ccfine” on mine when the correct one in “finecc”. It’s not yet excatly what I want, but I am definitely making forward progress now. Many thanks!

1 Like

I ended up stashing channel pressure in the onscreen keyboard instead of pitchbend because it automatically scales up to a 14-bit value. Added a “min(16383,” around the expression. Definitely doing what I wanted. I may need to tweak it a little, but I’m pretty happy with it so far. Thanks for your patience.

The only thing I’m not completely happy with is that it is very specific to controller and plug-in. Not trivial to move to a different rack or song. But at least my crazy ideas can be realized.

Is there a list of the generic sort of functions available? “min” was just an educated guess. Is it based on a standard programming/scripting language?

There are function lists at the main website in the support / User guide section.

It’s based on C and C++ scripting.

https://www.cantabilesoftware.com/guides/functions

I have been working on refining this idea so it is more portable. I have bult a linked rack with just midi I/O. I think I have discovered a bug, but it’s probably just my stupidity. There is a binding that stashes pitch wheel into finecc(0), a binding that stashes channel pressure into finecc(1) and a third binding that ties those together and adds in vibrato from he ring. This last one is the meat of it. It looks like this:

The expression is:

(finecc(0) + finecc(1) + input)

When I feed this into an instrument plugin it works great, allowing simultaneous use of pitch wheel, aftertouch (as bend up), and ring vibrato with no pitch glitch. But not so great when it gets to the extremes where the the sum is >16383 or <0. The pitch bend wraps around and jumps to the opposite extreme. I think this expression should fix it:

clamp(finecc(0) + finecc(1) + input,0,16383)

However, the result is pitchbend out = 16383 regardless of inputs.

Where is the flaw?

Hi @raydyo

This is a bit of tricky one - partly because of the use of PitchWheel. One thing to be aware with pitch wheel values is that although they’re often displayed as -8192 … 8191, internally they’re represented as 0…16383.

So if you’re store pitch wheel in finecc(0) and adding a second pitch wheel value (ie: input) - you’re probably adding two center values of 8191 and getting close to 16383 when everything is centered

In any case I just tested your expression here with zero in both finecc(0) and finecc(1) and the clamp function seemed to work fine.

One thing you can to do debug this is set the target to “Execute Command” and the message to $(value) and it’ll show the calculated value when the binding is invoked eg: see the “16383” shown below comments in this screen shot:

In order to fix this, you need to add together zero centered values. Ignoring the channel pressure value, and just considering the two pitch wheel values you could try something like this:

  • Centered value for fine cc: finecc(0) - 8192
  • Centered value for pitch wheel of binding: input - 8192

Add them:

(finecc(0) - 8192) + (input - 8192)

You then need to de-zero-center by adding back 8192.

(finecc(0) - 8192) + (input - 8192) + 8192

Simplifying and clamping gives:

clamp(finecc(0) + input - 8192, 0, 16383)

I’d try testing without the channel pressure setting first and then working than in later. Don’t forget channel pressure has a range of 0…127 (not 16383 like pitchwheel).

1 Like

Brad,

Thanks for the very quick response! What you are saying makes perfect sense. I probably have pitch errors even when not at the extremes. I’ll add a non-bendy plugin to the other keyboard for reference.

I probably missed pitch errors due to the range limitations in my setup. Combined with my far from perfect pitch. Only the pitch wheel can easily go full range. +/-1 octave in this case. The Genki ring can only approach full range if you wiggle your finger wildly. I didn’t mention it but the pitch bend from aftertouch gets constrained to a semitone or two by the Fluid Pitch plugin which is in my rack. So the goal is to allow dive bombs from the wheel, in-key bend up from channel pressure, and subtle vibrato from the ring.

By the way, when you stash channel pressure to fine cc Cantabile automatically expands the range. Nice!

I have put my PC away for the night. I will mess with this tomorrow and post an update here.

Thanks again
ray

Hi Brad,

The math works perfectly once it is all normalized to +/-8192 and then back to 16383. Thanks.

However the whole thing is kind of fragile. It only works because the Genki ring (aka input) is constantly spewing out pitchbend messages. If the ring is off then neither channel pressure (finecc(0)) nor pitch wheel (finecc(1)) have any effect. If I leave the ring on but set it on a table it will occasionally spit out a pitchbend message due to random vibration. Under these conditions, the response to the other inputs is ragged. Moving the wheel doesn’t work until the ring burps. And it can get stuck at the wrong pitch. I have tried various settings like “always”,“finecc(1) != 8192”, “when result changes”, etc. But no joy.

It appears that the binding is evaluated only upon input activity regardless of “always” or other conditions. Is that correct? That doesn’t seem right to me, but there may be ramifications that I am not thinking of. Is there a way around this?

I tried swapping things around so that the ring was stashed in finecc and pitch wheel was input. As I expected, it would not respond to ring or channel pressure unless I was actively moving the wheel.

-ray

Hi @raydyo ,

That’s correct bindings are only triggered by the source side of the binding - not any other dependencies used in math expressions.

Unfortunately I can’t think of anything off hand that will let you create a binding based on three different independent controllers.

Maybe PizMidi has something, or a custom script in reajs?

Brad