Jump prevention problem

Hey Neil,

I’ve not been able to reproduce this. Can you send me a copy of your two racks so I can check I’ve set it up the same way.

Brad

Thanks Brad - racks sent to you via e-mail.

Neil

Hi @Neil_Durant

I’ve been looking into this again this morning but still be unable to reproduce it even using your rack files. There must be something else going on that’s not in my simplified test.

The way jump prevention is implemented it’s fairly stateless - it actually asks the target what the current value is and only tracks if it’s what it expects. So if it’s tracking, that suggests the value never got set by the trigger.

Can you confirm whether the trigger is firing and that free-g is set to the correct gain level before moving the pedal?

Brad

Yes, I’ve just tested it again on a clean simple song, and the CC16 binding definitely sets FreeG’s initial level. But as soon as CC11 comes in over the other binding, FreeG moves, when it should remain static / jump-prevented until CC11 passes that CC16 value.

I tried disabling the CC16 binding, so FreeG doesn’t receive an initial level, and left FreeG in an arbitrary position. When I switched to the song, and moved the pedal to send CC11 in to move FreeG, jump prevention kicked in as you’d expect, until I moved through the current FreeG level, then it tracked.

So the bug appears to require both these two conditions to be met:

  1. Jumping in from another song, with the CC11/CC16 bindings set on that first song state (i.e. does not happen just jumping to that first state from a later state)
  2. The CC16 “initial level” binding must be enabled

Note: I can also reproduce this when the bindings go to a Cantabile gain slider, without using FreeG.

Strange…

Neil

Hey @Neil_Durant Sent you an email.

I’ve finally had some time to do some more experimentation with this, and have some new information.

As a reminder, I have a “pedal fade” rack that outputs controller 16, value 0 at song start, and maps expression pedal input to controller 11. The output of this goes to a strings rack, which has two bindings, from cc11 and cc16 both to a Cantabile gain control on an empty rack (rack stereo in routes straight to rack stereo out - basically the rack just acts as a gain control - I used to use FreeG for this). The cc11 binding is set to “Absolute with jump prevention” and the cc16 binding is set to “Absolute”. The idea is that cc16 always sets the desired start level, and expression pedal input won’t do anything until it passes the level set by cc16 (jump prevention). What I was finding was when this happens at the start of a song, the cc16 value appears to be ignored, so jump prevention on cc11 doesn’t work.

What I’ve found now is that jump prevention does appear to work, as long as some controller data passes through the “Absolute with jump prevention” binding before the absolute value is set with the cc16 binding.

To clarify, these are the two scenarios:

CC11 - “Absolute with jump prevention” binding to fader
CC16 - “Absolute” binding to same fader

Failing scenario:
Song state load
CC16 = 0 Set fader initially to zero (done using song state load trigger)
CC11 = 100 Fader incorrectly moves to 100 and tracks CC11 - should have remained at zero for jump prevention

Working scenario:
Song load
CC11 = 1 Set fader to something arbitrary on state load trigger with no delay
CC16 = 0 Set fader to zero, using song state load trigger after delay
CC11 = 100 Fader correctly remains at 0, until CC11 moves to 0, then tracks CC11

@brad , In this thread, you describe how jump prevention works as follows:

  1. After a binding sends a value to a target parameter it reads the value back and stores it.
  2. Next time the binding is invoked it compares the saved value to the current target value
    If it hasn’t changed then things are still in sync and binding takes place.
    If it has changed then it enters a mode where it waits for the source controller to touch or cross the current target parameter value.

Could it simply be that my cc11 binding has never sent a value to the target parameter in (1), so doesn’t have a stored value to compare against for jump prevention in (2) ? If that’s the case, it means jump prevention can only work properly with one binding. Wouldn’t it be more correct to set that initial stored value from the target parameter value, when jump prevention is enabled, so that in my scenario the binding starts in “jump preventing” mode?

Neil

Hi Neil,

I’ve just tried again to reproduce some problems here but it seems to work just fine.

Unless I’m misunderstanding something, this would be back to front.

If you want it to start in jump preventing (non-tracking) mode then the stored value must be different from the target value. If the binding was initialized with the target value then any new value from the controller would be applied immediately (because the binding would think it set that target value).

There’s obviously something not quite right here, but as mentioned I’ve not been able to repro it. Do you have a simple set of song/racks that demo it?

Brad

Aha, I see how you’ve implemented the stored state now - it’s basically the last target value the binding sent, yes? Then what I’m proposing is that the stored state is some invalid value initially, so that the first incoming controller data will always need to pass the current target value to lock on. Currently it appears to be that the binding will always acquire a lock on the first incoming controller data, and thus will be likely to cause a jump.

Neil

I’d like to hijack this thread because my question is also related to the jump prevention.

