motu: implement block async functions since they are ultimately required when dealing...
[ffado.git] / libffado / src / motu / motu_mixer.cpp
blobec1b372d505c528d817ea220be2e40be49ab1135
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
3 * Copyright (C) 2005-2009 by Jonathan Woithe
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB.
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) version 3 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 /* This file collects together everything associated with the management
26 * of mixer controls in the MOTU device object.
29 #include "motu/motu_avdevice.h"
30 #include "motu/motu_mixerdefs.h"
31 #include "motu/motu_mark3_mixerdefs.h"
33 namespace Motu {
35 bool
36 MotuDevice::buildMixerAudioControls(void) {
38 bool result = true;
39 MotuMatrixMixer *fader_mmixer = NULL;
40 MotuMatrixMixer *pan_mmixer = NULL;
41 MotuMatrixMixer *solo_mmixer = NULL;
42 MotuMatrixMixer *mute_mmixer = NULL;
43 const struct MatrixMixBus *buses = NULL;
44 const struct MatrixMixChannel *channels = NULL;
45 unsigned int bus, ch, i;
47 if (DevicesProperty[m_motu_model-1].mixer == NULL) {
48 debugOutput(DEBUG_LEVEL_INFO, "No pre-Mark3 mixer defined for model %d\n", m_motu_model);
49 return true;
50 } else {
51 buses = DevicesProperty[m_motu_model-1].mixer->mixer_buses;
52 result = false;
53 if (buses == NULL) {
54 debugOutput(DEBUG_LEVEL_INFO, "No mixer buses defined for model %d\n", m_motu_model);
55 } else
56 result = true;
57 channels = DevicesProperty[m_motu_model-1].mixer->mixer_channels;
58 if (channels == NULL) {
59 debugOutput(DEBUG_LEVEL_INFO, "No mixer channels defined for model %d\n", m_motu_model);
60 } else
61 result = true;
62 if (DevicesProperty[m_motu_model-1].mixer->mixer_ctrl == NULL) {
63 debugOutput(DEBUG_LEVEL_INFO, "No mixer device controls defined for model %d\n", m_motu_model);
64 } else
65 result = true;
67 if (result == false) {
68 return true;
71 /* Create the top-level matrix mixers */
72 fader_mmixer = new ChannelFaderMatrixMixer(*this, "fader");
73 result &= m_MixerContainer->addElement(fader_mmixer);
74 pan_mmixer = new ChannelPanMatrixMixer(*this, "pan");
75 result &= m_MixerContainer->addElement(pan_mmixer);
76 solo_mmixer = new ChannelBinSwMatrixMixer(*this, "solo",
77 MOTU_CTRL_MASK_SOLO_VALUE, MOTU_CTRL_MASK_SOLO_SETENABLE);
78 result &= m_MixerContainer->addElement(solo_mmixer);
79 mute_mmixer = new ChannelBinSwMatrixMixer(*this, "mute",
80 MOTU_CTRL_MASK_MUTE_VALUE, MOTU_CTRL_MASK_MUTE_SETENABLE);
81 result &= m_MixerContainer->addElement(mute_mmixer);
83 for (bus=0; bus<DevicesProperty[m_motu_model-1].mixer->n_mixer_buses; bus++) {
84 fader_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address);
85 pan_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address);
86 solo_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address);
87 mute_mmixer->addRowInfo(buses[bus].name, 0, buses[bus].address);
90 for (ch=0; ch<DevicesProperty[m_motu_model-1].mixer->n_mixer_channels; ch++) {
91 uint32_t flags = channels[ch].flags;
92 if (flags & MOTU_CTRL_CHANNEL_FADER)
93 fader_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs);
94 if (flags & MOTU_CTRL_CHANNEL_PAN)
95 pan_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs);
96 if (flags & MOTU_CTRL_CHANNEL_SOLO)
97 solo_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs);
98 if (flags & MOTU_CTRL_CHANNEL_MUTE)
99 mute_mmixer->addColInfo(channels[ch].name, 0, channels[ch].addr_ofs);
100 flags &= ~(MOTU_CTRL_CHANNEL_FADER|MOTU_CTRL_CHANNEL_PAN|MOTU_CTRL_CHANNEL_SOLO|MOTU_CTRL_CHANNEL_MUTE);
101 if (flags) {
102 debugOutput(DEBUG_LEVEL_WARNING, "Control %s: unknown flag bits 0x%08x\n", channels[ch].name, flags);
106 // Single non-matrixed mixer controls get added here. Channel controls are supported
107 // here, but usually these will be a part of a matrix mixer.
108 for (i=0; i<DevicesProperty[m_motu_model-1].mixer->n_mixer_ctrls; i++) {
109 const struct MixerCtrl *ctrl = &DevicesProperty[m_motu_model-1].mixer->mixer_ctrl[i];
110 unsigned int type;
111 char name[100];
112 char label[100];
114 if (ctrl == NULL) {
115 debugOutput(DEBUG_LEVEL_WARNING, "NULL control at index %d for model %d\n", i, m_motu_model);
116 continue;
118 type = ctrl->type;
119 if (type & MOTU_CTRL_CHANNEL_FADER) {
120 snprintf(name, 100, "%s%s", ctrl->name, "fader");
121 snprintf(label,100, "%s%s", ctrl->label,"fader");
122 result &= m_MixerContainer->addElement(
123 new ChannelFader(*this, ctrl->dev_register, name, label, ctrl->desc));
124 type &= ~MOTU_CTRL_CHANNEL_FADER;
126 if (type & MOTU_CTRL_CHANNEL_PAN) {
127 snprintf(name, 100, "%s%s", ctrl->name, "pan");
128 snprintf(label,100, "%s%s", ctrl->label,"pan");
129 result &= m_MixerContainer->addElement(
130 new ChannelPan(*this,
131 ctrl->dev_register,
132 name, label,
133 ctrl->desc));
134 type &= ~MOTU_CTRL_CHANNEL_PAN;
136 if (type & MOTU_CTRL_CHANNEL_MUTE) {
137 snprintf(name, 100, "%s%s", ctrl->name, "mute");
138 snprintf(label,100, "%s%s", ctrl->label,"mute");
139 result &= m_MixerContainer->addElement(
140 new MotuBinarySwitch(*this, ctrl->dev_register,
141 MOTU_CTRL_MASK_MUTE_VALUE, MOTU_CTRL_MASK_MUTE_SETENABLE,
142 name, label, ctrl->desc));
143 type &= ~MOTU_CTRL_CHANNEL_MUTE;
145 if (type & MOTU_CTRL_CHANNEL_SOLO) {
146 snprintf(name, 100, "%s%s", ctrl->name, "solo");
147 snprintf(label,100, "%s%s", ctrl->label,"solo");
148 result &= m_MixerContainer->addElement(
149 new MotuBinarySwitch(*this, ctrl->dev_register,
150 MOTU_CTRL_MASK_SOLO_VALUE, MOTU_CTRL_MASK_SOLO_SETENABLE,
151 name, label, ctrl->desc));
152 type &= ~MOTU_CTRL_CHANNEL_SOLO;
155 if (type & MOTU_CTRL_MIX_FADER) {
156 snprintf(name, 100, "%s%s", ctrl->name, "fader");
157 snprintf(label,100, "%s%s", ctrl->label,"fader");
158 result &= m_MixerContainer->addElement(
159 new MixFader(*this, ctrl->dev_register, name, label, ctrl->desc));
160 type &= ~MOTU_CTRL_MIX_FADER;
162 if (type & MOTU_CTRL_MIX_MUTE) {
163 snprintf(name, 100, "%s%s", ctrl->name, "mute");
164 snprintf(label,100, "%s%s", ctrl->label,"mute");
165 result &= m_MixerContainer->addElement(
166 new MixMute(*this, ctrl->dev_register, name, label, ctrl->desc));
167 type &= ~MOTU_CTRL_MIX_MUTE;
169 if (type & MOTU_CTRL_MIX_DEST) {
170 snprintf(name, 100, "%s%s", ctrl->name, "dest");
171 snprintf(label,100, "%s%s", ctrl->label,"dest");
172 result &= m_MixerContainer->addElement(
173 new MixDest(*this, ctrl->dev_register, name, label, ctrl->desc));
174 type &= ~MOTU_CTRL_MIX_DEST;
177 if (type & MOTU_CTRL_INPUT_UL_GAIN) {
178 snprintf(name, 100, "%s%s", ctrl->name, "trimgain");
179 snprintf(label,100, "%s%s", ctrl->label,"trimgain");
180 result &= m_MixerContainer->addElement(
181 new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_UL_GAIN,
182 name, label, ctrl->desc));
183 type &= ~MOTU_CTRL_INPUT_UL_GAIN;
185 if (type & MOTU_CTRL_INPUT_PHASE_INV) {
186 snprintf(name, 100, "%s%s", ctrl->name, "invert");
187 snprintf(label,100, "%s%s", ctrl->label,"invert");
188 result &= m_MixerContainer->addElement(
189 new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_PHASE_INV,
190 name, label, ctrl->desc));
191 type &= ~MOTU_CTRL_INPUT_PHASE_INV;
193 if (type & MOTU_CTRL_INPUT_TRIMGAIN) {
194 snprintf(name, 100, "%s%s", ctrl->name, "trimgain");
195 snprintf(label,100, "%s%s", ctrl->label,"trimgain");
196 result &= m_MixerContainer->addElement(
197 new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_TRIMGAIN,
198 name, label, ctrl->desc));
199 type &= ~MOTU_CTRL_INPUT_TRIMGAIN;
201 if (type & MOTU_CTRL_INPUT_PAD) {
202 snprintf(name, 100, "%s%s", ctrl->name, "pad");
203 snprintf(label,100, "%s%s", ctrl->label,"pad");
204 result &= m_MixerContainer->addElement(
205 new InputGainPadInv(*this, ctrl->dev_register, MOTU_CTRL_MODE_PAD,
206 name, label, ctrl->desc));
207 type &= ~MOTU_CTRL_INPUT_PAD;
210 if (type & MOTU_CTRL_INPUT_LEVEL) {
211 snprintf(name, 100, "%s%s", ctrl->name, "level");
212 snprintf(label,100, "%s%s", ctrl->label,"level");
213 result &= m_MixerContainer->addElement(
214 new MotuBinarySwitch(*this, MOTU_REG_INPUT_LEVEL,
215 1<<ctrl->dev_register, 0, name, label, ctrl->desc));
216 type &= ~MOTU_CTRL_INPUT_LEVEL;
218 if (type & MOTU_CTRL_INPUT_BOOST) {
219 snprintf(name, 100, "%s%s", ctrl->name, "boost");
220 snprintf(label,100, "%s%s", ctrl->label,"boost");
221 result &= m_MixerContainer->addElement(
222 new MotuBinarySwitch(*this, MOTU_REG_INPUT_BOOST,
223 1<<ctrl->dev_register, 0, name, label, ctrl->desc));
224 type &= ~MOTU_CTRL_INPUT_BOOST;
226 if (type & MOTU_CTRL_PHONES_SRC) {
227 snprintf(name, 100, "%s%s", ctrl->name, "src");
228 snprintf(label,100, "%s%s", ctrl->label,"src");
229 result &= m_MixerContainer->addElement(
230 new PhonesSrc(*this, name, label, ctrl->desc));
231 type &= ~MOTU_CTRL_PHONES_SRC;
233 if (type & MOTU_CTRL_OPTICAL_MODE) {
234 result &= m_MixerContainer->addElement(
235 new OpticalMode(*this, ctrl->dev_register,
236 ctrl->name, ctrl->label, ctrl->desc));
237 type &= ~MOTU_CTRL_OPTICAL_MODE;
239 if (type & MOTU_CTRL_METER) {
240 if (ctrl->dev_register & MOTU_CTRL_METER_PEAKHOLD) {
241 snprintf(name, 100, "%s%s", ctrl->name, "peakhold_time");
242 snprintf(label,100, "%s%s", ctrl->label,"peakhold time");
243 result &= m_MixerContainer->addElement(
244 new MeterControl(*this, MOTU_METER_PEAKHOLD_MASK,
245 MOTU_METER_PEAKHOLD_SHIFT, name, label, ctrl->desc));
247 if (ctrl->dev_register & MOTU_CTRL_METER_CLIPHOLD) {
248 snprintf(name, 100, "%s%s", ctrl->name, "cliphold_time");
249 snprintf(label,100, "%s%s", ctrl->label,"cliphold time");
250 result &= m_MixerContainer->addElement(
251 new MeterControl(*this, MOTU_METER_CLIPHOLD_MASK,
252 MOTU_METER_CLIPHOLD_SHIFT, name, label, ctrl->desc));
254 if (ctrl->dev_register & MOTU_CTRL_METER_AESEBU_SRC) {
255 snprintf(name, 100, "%s%s", ctrl->name, "aesebu_src");
256 snprintf(label,100, "%s%s", ctrl->label,"AESEBU source");
257 result &= m_MixerContainer->addElement(
258 new MeterControl(*this, MOTU_METER_AESEBU_SRC_MASK,
259 MOTU_METER_AESEBU_SRC_SHIFT, name, label, ctrl->desc));
261 if (ctrl->dev_register & MOTU_CTRL_METER_PROG_SRC) {
262 snprintf(name, 100, "%s%s", ctrl->name, "src");
263 snprintf(label,100, "%s%s", ctrl->label,"source");
264 result &= m_MixerContainer->addElement(
265 new MeterControl(*this, MOTU_METER_PROG_SRC_MASK,
266 MOTU_METER_PROG_SRC_SHIFT, name, label, ctrl->desc));
268 type &= ~MOTU_CTRL_METER;
271 if (type) {
272 debugOutput(DEBUG_LEVEL_WARNING, "Unknown mixer control type flag bits 0x%08x\n", ctrl->type);
275 return result;
278 bool
279 MotuDevice::buildMark3MixerAudioControls(void) {
281 bool result = true;
283 if (DevicesProperty[m_motu_model-1].m3mixer == NULL) {
284 debugOutput(DEBUG_LEVEL_INFO, "No Mark3 mixer controls defined for model %d\n", m_motu_model);
285 return false;
288 // FIXME: Details to come
289 result = false;
291 return result;
294 bool
295 MotuDevice::buildMixer() {
296 bool result = true;
297 debugOutput(DEBUG_LEVEL_VERBOSE, "Building a MOTU mixer...\n");
299 destroyMixer();
301 // create the mixer object container
302 m_MixerContainer = new Control::Container(this, "Mixer");
303 if (!m_MixerContainer) {
304 debugError("Could not create mixer container...\n");
305 return false;
308 if (DevicesProperty[m_motu_model-1].mixer != NULL &&
309 DevicesProperty[m_motu_model-1].m3mixer != NULL) {
310 debugError("MOTU model %d has pre-Mark3 and Mark3 mixer descriptions\n", m_motu_model);
311 return false;
314 // Create and populate the top-level matrix mixers
315 result = buildMixerAudioControls() || buildMark3MixerAudioControls();
317 /* Now add some general device information controls. These may yet
318 * become device-specific if it turns out to be easier that way.
320 result &= m_MixerContainer->addElement(
321 new InfoElement(*this, MOTU_INFO_MODEL, "Info/Model", "Model identifier", ""));
322 result &= m_MixerContainer->addElement(
323 new InfoElement(*this, MOTU_INFO_IS_STREAMING, "Info/IsStreaming", "Is device streaming", ""));
324 result &= m_MixerContainer->addElement(
325 new InfoElement(*this, MOTU_INFO_SAMPLE_RATE, "Info/SampleRate", "Device sample rate", ""));
327 if (!addElement(m_MixerContainer)) {
328 debugWarning("Could not register mixer to device\n");
329 // clean up
330 destroyMixer();
331 return false;
334 // Special controls
335 m_ControlContainer = new Control::Container(this, "Control");
336 if (!m_ControlContainer) {
337 debugError("Could not create control container...\n");
338 return false;
341 // Special controls get added here
343 if (!result) {
344 debugWarning("One or more device control elements could not be created.");
345 // clean up those that couldn't be created
346 destroyMixer();
347 return false;
349 if (!addElement(m_ControlContainer)) {
350 debugWarning("Could not register controls to device\n");
351 // clean up
352 destroyMixer();
353 return false;
356 return true;
360 bool
361 MotuDevice::destroyMixer() {
362 debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
364 if (m_MixerContainer == NULL) {
365 debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
366 return true;
369 if (!deleteElement(m_MixerContainer)) {
370 debugError("Mixer present but not registered to the avdevice\n");
371 return false;
374 // remove and delete (as in free) child control elements
375 m_MixerContainer->clearElements(true);
376 delete m_MixerContainer;
377 m_MixerContainer = NULL;
379 // remove control container
380 if (m_ControlContainer == NULL) {
381 debugOutput(DEBUG_LEVEL_VERBOSE, "no controls to destroy...\n");
382 return true;
385 if (!deleteElement(m_ControlContainer)) {
386 debugError("Controls present but not registered to the avdevice\n");
387 return false;
390 // remove and delete (as in free) child control elements
391 m_ControlContainer->clearElements(true);
392 delete m_ControlContainer;
393 m_ControlContainer = NULL;
395 return true;