MIDI volume control

I’m just re-thinking how I use Cantabile, as I move from v2 to v3, and I started wondering how people handle volume settings/control for plugins.

The most visible way is to have rack/plugin gains set for each song state, but then there’s also the MIDI CC7 level which is (generally) applied by the plugin itself (sometimes stored in its patch data, sometimes not). If you generally use rack/plugin gains, do you also use MIDI CC7 messages to set the plugin’s MIDI volume? Do you explicitly set it with a controller message and then just use Cantabile’s gain control? Do you adjust the plugin’s internal volume at the patch level, store it within the patch, and then just forget about MIDI CC7 control? If you control volumes dynamically from your controller keyboard, do you use MIDI CC7 on the plugin, or do you use a binding to control the rack/plugin gain?

Just wondering what everyone’s doing, and if there’s a best practice here.

Neil

Hi Neil,

I’m not sure what the right answer for this is except to say it might be personal preference. I remember discussing cc7 once before and we thought it would be handy to be able to assign this at the plugin level to the plugin slots gain level. (ie: cc assignments within the plugin slot). If you think that’s something that would still be handy let me know.

Brad

Hi Neil,

no best practice (I’m sure there is no best practice as this is individual) but the way I’m handling this:

I predefine several MIDI channels for several functions. (f.e. dynamic volume is always happening on channel 11 here). Principielly spoken: this can be chosen absolutely free (I call it my “MIDI port model” ;-)).

For virtual MIDI ports I map controller information to meaningful channels (f.e. volume pedal always to Cc11, mod wheel to Cc01,…)

On the rackside the same: controlling volume always via Cc11,… Also untypical controllers can be mapped in some cases (f.e. sustain pedal napped to the level of a hammonds lesley)

All not needed controls are suppressed so no problems with unwanted changes etc.

Controlling volume levels in plugs depends on the vsti:

  1. If the vsti has the possibility to trim the output level independently from Cc07 or Cc11 dynamic volume (means what I want to control live) is mapped to Cc11.

  2. If the vsti is only able to trim volume by a MIDI control I use this to trim the volume inside and add a volume control vst to the rack which again can be controlled by Cc11.

  3. If the vsti has no fixed mapping to a MIDI controller or if this only can be done by learn function I use the automated parameter MIDI filter if there is a second parameter to trim the volume. Otherwise again a plugin can be added to control volume by MIDI.

Probably you ask why not using the gain settings instead if internal trimming? Well this is possible of course and in most cases the internal trimming is not urgently necessary. I use this as I like to drive plugs to a useful level so that stacked instruments make a good iverall sound even though all gain faders are at 0dB. Gain faders are left for finetuning.

The other aspect are vstis that can be driven extremly “hot” (f.e. DIVA does with some patches): if I map a volume pedal to the volume controller inside I get levels of +20-30dB. Technical this is not a problem due to floating point math in cantabile but I find it idd to have gain faders at -30dB and permanently orange level meters…

So far the way I handle volume- (and other) MIDI controllers. I gave a further scetch of what I’m doing with MIDI routing here:

if you’re interested.

Sure there are many other ways to handle this.

Regards, humphrey

I tend to use both volume levels AND CC7 messages to control volume:

  • all my instruments are encapsulated in racks
  • I use the plugins’ volume levels within the racks to balance the individual rack’s presets to similar loudness (or to boost a dedicated solo sound)
  • I use rack volume levels to mix song-specific sounds from multiple racks
  • all this together is my “static mix” - now I use CC7 messages to my racks to dynamically change levels using whatever controller / pedal I want to use (I use routes and controller mapping to transform incoming controller messages to CC7 messages to the right racks)
  • all my racks have a Sonalksis FreeG volume fader embedded and a Binding that connects incoming CC7 messages to FreeG’s “volume” parameter. All plugins within a rack route their output to this FreeG plugin, which makes it easy to control the volume of a multi-plugin-rack with one CC7 command.
  • I use song state load triggers in my song files to send CC7 messages to my racks to initialize my manual levels to where I want them to be at the time (maybe turn a string layer all the way down at the beginning of one song, so that I can gradually fade it in, but turn it pretty high up at the beginning of the next song…)
  • I use MIDI filtering to filter CC7 data OUT OF all MIDI routes to my plugins - don’t want any nasty side effects there.