@brad: is the jump prevention only working for the first time the assigned controller is used? I work with a controller which doesn’t have motorized faders. But it has several banks. That means, in the first bank the faders send cc0-cc8, in the 2nd bank cc9-cc16 and so on. So let’s say the first fader in the first banks controls the volume of a rack and the first fader in the second bank controls a parameter inside the rack. If I change to the song, the jump prevention works fine. No change until the value of the fader == value of the rack volume. If I now change to bank 2, do some changes here with the first fader (so I move it to another value) and go back to bank 1, the jump prevention is no longer working. Is that meant to be like this?

And another question to @Neil_Durant: Why do you use FreeG instead of the instrument- / rackvolume in Cantabile directly?

Thanks,
Chris

Hi @FantomXR

Yep that’s how the jump prevention works - once it thinks it’s synced to the source controller it accepts anything further from that controller without questioning it.

In the case you described, when you switch banks and move the controller you’ve effectively de-synced the binding, but the binding has no way to know about it so it continues to track the sent values.

Unfortunately I can’t think of an easy fix for this.

Brad

Ah! I used to use instances of FreeG nested inside my instrument racks for volume control, because back then if I bound a continuous MIDI controller to the Cantabile gain faders, it didn’t change smoothly, giving audible steps. Also the controller scaling / gain curve wasn’t very nice to use with a pedal. This was quite a while ago, but then Brad fixed these things, and added different gain curves etc., and so now I just use Cantabile gain controls. This is nice because I save 1-2% of Cantabile load for each instance of FreeG I’m no longer using. :relaxed:

Neil

2 Likes

Ah, alright! Hm…

My setup is constructed like this, that the GUI of the plugin shows up as soon as I move the encoder. So I really like the idea of using a gain-plugin. But if you say, that the FreeG is quite hungry, it’s not the right thing for me. I use 8 different racks in every song. So this will be 8-10x FreeG.
Any other ideas for less hungry gain-control-plugins?

@brad: Alright. Thanks for checking! I have already an idea how to workaround this.

In the past, the idea of having customisable “control panels” for racks/songs, with a set of user-definable controllers (faders or whatever), that give you visual feedback, was discussed, and is still on the feature request list. I think that would provide the kind of functionality you want, without the overhead.

In the meantime, 80 instances of FreeG sounds like a bad approach, definitely! Could you instead just have instances at the point of entry of your controller data? For example, put them in your background rack, bound to the incoming controller data, and accessible automatically in all songs? You wouldn’t necessarily know which plugin parameter is being changed when you adjust an encoder, but you’d still have the visual feedback, and you’d only need one FreeG instance per physical encoder.

By the way, I like your idea of having plugin GUIs pop up when you move an encoder, for visual feedback. Do you have any mechanism for dismissing the GUI when you stop making adjustments?

Neil

No, you got me wrong. I have 8 channelstrips. So this would mean 8x FreeG. I think I just need to check if FreeG causes any significant CPU-Load.

Yes! This is quite easy. Assume your encoder sends CC80. At the moment you need four bindings (I know, it’s a lot):
Bind CC80 to the value in the plugin you want to change.
Bind CC80 to the plugin and choose as target “Show GUI Editor”.
Bind CC80 to trigger #0
Bind trigger #0 to the plugin and choose as target “Show GUI Editor” and as value “Off”. Now you can add a delay to the trigger, so it waits x milliseconds till the trigger runs.

Works great :wink:

1 Like

Okay, I noticed a drawback and maybe @brad can explain that.

At the moment a trigger can be triggered a lot of times at once. That means: If I bind CC80 to the trigger than the trigger get’s triggered not only one time, but everytime the value of CC80 changes. In other words: When adjusting CC80 from 0 to 20, the trigger get’s triggered 20x which doesn’t make really sense here. I also don’t know a case where this may be a good idea. To me it makes more sense, if the trigger only listens to the last time the trigger received the start-command. What I want to achieve is, that the GUI editor closes 3 seconds after the last change was made…

Ah yes, I mis-read 8-10x as 8x10, thinking you had 10 different parameters you were mapping to or something (I haven’t had enough coffee yet today). 8 is a lot more managable, and since (in my experience) FreeG only takes 1-2% load, the result is still fairly low. I believe @Torsten has stated before that he sees no noticeable increase in load from FreeG, so your mileage may vary.

Regarding the timed “close GUI” trigger thing, perhaps @brad will be able to reassure us that it’s harmless and not wasteful of performance to send multiple “Show GUI Editor” events, in which case I guess your approach is fine. Internally I’m guessing Cantabile only does something as a result of a binding if it’s actually going to change the state of something.

However this sounds like a great feature request for @brad for a new binding type, which will not trigger again for a user-definable period of time. I can imagine people finding all sorts of other uses - for example to prevent people from accidentally double-tapping a “next song state” footswitch.

Neil

Yeah! Sounds great! This sounds like a good usecase

Confirming: multiple show/hide plugin editor bindings are fine… if it’s a no-op it’ll just be ignored.

Delay retriggerable bindings is an interesting idea. Logged it.

1 Like

Available now: New Feature: Delay Retriggerable Bindings

2 Likes

Nice!!! :slight_smile: