1 #include "engine/enginemaster.h"
2
3 #include <QList>
4 #include <QPair>
5 #include <QtDebug>
6
7 #include "control/controlaudiotaperpot.h"
8 #include "control/controlpotmeter.h"
9 #include "control/controlpushbutton.h"
10 #include "effects/effectsmanager.h"
11 #include "engine/channelmixer.h"
12 #include "engine/channels/enginechannel.h"
13 #include "engine/channels/enginedeck.h"
14 #include "engine/effects/engineeffectsmanager.h"
15 #include "engine/enginebuffer.h"
16 #include "engine/enginedelay.h"
17 #include "engine/enginetalkoverducking.h"
18 #include "engine/enginevumeter.h"
19 #include "engine/engineworkerscheduler.h"
20 #include "engine/enginexfader.h"
21 #include "engine/sidechain/enginesidechain.h"
22 #include "engine/sync/enginesync.h"
23 #include "mixer/playermanager.h"
24 #include "moc_enginemaster.cpp"
25 #include "preferences/usersettings.h"
26 #include "util/defs.h"
27 #include "util/sample.h"
28 #include "util/timer.h"
29 #include "util/trace.h"
30
EngineMaster(UserSettingsPointer pConfig,const QString & group,EffectsManager * pEffectsManager,ChannelHandleFactoryPointer pChannelHandleFactory,bool bEnableSidechain)31 EngineMaster::EngineMaster(
32 UserSettingsPointer pConfig,
33 const QString& group,
34 EffectsManager* pEffectsManager,
35 ChannelHandleFactoryPointer pChannelHandleFactory,
36 bool bEnableSidechain)
37 : m_pChannelHandleFactory(pChannelHandleFactory),
38 m_pEngineEffectsManager(pEffectsManager->getEngineEffectsManager()),
39 m_masterGainOld(0.0),
40 m_boothGainOld(0.0),
41 m_headphoneMasterGainOld(0.0),
42 m_headphoneGainOld(1.0),
43 m_balleftOld(1.0),
44 m_balrightOld(1.0),
45 m_masterHandle(registerChannelGroup(group)),
46 m_headphoneHandle(registerChannelGroup("[Headphone]")),
47 m_masterOutputHandle(registerChannelGroup("[MasterOutput]")),
48 m_busTalkoverHandle(registerChannelGroup("[BusTalkover]")),
49 m_busCrossfaderLeftHandle(registerChannelGroup("[BusLeft]")),
50 m_busCrossfaderCenterHandle(registerChannelGroup("[BusCenter]")),
51 m_busCrossfaderRightHandle(registerChannelGroup("[BusRight]")) {
52 pEffectsManager->registerInputChannel(m_masterHandle);
53 pEffectsManager->registerInputChannel(m_headphoneHandle);
54 pEffectsManager->registerOutputChannel(m_masterHandle);
55 pEffectsManager->registerOutputChannel(m_headphoneHandle);
56
57 pEffectsManager->registerInputChannel(m_masterOutputHandle);
58 pEffectsManager->registerInputChannel(m_busTalkoverHandle);
59 pEffectsManager->registerInputChannel(m_busCrossfaderLeftHandle);
60 pEffectsManager->registerInputChannel(m_busCrossfaderCenterHandle);
61 pEffectsManager->registerInputChannel(m_busCrossfaderRightHandle);
62 m_bBusOutputConnected[EngineChannel::LEFT] = false;
63 m_bBusOutputConnected[EngineChannel::CENTER] = false;
64 m_bBusOutputConnected[EngineChannel::RIGHT] = false;
65 m_bExternalRecordBroadcastInputConnected = false;
66 m_pWorkerScheduler = new EngineWorkerScheduler(this);
67 m_pWorkerScheduler->start(QThread::HighPriority);
68
69 // Master sample rate
70 m_pMasterSampleRate = new ControlObject(ConfigKey(group, "samplerate"), true, true);
71 m_pMasterSampleRate->set(44100.);
72
73 // Latency control
74 m_pMasterLatency = new ControlObject(ConfigKey(group, "latency"), true, true);
75 m_pMasterAudioBufferSize = new ControlObject(ConfigKey(group, "audio_buffer_size"));
76 m_pAudioLatencyOverloadCount = new ControlObject(ConfigKey(group, "audio_latency_overload_count"), true, true);
77 m_pAudioLatencyUsage = new ControlPotmeter(ConfigKey(group, "audio_latency_usage"), 0.0, 0.25);
78 m_pAudioLatencyOverload = new ControlPotmeter(ConfigKey(group, "audio_latency_overload"), 0.0, 1.0);
79
80 // Master sync controller
81 m_pMasterSync = new EngineSync(pConfig);
82
83 // The last-used bpm value is saved in the destructor of EngineSync.
84 double default_bpm = pConfig->getValue(
85 ConfigKey("[InternalClock]", "bpm"), 124.0);
86 ControlObject::getControl(ConfigKey("[InternalClock]","bpm"))->set(default_bpm);
87
88 // Crossfader
89 m_pCrossfader = new ControlPotmeter(ConfigKey(group, "crossfader"), -1., 1.);
90
91 // Balance
92 m_pBalance = new ControlPotmeter(ConfigKey(group, "balance"), -1., 1.);
93
94 // Master gain
95 m_pMasterGain = new ControlAudioTaperPot(ConfigKey(group, "gain"), -14, 14, 0.5);
96
97 // Booth gain
98 m_pBoothGain = new ControlAudioTaperPot(ConfigKey(group, "booth_gain"), -14, 14, 0.5);
99
100 // Legacy: the master "gain" control used to be named "volume" in Mixxx
101 // 1.11.0 and earlier. See Bug #1306253.
102 ControlDoublePrivate::insertAlias(ConfigKey(group, "volume"),
103 ConfigKey(group, "gain"));
104
105 // VU meter:
106 m_pVumeter = new EngineVuMeter(group);
107
108 m_pMasterDelay = new EngineDelay(group, ConfigKey(group, "delay"));
109 m_pHeadDelay = new EngineDelay(group, ConfigKey(group, "headDelay"));
110 m_pBoothDelay = new EngineDelay(group, ConfigKey(group, "boothDelay"));
111 m_pLatencyCompensationDelay = new EngineDelay(group,
112 ConfigKey(group, "microphoneLatencyCompensation"));
113 m_pNumMicsConfigured = new ControlObject(ConfigKey(group, "num_mics_configured"));
114
115 // Headphone volume
116 m_pHeadGain = new ControlAudioTaperPot(ConfigKey(group, "headGain"), -14, 14, 0.5);
117
118 // Legacy: the headphone "headGain" control used to be named "headVolume" in
119 // Mixxx 1.11.0 and earlier. See Bug #1306253.
120 ControlDoublePrivate::insertAlias(ConfigKey(group, "headVolume"),
121 ConfigKey(group, "headGain"));
122
123 // Headphone mix (left/right)
124 m_pHeadMix = new ControlPotmeter(ConfigKey(group, "headMix"),-1.,1.);
125 m_pHeadMix->setDefaultValue(-1.);
126 m_pHeadMix->set(-1.);
127
128 // Master / Headphone split-out mode (for devices with only one output).
129 m_pHeadSplitEnabled = new ControlPushButton(ConfigKey(group, "headSplit"));
130 m_pHeadSplitEnabled->setButtonMode(ControlPushButton::TOGGLE);
131 m_pHeadSplitEnabled->set(0.0);
132
133 m_pTalkoverDucking = new EngineTalkoverDucking(pConfig, group);
134
135 // Allocate buffers
136 m_pHead = SampleUtil::alloc(MAX_BUFFER_LEN);
137 m_pMaster = SampleUtil::alloc(MAX_BUFFER_LEN);
138 m_pBooth = SampleUtil::alloc(MAX_BUFFER_LEN);
139 m_pTalkover = SampleUtil::alloc(MAX_BUFFER_LEN);
140 m_pTalkoverHeadphones = SampleUtil::alloc(MAX_BUFFER_LEN);
141 m_pSidechainMix = SampleUtil::alloc(MAX_BUFFER_LEN);
142 SampleUtil::clear(m_pHead, MAX_BUFFER_LEN);
143 SampleUtil::clear(m_pMaster, MAX_BUFFER_LEN);
144 SampleUtil::clear(m_pBooth, MAX_BUFFER_LEN);
145 SampleUtil::clear(m_pTalkover, MAX_BUFFER_LEN);
146 SampleUtil::clear(m_pTalkoverHeadphones, MAX_BUFFER_LEN);
147 SampleUtil::clear(m_pSidechainMix, MAX_BUFFER_LEN);
148
149 // Setup the output buses
150 for (int o = EngineChannel::LEFT; o <= EngineChannel::RIGHT; ++o) {
151 m_pOutputBusBuffers[o] = SampleUtil::alloc(MAX_BUFFER_LEN);
152 SampleUtil::clear(m_pOutputBusBuffers[o], MAX_BUFFER_LEN);
153 }
154
155 // Starts a thread for recording and broadcast
156 m_pEngineSideChain =
157 bEnableSidechain ?
158 new EngineSideChain(pConfig, m_pSidechainMix) : nullptr;
159
160 // X-Fader Setup
161 m_pXFaderMode = new ControlPushButton(
162 ConfigKey(EngineXfader::kXfaderConfigKey, "xFaderMode"));
163 m_pXFaderMode->setButtonMode(ControlPushButton::TOGGLE);
164
165 m_pXFaderCurve = new ControlPotmeter(
166 ConfigKey(EngineXfader::kXfaderConfigKey, "xFaderCurve"),
167 EngineXfader::kTransformMin, EngineXfader::kTransformMax);
168 m_pXFaderCalibration = new ControlPotmeter(
169 ConfigKey(EngineXfader::kXfaderConfigKey, "xFaderCalibration"),
170 0.3, 1., true);
171 m_pXFaderReverse = new ControlPushButton(
172 ConfigKey(EngineXfader::kXfaderConfigKey, "xFaderReverse"));
173 m_pXFaderReverse->setButtonMode(ControlPushButton::TOGGLE);
174
175 m_pKeylockEngine = new ControlObject(ConfigKey(group, "keylock_engine"),
176 true, false, true);
177 m_pKeylockEngine->set(pConfig->getValueString(
178 ConfigKey(group, "keylock_engine")).toDouble());
179
180 // TODO: Make this read only and make EngineMaster decide whether
181 // processing the master mix is necessary.
182 m_pMasterEnabled = new ControlObject(ConfigKey(group, "enabled"),
183 true, false, true); // persist = true
184 m_pBoothEnabled = new ControlObject(ConfigKey(group, "booth_enabled"));
185 m_pBoothEnabled->setReadOnly();
186 m_pMasterMonoMixdown = new ControlObject(ConfigKey(group, "mono_mixdown"),
187 true, false, true); // persist = true
188 m_pMicMonitorMode = new ControlObject(ConfigKey(group, "talkover_mix"),
189 true, false, true); // persist = true
190 m_pHeadphoneEnabled = new ControlObject(ConfigKey(group, "headEnabled"));
191 m_pHeadphoneEnabled->setReadOnly();
192
193 // Note: the EQ Rack is set in EffectsManager::setupDefaults();
194 }
195
~EngineMaster()196 EngineMaster::~EngineMaster() {
197 //qDebug() << "in ~EngineMaster()";
198 delete m_pKeylockEngine;
199 delete m_pCrossfader;
200 delete m_pBalance;
201 delete m_pHeadMix;
202 delete m_pHeadSplitEnabled;
203 delete m_pMasterGain;
204 delete m_pBoothGain;
205 delete m_pHeadGain;
206 delete m_pTalkoverDucking;
207 delete m_pVumeter;
208 delete m_pEngineSideChain;
209 delete m_pMasterDelay;
210 delete m_pHeadDelay;
211 delete m_pBoothDelay;
212 delete m_pLatencyCompensationDelay;
213 delete m_pNumMicsConfigured;
214
215 delete m_pXFaderReverse;
216 delete m_pXFaderCalibration;
217 delete m_pXFaderCurve;
218 delete m_pXFaderMode;
219
220 delete m_pMasterSync;
221 delete m_pMasterSampleRate;
222 delete m_pMasterLatency;
223 delete m_pMasterAudioBufferSize;
224 delete m_pAudioLatencyOverloadCount;
225 delete m_pAudioLatencyUsage;
226 delete m_pAudioLatencyOverload;
227
228 delete m_pMasterEnabled;
229 delete m_pBoothEnabled;
230 delete m_pMasterMonoMixdown;
231 delete m_pMicMonitorMode;
232 delete m_pHeadphoneEnabled;
233
234 SampleUtil::free(m_pHead);
235 SampleUtil::free(m_pMaster);
236 SampleUtil::free(m_pBooth);
237 SampleUtil::free(m_pTalkover);
238 SampleUtil::free(m_pTalkoverHeadphones);
239 SampleUtil::free(m_pSidechainMix);
240 for (int o = EngineChannel::LEFT; o <= EngineChannel::RIGHT; o++) {
241 SampleUtil::free(m_pOutputBusBuffers[o]);
242 }
243
244 delete m_pWorkerScheduler;
245
246 for (int i = 0; i < m_channels.size(); ++i) {
247 ChannelInfo* pChannelInfo = m_channels[i];
248 SampleUtil::free(pChannelInfo->m_pBuffer);
249 delete pChannelInfo->m_pChannel;
250 delete pChannelInfo->m_pVolumeControl;
251 delete pChannelInfo->m_pMuteControl;
252 delete pChannelInfo;
253 }
254 }
255
getMasterBuffer() const256 const CSAMPLE* EngineMaster::getMasterBuffer() const {
257 return m_pMaster;
258 }
259
getBoothBuffer() const260 const CSAMPLE* EngineMaster::getBoothBuffer() const {
261 return m_pBooth;
262 }
263
getHeadphoneBuffer() const264 const CSAMPLE* EngineMaster::getHeadphoneBuffer() const {
265 return m_pHead;
266 }
267
getSidechainBuffer() const268 const CSAMPLE* EngineMaster::getSidechainBuffer() const {
269 return m_pSidechainMix;
270 }
271
processChannels(int iBufferSize)272 void EngineMaster::processChannels(int iBufferSize) {
273 // Update internal master sync rate.
274 m_pMasterSync->onCallbackStart(m_iSampleRate, m_iBufferSize);
275
276 m_activeBusChannels[EngineChannel::LEFT].clear();
277 m_activeBusChannels[EngineChannel::CENTER].clear();
278 m_activeBusChannels[EngineChannel::RIGHT].clear();
279 m_activeHeadphoneChannels.clear();
280 m_activeTalkoverChannels.clear();
281 m_activeChannels.clear();
282
283 //ScopedTimer timer("EngineMaster::processChannels");
284 EngineChannel* pMasterChannel = m_pMasterSync->getMaster();
285 // Reserve the first place for the master channel which
286 // should be processed first
287 m_activeChannels.append(NULL);
288 int activeChannelsStartIndex = 1; // Nothing at 0 yet
289 for (int i = 0; i < m_channels.size(); ++i) {
290 ChannelInfo* pChannelInfo = m_channels[i];
291 EngineChannel* pChannel = pChannelInfo->m_pChannel;
292
293 // Skip inactive channels.
294 if (!pChannel || !pChannel->isActive()) {
295 continue;
296 }
297
298 if (pChannel->isTalkoverEnabled() &&
299 !pChannelInfo->m_pMuteControl->toBool()) {
300 // talkover is an exclusive channel
301 // once talkover is enabled it is not used in
302 // xFader-Mix
303 m_activeTalkoverChannels.append(pChannelInfo);
304
305 // Check if we need to fade out the master channel
306 GainCache& gainCache = m_channelMasterGainCache[i];
307 if (gainCache.m_gain != 0) {
308 gainCache.m_fadeout = true;
309 m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo);
310 }
311 } else {
312 // Check if we need to fade out the channel
313 GainCache& gainCache = m_channelTalkoverGainCache[i];
314 if (gainCache.m_gain != 0) {
315 gainCache.m_fadeout = true;
316 m_activeTalkoverChannels.append(pChannelInfo);
317 }
318 if (pChannel->isMasterEnabled() &&
319 !pChannelInfo->m_pMuteControl->toBool()) {
320 // the xFader-Mix
321 m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo);
322 } else {
323 // Check if we need to fade out the channel
324 GainCache& gainCache = m_channelMasterGainCache[i];
325 if (gainCache.m_gain != 0) {
326 gainCache.m_fadeout = true;
327 m_activeBusChannels[pChannel->getOrientation()].append(pChannelInfo);
328 }
329 }
330 }
331
332 // If the channel is enabled for previewing in headphones, copy it
333 // over to the headphone buffer
334 if (pChannel->isPflEnabled()) {
335 m_activeHeadphoneChannels.append(pChannelInfo);
336 } else {
337 // Check if we need to fade out the channel
338 GainCache& gainCache = m_channelHeadphoneGainCache[i];
339 if (gainCache.m_gain != 0) {
340 m_channelHeadphoneGainCache[i].m_fadeout = true;
341 m_activeHeadphoneChannels.append(pChannelInfo);
342 }
343 }
344
345 // If necessary, add the channel to the list of buffers to process.
346 if (pChannel == pMasterChannel) {
347 // If this is the sync master, it should be processed first.
348 m_activeChannels.replace(0, pChannelInfo);
349 activeChannelsStartIndex = 0;
350 } else {
351 m_activeChannels.append(pChannelInfo);
352 }
353 }
354
355 // Now that the list is built and ordered, do the processing.
356 for (int i = activeChannelsStartIndex;
357 i < m_activeChannels.size(); ++i) {
358 ChannelInfo* pChannelInfo = m_activeChannels[i];
359 EngineChannel* pChannel = pChannelInfo->m_pChannel;
360 pChannel->process(pChannelInfo->m_pBuffer, iBufferSize);
361
362 // Collect metadata for effects
363 if (m_pEngineEffectsManager) {
364 GroupFeatureState features;
365 pChannel->collectFeatures(&features);
366 pChannelInfo->m_features = features;
367 }
368 }
369
370 // Do internal master sync post-processing before the other
371 // channels.
372 m_pMasterSync->onCallbackEnd(m_iSampleRate, m_iBufferSize);
373
374 // After all the engines have been processed, trigger post-processing
375 // which ensures that all channels are updating certain values at the
376 // same point in time. This prevents sync from failing depending on
377 // if the sync target was processed before or after the sync origin.
378 for (int i = activeChannelsStartIndex;
379 i < m_activeChannels.size(); ++i) {
380 m_activeChannels[i]->m_pChannel->postProcess(iBufferSize);
381 }
382 }
383
process(const int iBufferSize)384 void EngineMaster::process(const int iBufferSize) {
385 static bool haveSetName = false;
386 if (!haveSetName) {
387 QThread::currentThread()->setObjectName("Engine");
388 haveSetName = true;
389 }
390 //Trace t("EngineMaster::process");
391
392 bool masterEnabled = m_pMasterEnabled->toBool();
393 bool boothEnabled = m_pBoothEnabled->toBool();
394 bool headphoneEnabled = m_pHeadphoneEnabled->toBool();
395
396 m_iSampleRate = static_cast<int>(m_pMasterSampleRate->get());
397 m_iBufferSize = iBufferSize;
398 // TODO: remove assumption of stereo buffer
399 const unsigned int kChannels = 2;
400 const unsigned int iFrames = iBufferSize / kChannels;
401
402 if (m_pEngineEffectsManager) {
403 m_pEngineEffectsManager->onCallbackStart();
404 }
405
406 // Prepare all channels for output
407 processChannels(m_iBufferSize);
408
409 // Compute headphone mix
410 // Head phone left/right mix
411 CSAMPLE pflMixGainInHeadphones = 1;
412 CSAMPLE masterMixGainInHeadphones = 0;
413 if (masterEnabled) {
414 const auto cf_val = static_cast<CSAMPLE_GAIN>(m_pHeadMix->get());
415 pflMixGainInHeadphones = 0.5f * (-cf_val + 1.0f);
416 masterMixGainInHeadphones = 0.5f * (cf_val + 1.0f);
417 // qDebug() << "head val " << cf_val << ", head " << chead_gain
418 // << ", master " << cmaster_gain;
419 }
420
421 // Mix all the PFL enabled channels together.
422 m_headphoneGain.setGain(pflMixGainInHeadphones);
423
424 if (headphoneEnabled) {
425 // Process effects and mix PFL channels together for the headphones.
426 // Effects will be reprocessed post-fader for the crossfader busses
427 // and master mix, so the channel input buffers cannot be modified here.
428 ChannelMixer::applyEffectsAndMixChannels(
429 m_headphoneGain, &m_activeHeadphoneChannels,
430 &m_channelHeadphoneGainCache,
431 m_pHead, m_headphoneHandle.handle(),
432 m_iBufferSize, m_iSampleRate,
433 m_pEngineEffectsManager);
434
435 // Process headphone channel effects
436 if (m_pEngineEffectsManager) {
437 GroupFeatureState headphoneFeatures;
438 // If there is only one channel in the headphone mix, use its features
439 // for effects processing. This allows for previewing how an effect will
440 // sound on a playing deck before turning up the dry/wet knob to make it
441 // audible on the master mix. Without this, the effect would sound different
442 // in headphones than how it would sound if it was enabled on the deck,
443 // for example with tempo synced effects.
444 if (m_activeHeadphoneChannels.size() == 1) {
445 headphoneFeatures = m_activeHeadphoneChannels.at(0)->m_features;
446 }
447 m_pEngineEffectsManager->processPostFaderInPlace(
448 m_headphoneHandle.handle(),
449 m_headphoneHandle.handle(),
450 m_pHead,
451 m_iBufferSize, m_iSampleRate,
452 headphoneFeatures);
453 }
454 }
455
456 // Mix all the talkover enabled channels together.
457 // Effects processing is done in place to avoid unnecessary buffer copying.
458 ChannelMixer::applyEffectsInPlaceAndMixChannels(
459 m_talkoverGain, &m_activeTalkoverChannels,
460 &m_channelTalkoverGainCache,
461 m_pTalkover, m_masterHandle.handle(),
462 m_iBufferSize, m_iSampleRate, m_pEngineEffectsManager);
463
464 // Process effects on all microphones mixed together
465 // We have no metadata for mixed effect buses, so use an empty GroupFeatureState.
466 GroupFeatureState busFeatures;
467 if (m_pEngineEffectsManager) {
468 m_pEngineEffectsManager->processPostFaderInPlace(
469 m_busTalkoverHandle.handle(),
470 m_masterHandle.handle(),
471 m_pTalkover,
472 m_iBufferSize,
473 m_iSampleRate,
474 busFeatures);
475 }
476
477 switch (m_pTalkoverDucking->getMode()) {
478 case EngineTalkoverDucking::OFF:
479 m_pTalkoverDucking->setAboveThreshold(false);
480 break;
481 case EngineTalkoverDucking::AUTO:
482 m_pTalkoverDucking->processKey(m_pTalkover, m_iBufferSize);
483 break;
484 case EngineTalkoverDucking::MANUAL:
485 m_pTalkoverDucking->setAboveThreshold(m_activeTalkoverChannels.size());
486 break;
487 default:
488 DEBUG_ASSERT("!Unknown Ducking mode");
489 m_pTalkoverDucking->setAboveThreshold(false);
490 break;
491 }
492
493 // Calculate the crossfader gains for left and right side of the crossfader
494 CSAMPLE_GAIN crossfaderLeftGain, crossfaderRightGain;
495 EngineXfader::getXfadeGains(m_pCrossfader->get(), m_pXFaderCurve->get(),
496 m_pXFaderCalibration->get(),
497 m_pXFaderMode->get(),
498 m_pXFaderReverse->toBool(),
499 &crossfaderLeftGain, &crossfaderRightGain);
500
501 // Make the mix for each crossfader orientation output bus.
502 // m_masterGain takes care of applying the attenuation from
503 // channel volume faders, crossfader, and talkover ducking.
504 // Talkover is mixed in later according to the configured MicMonitorMode
505 m_masterGain.setGains(crossfaderLeftGain,
506 1.0f,
507 crossfaderRightGain,
508 m_pTalkoverDucking->getGain(m_iBufferSize / 2));
509
510 for (int o = EngineChannel::LEFT; o <= EngineChannel::RIGHT; o++) {
511 ChannelMixer::applyEffectsInPlaceAndMixChannels(
512 m_masterGain,
513 &m_activeBusChannels[o],
514 &m_channelMasterGainCache, // no [o] because the old gain follows an orientation switch
515 m_pOutputBusBuffers[o], m_masterHandle.handle(),
516 m_iBufferSize, m_iSampleRate, m_pEngineEffectsManager);
517 }
518
519 // Process crossfader orientation bus channel effects
520 if (m_pEngineEffectsManager) {
521 m_pEngineEffectsManager->processPostFaderInPlace(
522 m_busCrossfaderLeftHandle.handle(),
523 m_masterHandle.handle(),
524 m_pOutputBusBuffers[EngineChannel::LEFT],
525 m_iBufferSize, m_iSampleRate, busFeatures);
526 m_pEngineEffectsManager->processPostFaderInPlace(
527 m_busCrossfaderCenterHandle.handle(),
528 m_masterHandle.handle(),
529 m_pOutputBusBuffers[EngineChannel::CENTER],
530 m_iBufferSize, m_iSampleRate, busFeatures);
531 m_pEngineEffectsManager->processPostFaderInPlace(
532 m_busCrossfaderRightHandle.handle(),
533 m_masterHandle.handle(),
534 m_pOutputBusBuffers[EngineChannel::RIGHT],
535 m_iBufferSize, m_iSampleRate, busFeatures);
536 }
537
538 if (masterEnabled) {
539 // Mix the crossfader orientation buffers together into the master mix
540 SampleUtil::copy3WithGain(m_pMaster,
541 m_pOutputBusBuffers[EngineChannel::LEFT], 1.0,
542 m_pOutputBusBuffers[EngineChannel::CENTER], 1.0,
543 m_pOutputBusBuffers[EngineChannel::RIGHT], 1.0,
544 m_iBufferSize);
545
546 MicMonitorMode configuredMicMonitorMode = static_cast<MicMonitorMode>(
547 static_cast<int>(m_pMicMonitorMode->get()));
548
549 // Process master, booth, and record/broadcast buffers according to the
550 // MicMonitorMode configured in DlgPrefSound
551 // TODO(Be): make SampleUtil ramping functions update the old gain variable
552 if (configuredMicMonitorMode == MicMonitorMode::MASTER) {
553 // Process master channel effects
554 // TODO(Be): Move this after mixing in talkover. To apply master effects
555 // to both the master and booth in that case will require refactoring
556 // the effects system to be able to process the same effects on multiple
557 // buffers within the same callback.
558 applyMasterEffects();
559
560 if (headphoneEnabled) {
561 processHeadphones(masterMixGainInHeadphones);
562 }
563
564 // Copy master mix to booth output with booth gain before mixing
565 // talkover with master mix
566 if (boothEnabled) {
567 CSAMPLE_GAIN boothGain = static_cast<CSAMPLE_GAIN>(m_pBoothGain->get());
568 SampleUtil::copyWithRampingGain(m_pBooth, m_pMaster,
569 m_boothGainOld, boothGain,
570 m_iBufferSize);
571 m_boothGainOld = boothGain;
572 }
573
574 // Mix talkover into master mix
575 if (m_pNumMicsConfigured->get() > 0) {
576 SampleUtil::add(m_pMaster, m_pTalkover, m_iBufferSize);
577 }
578
579 // Apply master gain
580 CSAMPLE_GAIN master_gain = static_cast<CSAMPLE_GAIN>(m_pMasterGain->get());
581 SampleUtil::applyRampingGain(m_pMaster, m_masterGainOld,
582 master_gain, m_iBufferSize);
583 m_masterGainOld = master_gain;
584
585 // Record/broadcast signal is the same as the master output
586 if (sidechainMixRequired()) {
587 SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize);
588 }
589 } else if (configuredMicMonitorMode == MicMonitorMode::MASTER_AND_BOOTH) {
590 // Process master channel effects
591 // TODO(Be): Move this after mixing in talkover. For the MASTER only
592 // MicMonitorMode above, that will require refactoring the effects system
593 // to be able to process the same effects on different buffers
594 // within the same callback. For consistency between the MicMonitorModes,
595 // process master effects here before mixing in talkover.
596 applyMasterEffects();
597
598 if (headphoneEnabled) {
599 processHeadphones(masterMixGainInHeadphones);
600 }
601
602 // Mix talkover with master
603 if (m_pNumMicsConfigured->get() > 0) {
604 SampleUtil::add(m_pMaster, m_pTalkover, m_iBufferSize);
605 }
606
607 // Copy master mix (with talkover mixed in) to booth output with booth gain
608 if (boothEnabled) {
609 CSAMPLE_GAIN boothGain = static_cast<CSAMPLE_GAIN>(m_pBoothGain->get());
610 SampleUtil::copyWithRampingGain(m_pBooth, m_pMaster,
611 m_boothGainOld, boothGain,
612 m_iBufferSize);
613 m_boothGainOld = boothGain;
614 }
615
616 // Apply master gain
617 CSAMPLE_GAIN master_gain = static_cast<CSAMPLE_GAIN>(m_pMasterGain->get());
618 SampleUtil::applyRampingGain(m_pMaster, m_masterGainOld,
619 master_gain, m_iBufferSize);
620 m_masterGainOld = master_gain;
621
622 // Record/broadcast signal is the same as the master output
623 if (sidechainMixRequired()) {
624 SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize);
625 }
626 } else if (configuredMicMonitorMode == MicMonitorMode::DIRECT_MONITOR) {
627 // Skip mixing talkover with the master and booth outputs
628 // if using direct monitoring because it is being mixed in hardware
629 // without the latency of sending the signal into Mixxx for processing.
630 // However, include the talkover mix in the record/broadcast signal.
631
632 // Copy master mix to booth output with booth gain
633 if (boothEnabled) {
634 CSAMPLE_GAIN boothGain = static_cast<CSAMPLE_GAIN>(m_pBoothGain->get());
635 SampleUtil::copyWithRampingGain(m_pBooth, m_pMaster,
636 m_boothGainOld, boothGain,
637 m_iBufferSize);
638 m_boothGainOld = boothGain;
639 }
640
641 // Process master channel effects
642 // NOTE(Be): This should occur before mixing in talkover for the
643 // record/broadcast signal so the record/broadcast signal is the same
644 // as what is heard on the master & booth outputs.
645 applyMasterEffects();
646
647 if (headphoneEnabled) {
648 processHeadphones(masterMixGainInHeadphones);
649 }
650
651 // Apply master gain
652 CSAMPLE_GAIN master_gain = static_cast<CSAMPLE_GAIN>(m_pMasterGain->get());
653 SampleUtil::applyRampingGain(m_pMaster, m_masterGainOld,
654 master_gain, m_iBufferSize);
655 m_masterGainOld = master_gain;
656 if (sidechainMixRequired()) {
657 SampleUtil::copy(m_pSidechainMix, m_pMaster, m_iBufferSize);
658
659 if (m_pNumMicsConfigured->get() > 0) {
660 // The talkover signal Mixxx receives is delayed by the round trip latency.
661 // There is an output latency between the time Mixxx processes the audio
662 // and the user hears it. So if the microphone user plays on beat with
663 // what they hear, they will be playing out of sync with the engine's
664 // processing by the output latency. Additionally, Mixxx gets input signals
665 // delayed by the input latency. By the time Mixxx receives the input signal,
666 // a full round trip through the signal chain has elapsed since Mixxx
667 // processed the output signal.
668 // Although Mixxx receives the input signal delayed, the user hears it mixed
669 // in hardware with the master & booth outputs without that
670 // latency, so to record/broadcast the same signal that is heard
671 // on the master & booth outputs, the master mix must be delayed before
672 // mixing the talkover signal for the record/broadcast mix.
673 // If not using microphone inputs or recording/broadcasting from
674 // a sound card input, skip unnecessary processing here.
675
676 // Copy the master mix to a separate buffer before delaying it
677 // to avoid delaying the master output.
678 m_pLatencyCompensationDelay->process(m_pSidechainMix, m_iBufferSize);
679 SampleUtil::add(m_pSidechainMix, m_pTalkover, m_iBufferSize);
680 }
681 }
682 }
683
684 // Submit buffer to the side chain to do CPU intensive non-realtime
685 // tasks like recording. The SoundDeviceNetwork, responsible for
686 // passing samples to the network reads directly from m_pSidechainMix,
687 // registering it with SoundDevice::addOutput().
688 // Note: In case the broadcast/recording input is configured,
689 // EngineSideChain::receiveBuffer has copied the input buffer to m_pSidechainMix
690 // via before (called by SoundManager::pushInputBuffers())
691 if (m_pEngineSideChain) {
692 m_pEngineSideChain->writeSamples(m_pSidechainMix, iFrames);
693 }
694
695 // Process effects that apply to master hardware output only but not
696 // record/broadcast signal
697 if (m_pEngineEffectsManager) {
698 GroupFeatureState masterFeatures;
699 masterFeatures.has_gain = true;
700 masterFeatures.gain = m_pMasterGain->get();
701 m_pEngineEffectsManager->processPostFaderInPlace(
702 m_masterOutputHandle.handle(),
703 m_masterHandle.handle(),
704 m_pMaster,
705 m_iBufferSize, m_iSampleRate,
706 masterFeatures);
707 }
708
709 // Balance values
710 CSAMPLE balright = 1.;
711 CSAMPLE balleft = 1.;
712 const auto bal = static_cast<CSAMPLE_GAIN>(m_pBalance->get());
713 if (bal > 0.) {
714 balleft -= bal;
715 } else if (bal < 0.) {
716 balright += bal;
717 }
718
719 // Perform balancing on main out
720 SampleUtil::applyRampingAlternatingGain(m_pMaster, balleft, balright,
721 m_balleftOld, m_balrightOld, iBufferSize);
722
723 m_balleftOld = balleft;
724 m_balrightOld = balright;
725
726 // Update VU meter (it does not return anything). Needs to be here so that
727 // master balance and talkover is reflected in the VU meter.
728 if (m_pVumeter != nullptr) {
729 m_pVumeter->process(m_pMaster, m_iBufferSize);
730 }
731 }
732
733 if (m_pMasterMonoMixdown->toBool()) {
734 SampleUtil::mixStereoToMono(m_pMaster, m_iBufferSize);
735 }
736
737 if (masterEnabled) {
738 m_pMasterDelay->process(m_pMaster, m_iBufferSize);
739 } else {
740 SampleUtil::clear(m_pMaster, m_iBufferSize);
741 }
742 if (headphoneEnabled) {
743 m_pHeadDelay->process(m_pHead, m_iBufferSize);
744 }
745 if (boothEnabled) {
746 m_pBoothDelay->process(m_pBooth, m_iBufferSize);
747 }
748
749 // We're close to the end of the callback. Wake up the engine worker
750 // scheduler so that it runs the workers.
751 m_pWorkerScheduler->runWorkers();
752 }
753
applyMasterEffects()754 void EngineMaster::applyMasterEffects() {
755 // Apply master effects
756 if (m_pEngineEffectsManager) {
757 GroupFeatureState masterFeatures;
758 masterFeatures.has_gain = true;
759 masterFeatures.gain = m_pMasterGain->get();
760 m_pEngineEffectsManager->processPostFaderInPlace(m_masterHandle.handle(),
761 m_masterHandle.handle(),
762 m_pMaster,
763 m_iBufferSize, m_iSampleRate,
764 masterFeatures);
765 }
766 }
767
processHeadphones(const CSAMPLE_GAIN masterMixGainInHeadphones)768 void EngineMaster::processHeadphones(const CSAMPLE_GAIN masterMixGainInHeadphones) {
769 // Add master mix to headphones
770 SampleUtil::addWithRampingGain(m_pHead, m_pMaster,
771 m_headphoneMasterGainOld,
772 masterMixGainInHeadphones, m_iBufferSize);
773 m_headphoneMasterGainOld = masterMixGainInHeadphones;
774
775 // If Head Split is enabled, replace the left channel of the pfl buffer
776 // with a mono mix of the headphone buffer, and the right channel of the pfl
777 // buffer with a mono mix of the master output buffer.
778 if (m_pHeadSplitEnabled->toBool()) {
779 // note: NOT VECTORIZED because of in place copy
780 for (unsigned int i = 0; i + 1 < m_iBufferSize; i += 2) {
781 m_pHead[i] = (m_pHead[i] + m_pHead[i + 1]) / 2;
782 m_pHead[i + 1] = (m_pMaster[i] + m_pMaster[i + 1]) / 2;
783 }
784 }
785
786 // Apply headphone gain
787 CSAMPLE_GAIN headphoneGain = static_cast<CSAMPLE_GAIN>(m_pHeadGain->get());
788 SampleUtil::applyRampingGain(m_pHead, m_headphoneGainOld,
789 headphoneGain, m_iBufferSize);
790 m_headphoneGainOld = headphoneGain;
791 }
792
addChannel(EngineChannel * pChannel)793 void EngineMaster::addChannel(EngineChannel* pChannel) {
794 ChannelInfo* pChannelInfo = new ChannelInfo(m_channels.size());
795 pChannel->setChannelIndex(pChannelInfo->m_index);
796 pChannelInfo->m_pChannel = pChannel;
797 const QString& group = pChannel->getGroup();
798 pChannelInfo->m_handle = m_pChannelHandleFactory->getOrCreateHandle(group);
799 pChannelInfo->m_pVolumeControl = new ControlAudioTaperPot(
800 ConfigKey(group, "volume"), -20, 0, 1);
801 pChannelInfo->m_pVolumeControl->setDefaultValue(1.0);
802 pChannelInfo->m_pVolumeControl->set(1.0);
803 pChannelInfo->m_pMuteControl = new ControlPushButton(
804 ConfigKey(group, "mute"));
805 pChannelInfo->m_pMuteControl->setButtonMode(ControlPushButton::POWERWINDOW);
806 pChannelInfo->m_pBuffer = SampleUtil::alloc(MAX_BUFFER_LEN);
807 SampleUtil::clear(pChannelInfo->m_pBuffer, MAX_BUFFER_LEN);
808 m_channels.append(pChannelInfo);
809 const GainCache gainCacheDefault = {0, false};
810 m_channelHeadphoneGainCache.append(gainCacheDefault);
811 m_channelTalkoverGainCache.append(gainCacheDefault);
812 m_channelMasterGainCache.append(gainCacheDefault);
813
814 // Pre-allocate scratch buffers to avoid memory allocation in the
815 // callback. QVarLengthArray does nothing if reserve is called with a size
816 // smaller than its pre-allocation.
817 m_activeChannels.reserve(m_channels.size());
818 m_activeBusChannels[EngineChannel::LEFT].reserve(m_channels.size());
819 m_activeBusChannels[EngineChannel::CENTER].reserve(m_channels.size());
820 m_activeBusChannels[EngineChannel::RIGHT].reserve(m_channels.size());
821 m_activeHeadphoneChannels.reserve(m_channels.size());
822 m_activeTalkoverChannels.reserve(m_channels.size());
823
824 EngineBuffer* pBuffer = pChannelInfo->m_pChannel->getEngineBuffer();
825 if (pBuffer != nullptr) {
826 pBuffer->bindWorkers(m_pWorkerScheduler);
827 }
828 }
829
getChannel(const QString & group)830 EngineChannel* EngineMaster::getChannel(const QString& group) {
831 for (int i = 0; i < m_channels.size(); ++i) {
832 ChannelInfo* pChannelInfo = m_channels[i];
833 if (pChannelInfo->m_pChannel->getGroup() == group) {
834 return pChannelInfo->m_pChannel;
835 }
836 }
837 return nullptr;
838 }
839
getMasterGain(int channelIndex) const840 CSAMPLE_GAIN EngineMaster::getMasterGain(int channelIndex) const {
841 if (channelIndex >= 0 && channelIndex < m_channelMasterGainCache.size()) {
842 return m_channelMasterGainCache[channelIndex].m_gain;
843 }
844 return CSAMPLE_GAIN_ZERO;
845 }
846
getDeckBuffer(unsigned int i) const847 const CSAMPLE* EngineMaster::getDeckBuffer(unsigned int i) const {
848 return getChannelBuffer(PlayerManager::groupForDeck(i));
849 }
850
getOutputBusBuffer(unsigned int i) const851 const CSAMPLE* EngineMaster::getOutputBusBuffer(unsigned int i) const {
852 if (i <= EngineChannel::RIGHT) {
853 return m_pOutputBusBuffers[i];
854 }
855 return nullptr;
856 }
857
getChannelBuffer(const QString & group) const858 const CSAMPLE* EngineMaster::getChannelBuffer(const QString& group) const {
859 for (int i = 0; i < m_channels.size(); ++i) {
860 const ChannelInfo* pChannelInfo = m_channels[i];
861 if (pChannelInfo->m_pChannel->getGroup() == group) {
862 return pChannelInfo->m_pBuffer;
863 }
864 }
865 return nullptr;
866 }
867
buffer(const AudioOutput & output) const868 const CSAMPLE* EngineMaster::buffer(const AudioOutput& output) const {
869 switch (output.getType()) {
870 case AudioOutput::MASTER:
871 return getMasterBuffer();
872 break;
873 case AudioOutput::BOOTH:
874 return getBoothBuffer();
875 break;
876 case AudioOutput::HEADPHONES:
877 return getHeadphoneBuffer();
878 break;
879 case AudioOutput::BUS:
880 return getOutputBusBuffer(output.getIndex());
881 break;
882 case AudioOutput::DECK:
883 return getDeckBuffer(output.getIndex());
884 break;
885 case AudioOutput::RECORD_BROADCAST:
886 return getSidechainBuffer();
887 break;
888 default:
889 return nullptr;
890 }
891 }
892
onOutputConnected(const AudioOutput & output)893 void EngineMaster::onOutputConnected(const AudioOutput& output) {
894 switch (output.getType()) {
895 case AudioOutput::MASTER:
896 // overwrite config option if a master output is configured
897 m_pMasterEnabled->forceSet(1.0);
898 break;
899 case AudioOutput::HEADPHONES:
900 m_pMasterEnabled->forceSet(1.0);
901 m_pHeadphoneEnabled->forceSet(1.0);
902 break;
903 case AudioOutput::BOOTH:
904 m_pMasterEnabled->forceSet(1.0);
905 m_pBoothEnabled->forceSet(1.0);
906 break;
907 case AudioOutput::BUS:
908 m_bBusOutputConnected[output.getIndex()] = true;
909 break;
910 case AudioOutput::DECK:
911 // We don't track enabled decks.
912 break;
913 case AudioOutput::RECORD_BROADCAST:
914 // We don't track enabled sidechain.
915 break;
916 default:
917 break;
918 }
919 }
920
onOutputDisconnected(const AudioOutput & output)921 void EngineMaster::onOutputDisconnected(const AudioOutput& output) {
922 switch (output.getType()) {
923 case AudioOutput::MASTER:
924 // not used, because we need the master buffer for headphone mix
925 // and recording/broadcasting as well
926 break;
927 case AudioOutput::BOOTH:
928 m_pBoothEnabled->forceSet(0.0);
929 break;
930 case AudioOutput::HEADPHONES:
931 m_pHeadphoneEnabled->forceSet(0.0);
932 break;
933 case AudioOutput::BUS:
934 m_bBusOutputConnected[output.getIndex()] = false;
935 break;
936 case AudioOutput::DECK:
937 // We don't track enabled decks.
938 break;
939 case AudioOutput::RECORD_BROADCAST:
940 // We don't track enabled sidechain.
941 break;
942 default:
943 break;
944 }
945 }
946
onInputConnected(const AudioInput & input)947 void EngineMaster::onInputConnected(const AudioInput& input) {
948 switch (input.getType()) {
949 case AudioInput::MICROPHONE:
950 m_pNumMicsConfigured->set(m_pNumMicsConfigured->get() + 1);
951 break;
952 case AudioInput::AUXILIARY:
953 // We don't track enabled auxiliary inputs.
954 break;
955 case AudioInput::VINYLCONTROL:
956 // We don't track enabled vinyl control inputs.
957 break;
958 case AudioInput::RECORD_BROADCAST:
959 m_bExternalRecordBroadcastInputConnected = true;
960 break;
961 default:
962 break;
963 }
964 }
965
onInputDisconnected(const AudioInput & input)966 void EngineMaster::onInputDisconnected(const AudioInput& input) {
967 switch (input.getType()) {
968 case AudioInput::MICROPHONE:
969 m_pNumMicsConfigured->set(m_pNumMicsConfigured->get() - 1);
970 break;
971 case AudioInput::AUXILIARY:
972 // We don't track enabled auxiliary inputs.
973 break;
974 case AudioInput::VINYLCONTROL:
975 // We don't track enabled vinyl control inputs.
976 break;
977 case AudioInput::RECORD_BROADCAST:
978 m_bExternalRecordBroadcastInputConnected = false;
979 break;
980 default:
981 break;
982 }
983 }
984
registerNonEngineChannelSoundIO(SoundManager * pSoundManager)985 void EngineMaster::registerNonEngineChannelSoundIO(SoundManager* pSoundManager) {
986 pSoundManager->registerInput(AudioInput(AudioPath::RECORD_BROADCAST, 0, 2),
987 m_pEngineSideChain);
988
989 pSoundManager->registerOutput(AudioOutput(AudioOutput::MASTER, 0, 2), this);
990 pSoundManager->registerOutput(AudioOutput(AudioOutput::HEADPHONES, 0, 2), this);
991 pSoundManager->registerOutput(AudioOutput(AudioOutput::BOOTH, 0, 2), this);
992 for (int o = EngineChannel::LEFT; o <= EngineChannel::RIGHT; o++) {
993 pSoundManager->registerOutput(AudioOutput(AudioOutput::BUS, 0, 2, o), this);
994 }
995 pSoundManager->registerOutput(AudioOutput(AudioOutput::RECORD_BROADCAST, 0, 2), this);
996 }
997
sidechainMixRequired() const998 bool EngineMaster::sidechainMixRequired() const {
999 return m_pEngineSideChain && !m_bExternalRecordBroadcastInputConnected;
1000 }
1001