Pretty complex setup (with some interesting debugging to do when things don’t quite do what they are supposed to) - but extremely powerful!

Hope this helps!

Cheers,

Torsten

1 Like

Well, I wouldn’t say no! However, for my own use I think I’m more likely to find value in having cc7 and slot gain as separate volume controls, so that for example you can trim patches to a similar/usable level, and then use slot gains driven by state to set the levels required for parts of songs. But I can imagine it being something users could find useful, especially those who don’t want to dig into lots of detailed programming/setup.

Many thanks Humphrey and Torsten for your fantastic detailed run-down of how you handle volumes - it has given me some good ideas to work into my own setup.

Humphrey - I like your use of CC11 for your expression controller, which you explicitly map to whatever is required in a rack. Keeps things nice and clean and understandable. Similarly, the way you both filter out unnecessary controller information - something I haven’t done up to now in Cantabile 2, and it has caught me out a few times.

Torsten, you mentioned using Sonalksis FreeG in all your racks - do you find it adds much load overhead? On my setup I see a roughly 3% increase in load for each instance of FreeG, which really starts to add up if you use it in lots of places.

Also Torsten, am I right in interpreting that you never let CC7 into your instrument plugins? It’s used entirely to control FreeG?

Hmm, no, on my system (x64, quad-core i7) its load is pretty much neglegible. But you can also do things differently - just remote-control the gain level of the last plugin in the respective rack before the rack’s output via a binding. I’ve just gotten used to doing things via FreeG from my old “monster rack” - may actually re-engineer my racks to work differently in the future.

And yes, I never let CC7 reach my instruments - I like keeping things clean; I set my static levels within the instruments’ patches and additionally their respective gain levels; CC7 is purely for dynamic changes for me, so I direct it elsewhere.

Makes things lots easier to understand and analyse when something misbehaves…

Cheers,

Torsten

1 Like

I’ve done this on my setup and I’ve hit something that worries me - whenever I send a CC7 value into my rack, and it gets routed to FreeG within the rack, the rack becomes marked as modified. Since it’s only a dynamic change from my controller keyboard, I don’t care about the rack being modified. However, when I change to a new song, I get a dialog up asking me if I want to save the rack.

Am I doing something wrong or missing something? How can I control the volume within a rack with CC7 using a fader type plugin, without the rack being “modified” ?

Neil

Hi Neil

you are doing nothing wrong - Cantabile doesn’t distinguish between a manual change (via the GUI) and a change via MIDI. This means that all MIDI-controlled racks and plugins get “modified”.

Maybe @brad could create a Preferences setting “ignore binding-initiated changes for modified status” (hope there is a better wording ;-))

For the moment, I have done two things:

  • turned off all prompts that ask me if I want to save changes on song change etc
  • turned off “automatically save states”

This keeps all plugins and racks in the state I actively saved them. But you really need to be a bit careful - you may lose changes to songs if you forget to manually save the song when stepping to the next. And, reversely, you may accidentally save your rack with a volume slider at 50% if it was that way when you hit “save”.

So maybe a setting that write protects individual plugins within a rack could help here - @brad, would that be something similar to the “scene protect” we discussed?

Cheers,

Torsten

1 Like

Thanks Torsten, glad to know I’m not missing some important understanding here! Your workaround looks like it’ll do the job, although the first of those steps, disabling prompts, is a bit scary.

I’d extend your “ignore binding-initiated changes for modified status” preference idea to also have an “ignore MIDI-initiated changes for modified status”, so it would include dynamic CC7 type changes that don’t go via a binding.

This feels like quite an important problem to solve…

Thinking about it some more, I guess the better solution would actually be my afterthought from the last post: if we could set specific plugins to a “write-protect” status, so that nothing we do to them would affect the way they are stored in the song (and never flag them as “changed”) unless we explicitly tell Cantabile to update them in the song. This would allow us to set the level of our FreeGs once and for all and forget about them.

