New VST: Smooth Fades for Cantabile

Cantabile is a wonderful piece of software—it’s the centerpiece of my rig—but I’ve long felt it lacked one critical feature: bindings and state changes that smoothly move parameters to new values without jumping them. Over the years I’ve seen various solutions suggested on this forum, but all seem to have their drawbacks. For example, there are VSTs that “play” waveform shapes (e.g., sawtooth) as CC patterns, but those jump the CC before fading it instead of fading from its current (arbitrary) value to a desired target. @dave_dore’s wonderful Auto-Fade Rack uses binding loops to repeatedly adjust CCs until they reach a target, but CC-based solutions can’t achieve perfect smoothness because of the low granularity of CC values, and the looping starts to impose some significant load if I have a lot of different parameters doing fades that way.

So as a different approach to this problem, I’ve written a new VST that adds parameter smoothing to Cantabile:

https://github.com/hamlen/SmoothieVST

The basic concept is pretty simple: SmoothieVST exports three parameters named InParam, OutParam, and Slowness. Any change made to InParam (e.g., via a Cantabile binding or state change) causes OutParam to smoothly move from its current value to the value of InParam. So if you bind OutParam to Gain, and you bind a controller button to alternately send 1.0 and 0.0 to InParam, then pushing the button will smoothly fade your Gain up and down. Slowness determines how fast OutParam may move (0 means instant, 0.5 means OutParam goes from 0 to 1 in 2 seconds, and 1 means OutParam is infinitely slow).

SmoothieVST is sample-accurate, 64-bit, uses VST3 automation, and uses double-precision decimal arithmetic for everything, so it’s very smooth. If InParam keeps changing before OutParam can catch it, OutParam keeps chasing InParam’s new value(s) without jumping anywhere or requiring any manual intervention to reverse direction or avoid overshooting.

This is the first VST I’ve ever written, so apologies if it lacks the finesse of other VSTs. However, I’ve been using it in my own Cantabile performances for the past several months, and it’s worked flawlessly for me so far. Feedback is appreciated.

16 Likes

Hi Hamlen,

This is really nice!! Thank you for sharing it. I got it going and love it! It will find a home in my setup I’m sure. :+1: :+1:

Dave

Hi, I’ve downloaded the files but I can’t get it to work… I must be doing something wrong… any ideas? BTW, I’m running WINDOWS … is that the problem? Is it only for MAC?

Hi Vinlbiza,

I used bindings like this to get it going for me. All you need is the VST3 .dll file to be saved to your VST3 folder.

You set the speed in the GUI using the Slowness slider.

Cheers,

Dave

2 Likes

Got it now thanks :slight_smile: I didn’t see the download to the side of the page… I was downloading the ZIP file with the code etc…

Thanks,

David

1 Like

Hi Hamlen,
I’ve been looking for something like this…thanks!
Tom

This is a Godsend! A solution to something I’ve been dealing with since I started using Cantabile 6 years ago. Thanks!

Hi All,

At the request of @Hamlen I am posting a linked rack for use with Cantabile Performer. I made the rack to work as a replacement my auto-fader racks but with better resolution and hopefully easier to set up. Basically it allows the choice of input and the targeting and routing for each of the 8 Smoothie modules in the VST. The plugin itself was designed to smooth continuous controller inputs but I wanted to have switch activated options as well so I built the rack to make setup of the choice of input easier. The rack saves all edited settings of the VST and the rack to the song file so it requires no rack states to store settings. Of course you have to have Hamlen’s Smoothie VST installed for the rack to work. The following video gives a detailed explanation of the rack and how to set things up.

SMOOTHIE.cantabileRack (344.1 KB)

Thanks again to Hamlen for the great VST!

Cheers,

Dave

8 Likes

Thanks, @dave_dore — this looks awesome!

2 Likes

Hi All,

I made some additions and hopefully improvements to the Smoothie rack. First a summary of operation covered in the video.

  • CC 90~97 act as inputs to the fader array. There are 8 separate fader events available.

  • the 3 custom buttons on the rack are shortcuts that open the rack to either the function setting (1st button), the target bindings area (2nd button) or the GUI for the Smoothie VST where you set the duration of the various fades.

  • Setting the function the SLIDER the input expects a variable CC input and provides a smoother to faders and expression pedals. Where ever you stop the travel of the slider or pedal the fade will go to that point.

  • Setting the function the SWITCH the input expects a Momentary Edge sensitive button. Upon reception of the 1st button message the output is an auto fade up. Upon reception of the second press of the same switch the output is an auto fade down. This function is suited to using the same switch to auto fade up and then later on in the song auto fade down.

