Mixer API Design
Most devices contain an onboard mixer. This document tries to come up with a API that will allow external programs to access these mixers. It is the intermediate layer between the FFADO low level code and the mixer & control application(s).
Jonathan's initial proposal
Over what turned out to be a very busy weekend I managed to start outlining my current thoughts about the control API. These thoughts are given in note form below. It should be work noting that the flexibility of the API comes from having seen a number of non-ffado interfaces which have needed more than what a typical ffado interface might. There's no actual code yet - sorry. This is really a snapshot of one possible direction I think we could take.
Yes, at first glance this probably looks a little more complicated than it needs to be. However, given the great variety in devices we're trying to abstract here I think the underlying system needs to be this flexible. Otherwise we'll end up having to write device-specific control applications which would be a real pain to maintain.
Anyway, see what you think and let me know.
What we require
- provide mixer and device controls for a ffado-supported devices
- allow device to feed hardware changes back to the software if supported by the device
- sometimes some controls can only be used if streaming is not active (and vice versa). Deal with this.
- query whether streaming is active
- request controls supported by the device. Some controls might be disabled depending on whether streaming is active or not.
- Could have the option of starting the streaming layer if it's not running. This must remain optional however since some controls become unusable if streaming is operational (change sample rate for example).
- set a given control to a given setting.
- control values to be normalised; the driver does the conversion to "real" device units as required.
- ability to set a callback which is called whenever hardware causes a control value to change. We'll call this the "hardware control callback", at least for now.
A number of so-called "control widgets" will be supported by the API. Every control widget will include a number of properties:
- a name
- a unique ID number
- "enabled" flag (possibly as part of a generic flags field)
- volume control
- assumed logarithmic, in units of dB
- range is -inf to some driver-specified maximum (some devices implement controls which both cut and boost volume).
- Possibly include a "number of steps" hint.
- pan control
- scale is -1 to +1
- again, a "number of steps" hint might make GUI issues easier to deal with.
- multiselection list
- each item can be either on or off
- generic toggle switch
- two states: on and off
- probably a special case of the multiselection list with one item
- single selection list
- only one item can be selected
We also need the concept of a control container to facilitate GUI construction. A container consists of a list of widgets along with:
- a name
- container type (currently group, device, bus, channel)
- one or more child containers or controls.
Types of containers:
- group: groups related controls together (mainly to facilitate GUI arrangements)
- device: collects all global device controls
- bus: consists of controls applicable to a single output bus. Normally it would contain a number of channel containers along with perhaps a "bus master volume" control.
- channel: collects all controls associated with a given channel.
Conceptual object hierarchy
control_base [ abstract classs ]
- control type (inherent from object class perhaps)
- name, id, flags
- container type (group, device, bus or channel, inherent from object class perhaps)
- child control list (control_base)
- min, max, value (in dB)
- value (-1.0 ... +1.0)
control_list(control_base) [ abstract class ]
- list item array
The ffado API should provide a single call to query the device control list. This will return a tree of control objects; the top-level control should be a container which logically groups all a device's controls together. This makes it easier to keep track of controls when multiple devices are in use.
Hardware control callback
Some devices use substreams in the iso stream to send control changes made with hardware back to the software. There is therefore a need for a libffado application which starts the streaming layer to be able to send this control data off to another libffado application. At the lowest level this would consist of a KV stream; the key would be the ID of the control which changed, the value being the new value. It is envisaged that this information will be conveyed via some form of shared memory interface.
Still to be considered
ffado itself is C++. The control API probably needs to be C so as to not place limits on control application developers.
As far as I can tell, OSC can provide everything we need for communication between control and backend/engine.
We can have the library implement an OSC namespace (doesn't seem to be very hard) and have the clients explore this to discover the available options:
some example: /freebob/devices/[devnr]/name /freebob/devices/[devnr]/mixer/[bus]/[channel]/value
/freebob/devices/[devnr]/events/0/name /freebob/devices/[devnr]/events/0/subscribe /freebob/devices/[devnr]/events/0/unsubscribe
At first this provides an easy way to implement this, and have some control GUI's really fast (e.g. using Khagan).
On the long run this can also solve our control w/o backend problems, by implementing a 'non-streaming server', along with a 'takeover' method and some master-slave concepts to support multiple servers (e.g. when 2 devices are each on a separate jackd). But this part might be done by some new developer we're going to attract soon ;) .
InitalOscSpace -- a first try