But it would also allow us to e.g. automate the VB3’s pedal via CC11 and never worry about its changed state erroneously being saved with the state (and have us worry later why our organ starts at such a low volume). Simply set VB3 to “write protect” and not worry about the current preset being changed. When we make a change to the preset, actively tell Cantabile to update the preset; then the plugin (and the containing rack) is marked as “changed”, requiring us to save it.

Not sure how complex this is in implementation - all hinges on how preset management works in C3…

Cheers,

Torsten

1 Like

I really like that Torsten, and the concept would be an easy one for users to understand, whereas “ignore binding-initiated changes for modified status” probably isn’t. The write-protect / lock on a plugin (and rack?) would also give confidence that a good stable working setup will always remain so, while it remains locked.

And most importantly it would certainly fix this particular modified state problem!

1 Like

Hey @Neil_Durant / @Torsten

I’m about to implement some changes for this and thinking of the following two options on the rack:

[x] Selected Rack State Controlled by Parent Song

We discussed this elsewhere with the idea to be able to load a rack state and never have it affected by loading a song.

[x] Always Discard Changes To This Rack

Self explanatory - basically the modified flag is ignored.

Would this cover everything in this area?

Regarding “Selected Rack State Controlled by Parent Song”, I guess you can already approximate this by unchecking state control of rack state for the given rack for every song, right? The difference here being that it’s a rack-level setting, so could disable song control for all songs? Sounds good.

Also would this also work for racks nested within other racks, to prevent the parent rack from controlling the child rack state?

Regarding “Always Discard Changes To This Rack”, that sounds great as long as any rack state changes / reloads (in particular if the same state is selected), should continue to set the state as before. The situation I’m thinking about is where a rack is set up with one of its plugin levels set to zero in a rack state, so the user can fade it up with a pedal during the song. But having modified that level, if the state is selected again, that level should definitely revert to zero again. I guess what I’m getting at is not to implement this by simply not setting a dirty flag when something is changed, as then Cantabile might incorrectly assume the rack hasn’t changed, and conclude the state doesn’t need to be reapplied.

Also, if this option is set, would it mean that changes applied to a rack from the user interface would also be discarded if the state is changed? In other words, any changes, not just from controllers/bindings? I think either would be OK, I’m just asking to clarify. Although I think I’d have a slight leaning towards discarding changes coming in from controllers/bindings, to avoid forgetting to explicitly save after making manual changes.

But those points aside, these settings sound perfect, and as far as I can see will nicely allow for the user case we were discussing.

Neil

I’m fully on one page with Neil regarding the “reload rack on song change” aspect of “always discard changes”. Otherwise this would require all kinds of “song load” triggers to compensate - nasty stuff!

If it was possible, I would also like to have an “Always discard changes” at the plugin level within a rack: maybe only ignore changes to my FreeG plugin within the piano rack, but not to the other plugins? But that might be a bit more complicated to implement…

Regarding “Selected Rack State Controlled by Parent Song”, I guess you can already approximate this by unchecking state control of rack state for the given rack for every song, right? The difference here being that it’s a rack-level setting, so could disable song control for all songs?

I think the main difference here would be that the rack state would be ignored not only on state changes, but also on song LOADING - which would be great for “session-level” racks: select an EQ preset (as a rack state) for live or practice setup at the beginning of a set and not have it changed by loading a new song. IMU this isn’t covered by unchecking state control for the rack state today - correct?

Cheers,

Torsten

Correct - that’s exactly the scenario this is for.

As for the modified flag stuff I’m still trying to understand all the requirements here and how it fits together with pre-loaded racks. Sounds like what’s needed is pre-loaded racks that stay loaded, but certain aspects of the rack to be reset when the song changes.