The following contains some additions and changes to the rack.

  • The ONE SHOT function is one area where I made an addition. The old behavior is still the same, when it receives an input switch (momentary) it fades up. I added a new CC input that allows you to fade down using a different input. For example, I use CC90 SWT to trigger a One Shot fade up to start a song that uses either a switch or a note from the keyboard for the Source. Later in the song I want to fade out so I have a different switch, state change or PG change that sends a CC100 momentary switch to the Smoothie rack to trigger the down fade. The speed of up and down would be the same for the same fader in the array.

  • I added Reset buttons to the individual Fade racks to help when auditioning ONE SHOT fades.

  • I added a Speed Control slider to each OUTPUT rack using a dummy audio output route. Access it by expanding the embedded OUTPUT rack you want to adjust.

  • Another thing I added was CC outputs for external MIDI devices. The CC out number matches the input number. So CC90 input produces CC 90 output. It applies to all the operating functions. You just route the output of the rack to the desired target.

If you have any questions just post here.

Enjoy! :slight_smile:

SMOOTHIE_Version 2.zip (50.2 KB)

Dave

5 Likes

Thanks, Dave

Those changes are (in the words of The Cars) “just what I needed”.

This (and the embedded Smoothie VST) is a really useful rack.

1 Like

Finally got around to downloading and testing the Smoothie plugin - great addition to the arsenal - thanx @Hamlen!

I thought about how to best use this for simple and smooth level automation within a song, and my current approach is this:

  • I created a Smoothie rack (actually multiple copies of it) that uses the rack’s gain fader as input for Smoothie and provides the smoothed output at its output gain parameter (the one inside the rack, not the displayed gain)

  • Now for every instrument rack I want to have automated levels for, I insert a Smoothie rack and create a binding that ties the Smoothie rack’s (inner) output gain to the instrument rack’s outer output gain. Now the gain slider of my instrument rack smoothly follows the gain slider of the Smoothie rack.

  • Set “output Gain” State Behavior of the Smoothie rack to “on” - now I can easily set the target level of the respective instrument by using the gain slider of the Smoothie rack. And I can hear the result in real time, since the instrument rack’s gain will follow automatically, so it’s easy to set my target levels “by ear”

  • The Smoothie rack has different rack states as “speed presets” → 0.3 sec, 0.5 sec, 1 sec, 2 secs, … By setting state behavior for “Selected Rack State”, I can have different ramping speeds for every song state change → have a slow volume ramp-up at the beginning of the song, then faster smoothed volume changes between states.

  • The usage of this rack isn’t limited to changing rack volumes - I can easily use it to send smooth expression pedal moves with a different binding or any other smooth change that I’ll need during a song

Here is the rack, in case someone wants to try it:
Smoothie 1.zip (3.2 KB)

BTW: there is a "Song->OnLoad Song->OnUnload binding in there that sets the input value to something you typically wouldn’t set it to in a song. This is to make sure that the first “real” value the rack receives from the first state change in a song actually is a change, so Cantabile tells the binding to fire. A bit of a brute-force approach, but should work. I’ll have to test it for some time…

And this is what the bindings look like in a song:


(I just created the second binding to test if Smoothie can also create nice MIDI fades - seems to work nicely as well)

The Smoothie rack doesn’t need to be routed in any way - all you need is the binding:

Cheers,

Torsten

2 Likes

OK, did some more testing - looks like the “brute force” approach of initializing doesn’t really work - the rack doesn’t seem to receive the initial state-specific output gain level after the Song-OnLoad binding, so the first state value doesn’t “stick” - will have to do some more experimenting here… For the time being, I’ve updated the binding to a “Song->OnUnload” binding, which seems to work better.

It seems that the event sequence in Cantabile isn’t 100% strict - I had expected the sequence to be Song->OnLoad, then all the State load state behavior loading, but in this case, it looks like the state load for the first state doesn’t come after the rack’s Song->OnLoad.

