I’m setting up Ardour for use with my X-touch compact control surface, and am running into some limitations that I would like to resolve. In this post, I’ll share some thoughts on this, and hope to get some feedback and maybe suggestions.
Background
I’m new to Ardour, just starting my first project, which is making a nice mix from a live recording of a choir/musical group performance, including both spoken scenes and songs. I have 21 channels, each individual singer/actor is separate, so I suspect my workflow might be a bit different than the typical usecase of a small band with diverse instruments, or producing electronic music. In particular, I suspect there will be a lot of repetition in my work, which makes it particularly useful to be able to use my X-touch as much as possible. However, since I’m not very familiar with Ardour, I might also be hung up on a particular work flow I think I want, even when that might not be the best approach in practice (so feel free to call me out on that). I’m an embedded software engineer by trade, so I have a tendency to add code to make things do what I want (I’ve already dug around the Ardour codebase a bit this week…).
Intended workflow
So, the workflow I imagine is similar to what the Mackie Control mode in Ardour offers:
- Use banks to access all channels, with faders for the channel fader gain, buttons for solo/mute/select.
- My X-Touch Compact (XT) has one encoder per channel, so I would like to change its function using other buttons (i.e. switch between channel trim, panning, FX send, etc.).
- For controlling plugins, I imagine using the 8 extra encoders to control plugin parameters on the selected channel. Since there are more parameters than I have encoders, I would select the set of parameters to edit using one of the encoders or buttons (i.e. press one button to select EQ band 1, another to select EQ band 2, one more for the compressor), etc.
AFAICS I cannot achieve this with the MC mode, because the MC mode does not offer editing plugin paramters, and also the MC mode on my XT does not send the right MC commands for this anyway (which could be remapped on the XT side, but still prevents editing plugin params AFAICS).
Using the Generic MIDI control surface in Ardour, I think I can express every control (provided I use a consistent plugin ordering, since identifiying plugins by name is not possible), except that I cannot seem to use the same encoder for different purposes. The Sn/Bn strip numbering does allow for using a single encoder to control different tracks, but I cannot see a builtin way to switch one encoder between e.g. EQ band 1 freq and EQ band 2 freq.
Implementation
So, I’m considering some approaches to make this possible:
- Modify Ardour Generic MIDI code to support “mode variables”. I can imagine entries in a MIDI map could either set a specific mode variable (possibly in addition to, or instead of a normal action/uri/function), other entries could then be tagged to only be active in a specific mode (plus some code to handle feedback when switching modes). It’s probably quite a bit of work to get this working quickly and not as flexible as some of the other options below (especially relevant while I’m still exploring what I need exactly).
- Adding a LUA session script that essentially implements a control surface driver by reading MIDI and applying the changes directly. Upside of LUA is that you can potentially control more than what is exposed through OSC/Generic MIDI, but this does mean reimplementing a lot of things (feedback, banking, etc.). I’m also worried a bit about the development experience - reloading and debugging sessions scripts did not look very convenient at first glance.
- Running an external service (probably a python script) that reads MIDI and controls Ardour through OSC. This is probably a lot more convenient to develop, and reuses stuff (feedback, banking) from the OSC implementation in Ardour. Specifying the mapping, including mode switches, can probably be generalized with a bit of YAML or JSON.
- The same, but using Open Stage Control with a custom module to translate MIDI to OSC and back. This might be even easier, since Open Stage Control already handles MIDI and OSC connections, and I can just implement the right filters. As an added advantage, it is probably easy to add some additional UI (i.e. show the current bank and mode).
- Using an external MIDI translator, such as mididings. This would map all possible controls in the Ardour MIDI map to different MIDI messages, and then use mididings scenes for modes, mapping the same encoder to different midi messages based on the current mode/scene. Downside of this approach is that it splits the mapping configuration between Ardour and mididings, which is not so nice.
- The same, but using x42 MIDI filtering plugins inside Ardour to do the mapping. This keeps everything inside Ardour, but probably results in a complex stack of plugins that control themselves, so probably more complex than splitting the config between Ardour and mididings (if it is at all possible, I’m not sure).
Right now, I’m inclined to try option 4, using Open Stage Control to map my XT to Ardour’s OSC messages. Given the mapping will be done by a bit of my own custom code, this also gives extra flexibility to implement extra things (possibly hardcoded) I might figure out I need later on. Does this make sense? Or are there other ways that I might have missed?
Unifying control surface implementations?
Looking a bit around the control surface implementations, I did also wonder if it would not make sense to unify them more. E.g. MC surfaces are (or at least can be, I think) essentially just sending MIDI, so if the MIDI mapping was made sufficiently expressive, a separate MC implementation would not be needed at all. Also, the Generic MIDI uri/action/function specifiers are largely the same (i.e. they can express the same things) as OSC addresses, so it would make sense (to my outsider newbie mind) to just map MIDI messages into OSC messages, making things more uniform and potentially easier to maintain (and exposing new things benefits more surfaces then instead of having to duplicate work). I can imagine this is not currently the case because of how things evolved and the effort of making the conversion now, or maybe there are technical reasons to not allow this.