For me, the point is pretty simple: for all pre-loaded racks, I need their saved state to be re-loaded when a song is loaded, so that any settings that I have explicitly saved to this state are recalled (for example volume settings) - even if this rack is already pre-loaded and in the same state. Specific use-case:

  • I have a “Pad Layer” that contains a FreeG plugin for volume control.
  • in one rack state (“Pad Full”), this plugin is at 0dB, in another (“Pad Mute”), it is at -oo dB.
  • over the course of the song, I remote-control the “Gain” parameter of this FreeG via a slider, mapped to CC7 and routed to this rack, tied via a rack-internal binding to the Gain parameter
  • Now I have “Song 1” that starts with “Pad Layer” in state “Pad Mute”. Over the course of the song, I turn the volume for the pad layer up manually with my fader. Next Song “Song 2” has “Pad Layer” in the same state “Pad Mute”. Cantabile would think: “OK, same rack, same state, no need to re-load” - and my pad would start the song at full volume - not what I want!

So, essentially, I believe all racks should by default re-load their saved states on song change to avoid such nasty song-changing side-effects. Songs should predictably start in the same state, independent of the song that comes before them - otherwise songs would sound different, dependent on where they are in a set list. Carrying over manual changes from one song to the other should be the exception - and for these, I guess the “Selected Rack State Controlled by Parent Song” you propose could do the trick!

Now regarding the “Always Discard Changes” / modified flag in the above scenario:

  • I want to apply “discard changes” specifically to the FreeG plugin in my “Pad Layer” rack, so that all my fader moves get ignored when considering the rack as modified.
  • But OTOH, I want to be able to save a defined fader value with the rack when I want to, so I need to be able to save the Gain when I save the rack. Ideally, Cantabile would ask me every time I save this rack if I want to update the stored settings for any plugin with “discard changes” set. This would help me avoid unwanted changes to the gain and still allow me to make state-specific settings to this parameter.

Hope this makes sense…

Cheers,

Torsten

2 Likes

Nicely put, Torsten - that precisely describes my requirements too.

Neil

Hey Guys,

That sounds good - not sure how to implement it though. The problem I see is that there’s two sets of states here

  1. The full state - when switching from one state to another - everything that needs to be loaded
  2. A reset state - just the things that might have changed during performance

The full state is typically an opaque blob of bytes rendered by the plugin as a preset/bank. Cantabile has no visibility into this to determine what might have changed. On the other hand, the parameters exported by a plugin have granular visibility but often don’t represent the full state of the plugin.

There are a few possibilities here:

  1. Always do a full state load and accept this might be slow (often loading the plugin state is slower than loading the plugin itself). However it would be no slower than switching to a song with a different state.
  2. Have a second set of behaviours that determines what’s controlled by the full load and what’s restored on a reset. I don’t like this at all.
  3. Have a per-plugin setting that says what to do on reload:
    a. Do nothing (current behaviour)
    b. Full state load (equivalent to switching from another state to this one)
    c. Parameter reset only - which would look at the exported parameters and just reset those that are different.

I think 3c might actually be the most common scenario and work for the vast majority of plugins. I can’t imagine there are many plugin settings that change during performance and aren’t exported as parameters. Also parameters typically are fast to update and they can inspected and only those that have change would need to be reset.

Onto the modified flag… not sure I like the idea of “asking every time I save this rack”. How about this:

  1. An option to “discard changes to this plugin when saving rack”. The rack file would be re-written using the originally loaded plugin state.
  2. A right click command “Update Saved State”, or perhaps “Recapture Plugin State” which would replace the originally loaded plugin state with the current plugin state and mark the rack as modified.

Brad

I agree, I think this should deal with any reasonable scenario of the type we’re looking at - we’re dealing with the case where a plugin is remotely controlled for dynamics within a song, so a parameter reset ought to always be sufficient.

I think “Discard changes to this plugin when saving rack” might be confusing though. Does this mean the in-memory rack would have that plugin reset to its previously saved state when saving, as well as for the saved rack? Or just the saved rack, leaving the in-memory rack as it is?

Perhaps having “Save changes to this plugin when saving rack” (defaulting to true) might reduce the confusion risk slightly. So when you save the rack, the flag simply defines whether changes to that plugin since its last “snapshot” are saved, and what you have in memory stays as it is. If you actually want to discard changes you can just reload the current state.

Neil