@brad: is there a way that I could force a specific binding to update its output on song load even though the input value hasn’t changed? This would be extremely helpful for all kinds of initialization bindings. Currently, I need to use different kinds of brute-force approaches to make sure that my automation racks catch the first state of a song correctly…

Happy to consider some thing like this, but not exactly sure where it fits. Do you mean a per-binding option “Resend on Song Load” and/or “Resent on State Load”.

Also don’t forget there’s a “Resend Bound Values” target binding point on songs and racks. Does that help?

Oh, I wasn’t aware of that target point - looks interesting! Not yet 100% sure if this will do it, but let me explain:

My key use case for this with automation racks - used to create smooth transitions between song states. These racks all have internal values within a plugin (e.g. Smoothy or ReaJS); these get changed via State Behaviors; then the plugin will create a smooth transition. This will be sent to one or more receiving plugins to steer levels or parameters, via MIDI routes or direct bindings.

The key issue with this is that for these racks to notice something has changed, they need to receive a value via the State Behavior. Since Cantabile’s State Behavior doesn’t send the plugin a new value unless there is a difference between the current parameter within the rack and the target value in State Behavior, there may be cases that after loading a new song, the automation rack doesn’t change its state, but the controlled plugins/racks are in a different state → not good…

To be sure that everything is initialized, I would like to have a mechanism to force the plugin within the automation rack to initialize and send the correct target value on the first state of a song - of course AFTER the saved State Behavior value within the song has been loaded.

So the sequence of events is important; what happens in what sequence?

  • Song->OnLoad bindings
  • Loading of State Behavior values for the first state

My initial idea was to use Song->OnLoad to set the rack state to something that will definitely be changed by the first State Behavior value, but that didn’t seem to work. The Song->OnLoad does trigger the ramp mechanism within the plugin to the target set in Song->OnLoad, but then the ramp towards the StateBehavior of the first state doesn’t happen. So it looks like Song->OnLoad comes after the internal Rack State Load? @brad, can you clarify this?

Currently, I’m using Song->OnUnload to set the rack to a “dirty” value that will be changed by the first state of the next song, so the ramping mechanism will be triggered. Works, but a bit clumsy…

The problem with “Resend Bound Values” is that it will only trigger the “outbound” bindings of a rack that depend on exposed plugin parameters; this will work with the “Smoothy” rack, since that contains the actual output value as a plugin parameter. But with my ReaJS based MIDI automation, this wouldn’t work: it will only send MIDI data when its sliders (plugin parameters) are updated via State Load - the sliders are VST parameters, but they aren’t used in output bindings; the output is sent solely via MIDI routes.

So to be 100% sure, I would need a mechanism that allows me to force State Behaviors to send value updates to plugins contained in the rack on Song Load, to force the plugins to “do their thing” at the beginning of a song to make sure that all “dependent” racks get initialized…

The most immediate question to go the next step: when are “Song->OnLoad” bindings triggered within racks? Before or after the State Behavior values get loaded (I assumed this is “State->OnLoad”)? Unless this is 100% clear, I’m struggling to put the right mechanism in place (can I use a Song->OnLoad to initialize the first state?).

Hope this all makes some kind of sense - sorry for the convoluted explanation; still trying to understand in detail how the sequence of song and state loading works with State Behaviors …

Cheers,

Torsten

Hey @Torsten,

This is definitely a complex area. Let’s summarise the current way things work:

For a single triggering event, the order bindings are invoked is defined here but is basically:

  1. song
  2. the songs racks (in song order)
  3. any nest embedded racks in the song’s rack (in undefined order)
  4. the background rack.

Remember, this is for a single event. ie: events that are broadcast across songs and racks (eg: a Song Load event) will trigger the bindings in the above order.

On top of this is the order of the events, which for song and state load events is:

  1. Rack Load
  2. Rack State Load
  3. Above repeated for all racks
  4. Song Load
  5. Song State Load

Combining all the above, for a song with 2 racks you get this order: (object <= event)

  1. Rack 1 <= Rack Load
  2. Rack 1 <= Rack State Load
  3. Rack 2 <= Rack Load
  4. Rack 2 <= Rack State Load
  5. Song <= Song Load
  6. Rack 1 <= Song Load
  7. Rack 2 <= Song Load
  8. Song <= Song State Load
  9. Rack 1 <= Song State Load
  10. Rack 2 <= Song State Load

Now consider the case where the same two racks are used in two songs and in both songs, both racks use the same states:

  1. Song <= Song Load
  2. Rack 1 <= Song Load
  3. Rack 2 <= Song Load
  4. Song <= Song State Load
  5. Rack 1 <= Song State Load
  6. Rack 2 <= Song State Load

If the racks however use different states, you’ll get this: (same as initial load, but without the rack load events - because the racks are already loaded).

  1. Rack 1 <= Rack State Load
  2. Rack 2 <= Rack State Load
  3. Song <= Song Load
  4. Rack 1 <= Song Load
  5. Rack 2 <= Song Load
  6. Song <= Song State Load
  7. Rack 1 <= Song State Load
  8. Rack 2 <= Song State Load

Now let’s look at where state behaviour parameters fit into things. Lets assume Rack 1 has a state behaviour controlled plugin parameter. When the parent songs both use the rack with the same state, nothing happens and everything is the same as before:

  1. Song <= Song Load
  2. Rack 1 <= Song Load
  3. Rack 2 <= Song Load
  4. Song <= Song State Load
  5. Rack 1 <= Song State Load
  6. Rack 2 <= Song State Load

If however, the songs have a different states for Rack 1, then the order is:

  1. Parameter is assigned
  2. Rack 1 <= Rack State Load
  3. Song <= Song Load
  4. Rack 1 <= Song Load
  5. Rack 2 <= Song Load
  6. Song <= Song State Load
  7. Rack 1 <= Song State Load
  8. Rack 2 <= Song State Load

As another example, if the song has two states, each loading different state on the rack, then when switching states:

  1. Parameter is assigned
  2. Rack 1 <= Rack State Load
  3. Song <= Song State Load
  4. Rack 1 <= Song State Load
  5. Rack 2 <= Song State Load

Finally, if the plugin parameter is not just state behaviour controlled, but exported to the parent song then the same thing happens:

  1. Parameter is assigned
  2. Rack 1 <= Rack State Load
  3. Song <= Song State Load
  4. Rack 1 <= Song State Load
  5. Rack 2 <= Song State Load

The only difference with the last example, is that even if the song doesn’t change the rack’s state and only affects it through exported state behaviours, the rack state load event still fires (since internally it does a state load to apply the exported state behaviour).

Regarding this:

Unless there’s some edge case I’m not aware of, state controlled plugin parameters are always applied regardless of the plugin’s current value. ie: in the above explanations “Parameter is assigned” is unconditional - it always happens.

I hope this clarifies the current way things work but not sure it helps solve your issue. Let me know if there’s something I can add that will let you solve it.


Note: In writing all this, I found one small bug relating to the order events are fired across racks but I don’t think this affects your scenario. Bug will be fixed in 4139.

1 Like

Wow - great summary! Definitely a keeper for my “Cantabile secrets” book!

OK, then it seems to be more an issue of the “smoothing” plugins - these won’t send output values unless an input parameter changes (makes sense).

One question: the “Re-send bound values” doesn’t seem to work on MIDI output bindings: This binding


doesn’t seem to fire when I force the “Smoothie 1” rack to re-send its bound values with “Output Gain” being the bound value.

My expectation was for the “re-send bound values” to re-send the value of OutParam1 to Rack-Output Gain, and thus for the binding above to send a new MIDI value. But this doesn’t happen - no new MIDI messages appear.

Am I getting this binding wrong?

I had a look at this and the Resend Bound Values binding is working fine and the Rack’s Output Gain is reapplied. The problem is, if the Output Gain value doesn’t actually change, then the binding from it to the MIDI point doesn’t get triggered.

This is not an easy thing to change in Cantabile - there’s lots of places where redundant value assignments are suppressed.

Two suggestions:

  1. Instead of Output Gain, use a MIDI event
  2. Trigger the Resend Bound Values binding on the rack with the MIDI binding - not the rack with the param to output gain binding.

yes, that looks like the elegant solution - make the Smoothie rack output both smoothed output gain AND ramped Midi CC output. In that case, resend bound values should work.

I’ll test this tomorrow…

Quick note: In case anyone is still using the original version of the Smoothie VST, I recommend updating to the latest one (currently v1.2), which is downloadable from the github link in the first post of this thread.

Great to hear that folks are finding it useful!

4 Likes