=== modified file 'mixxx/src/dlgprefsounditem.cpp' --- mixxx/src/dlgprefsounditem.cpp 2011-12-18 20:23:14 +0000 +++ mixxx/src/dlgprefsounditem.cpp 2012-04-27 10:58:14 +0000 @@ -37,13 +37,8 @@ , m_savedDevice("") , m_savedChannel(0) { setupUi(this); - if (AudioPath::isIndexed(type)) { - typeLabel->setText( - QString("%1 %2").arg(AudioPath::getTrStringFromType(type), - QString::number(index + 1))); - } else { - typeLabel->setText(AudioPath::getTrStringFromType(type)); - } + typeLabel->setText(AudioPath::getTrStringFromType(type, index)); + deviceComboBox->addItem(tr("None"), "None"); connect(deviceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(deviceChanged(int))); === modified file 'mixxx/src/engine/enginemaster.cpp' --- mixxx/src/engine/enginemaster.cpp 2011-11-09 04:30:24 +0000 +++ mixxx/src/engine/enginemaster.cpp 2012-04-29 12:08:24 +0000 @@ -94,6 +94,17 @@ memset(m_pHead, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN); memset(m_pMaster, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN); + // Setup the cross fader channels + for (int o = EngineChannel::LEFT ; o <= EngineChannel::RIGHT ; o++) { + struct XFaderChannel* chan = &m_XFaderChannel[o]; + chan->m_pBuffer = SampleUtil::alloc(MAX_BUFFER_LEN); + memset(chan->m_pBuffer, 0, sizeof(CSAMPLE) * MAX_BUFFER_LEN); + chan->m_OrientationGain.setGains(1.0, + 1.0*(o == EngineChannel::LEFT), + 1.0*(o == EngineChannel::CENTER), + 1.0*(o == EngineChannel::RIGHT)); + } + //Starts a thread for recording and shoutcast sidechain = NULL; if (bEnableSidechain) { @@ -134,6 +145,9 @@ SampleUtil::free(m_pHead); SampleUtil::free(m_pMaster); + for (int o = EngineChannel::LEFT ; o <= EngineChannel::RIGHT ; o++) + SampleUtil::free(m_XFaderChannel[o].m_pBuffer); + QMutableListIterator channel_it(m_channels); while (channel_it.hasNext()) { ChannelInfo* pChannelInfo = channel_it.next(); @@ -328,7 +342,7 @@ // Bitvector of enabled channels const unsigned int maxChannels = 32; - unsigned int masterOutput = 0; + unsigned int xFader[3] = { 0, 0, 0 }; unsigned int headphoneOutput = 0; // Compute headphone mix @@ -351,7 +365,7 @@ bool needsProcessing = false; if (pChannel->isMaster()) { - masterOutput |= (1 << channel_number); + xFader[pChannel->getOrientation()] |= (1 << channel_number); needsProcessing = true; } @@ -372,17 +386,24 @@ m_headphoneGain.setGain(chead_gain); mixChannels(headphoneOutput, maxChannels, m_pHead, iBufferSize, &m_headphoneGain); + // Make the mix for each input of the cross fader + for (int o = EngineChannel::LEFT ; o <= EngineChannel::RIGHT ; o++) + mixChannels(xFader[o], maxChannels, m_XFaderChannel[o].m_pBuffer, iBufferSize, + &m_XFaderChannel[o].m_OrientationGain); + // Calculate the crossfader gains for left and right side of the crossfader float c1_gain, c2_gain; EngineXfader::getXfadeGains(c1_gain, c2_gain, crossfader->get(), xFaderCurve->get(), xFaderCalibration->get()); - // Now set the gains for overall volume and the left, center, right gains. - m_masterGain.setGains(m_pMasterVolume->get(), c1_gain, 1.0, c2_gain); - - // Perform the master mix - mixChannels(masterOutput, maxChannels, m_pMaster, iBufferSize, &m_masterGain); + // And mix the 3 into the master + float master_gain = m_pMasterVolume->get(); + SampleUtil::copy3WithGain(m_pMaster, + m_XFaderChannel[EngineChannel::LEFT].m_pBuffer, c1_gain*master_gain, + m_XFaderChannel[EngineChannel::CENTER].m_pBuffer, master_gain, + m_XFaderChannel[EngineChannel::RIGHT].m_pBuffer, c2_gain*master_gain, + iBufferSize); #ifdef __LADSPA__ // LADPSA master effects @@ -473,6 +494,12 @@ return getChannelBuffer(QString("[Channel%1]").arg(i+1)); } +const CSAMPLE* EngineMaster::getXFaderBuffer(unsigned int i) const { + if (i <= EngineChannel::RIGHT) + return m_XFaderChannel[i].m_pBuffer; + return NULL; +} + const CSAMPLE* EngineMaster::getChannelBuffer(QString group) const { for (QList::const_iterator i = m_channels.constBegin(); i != m_channels.constEnd(); ++i) { @@ -492,6 +519,9 @@ case AudioOutput::HEADPHONES: return getHeadphoneBuffer(); break; + case AudioOutput::XFADERINPUT: + return getXFaderBuffer(output.getIndex()); + break; case AudioOutput::DECK: return getDeckBuffer(output.getIndex()); break; === modified file 'mixxx/src/engine/enginemaster.h' --- mixxx/src/engine/enginemaster.h 2011-11-09 04:30:24 +0000 +++ mixxx/src/engine/enginemaster.h 2012-04-27 10:58:14 +0000 @@ -76,6 +76,7 @@ // These are really only exposed for tests to use. const CSAMPLE* getMasterBuffer() const; const CSAMPLE* getHeadphoneBuffer() const; + const CSAMPLE* getXFaderBuffer(unsigned int i) const; const CSAMPLE* getDeckBuffer(unsigned int i) const; const CSAMPLE* getChannelBuffer(QString name) const; @@ -131,6 +132,11 @@ QList m_channels; + struct XFaderChannel { + CSAMPLE *m_pBuffer; + OrientationVolumeGainCalculator m_OrientationGain; + } m_XFaderChannel[3]; + CSAMPLE *m_pMaster, *m_pHead; EngineWorkerScheduler *m_pWorkerScheduler; @@ -153,7 +159,6 @@ *m_pBalance, *xFaderCurve, *xFaderCalibration; ConstantGainCalculator m_headphoneGain; - OrientationVolumeGainCalculator m_masterGain; }; #endif === modified file 'mixxx/src/mixxx.cpp' --- mixxx/src/mixxx.cpp 2012-04-26 21:26:39 +0000 +++ mixxx/src/mixxx.cpp 2012-04-27 10:58:14 +0000 @@ -279,6 +279,10 @@ m_pSoundManager->registerOutput( AudioOutput(AudioOutput::DECK, 0, deck), m_pEngine); } + for (int o = EngineChannel::LEFT ; o <= EngineChannel::RIGHT ; o++) { + m_pSoundManager->registerOutput( + AudioOutput(AudioOutput::XFADERINPUT, 0, o), m_pEngine); + } #ifdef __VINYLCONTROL__ m_pVCManager = new VinylControlManager(this, m_pConfig); === modified file 'mixxx/src/soundmanager.cpp' --- mixxx/src/soundmanager.cpp 2011-11-03 20:48:06 +0000 +++ mixxx/src/soundmanager.cpp 2012-04-27 10:58:14 +0000 @@ -413,7 +413,8 @@ m_outputBuffers[out] = m_registeredSources[out]->buffer(out); if (out.getType() == AudioOutput::MASTER) { m_pClkRefDevice = device; - } else if (out.getType() == AudioOutput::DECK + } else if ((out.getType() == AudioOutput::DECK || + out.getType() == AudioOutput::XFADERINPUT) && !m_pClkRefDevice) { m_pClkRefDevice = device; } === modified file 'mixxx/src/soundmanagerutil.cpp' --- mixxx/src/soundmanagerutil.cpp 2011-12-18 20:23:14 +0000 +++ mixxx/src/soundmanagerutil.cpp 2012-04-27 10:58:14 +0000 @@ -15,6 +15,7 @@ #include #include "soundmanagerutil.h" +#include "engine/enginechannel.h" /** * Constructs a ChannelGroup. @@ -136,11 +137,7 @@ * Returns a string describing the AudioPath for user benefit. */ QString AudioPath::getString() const { - if (isIndexed(getType())) { - return QString("%1 %2").arg(getTrStringFromType(getType()), - QString::number(m_index + 1)); - } - return getTrStringFromType(getType()); + return getTrStringFromType(m_type, m_index); } /** @@ -158,6 +155,8 @@ return QString::fromAscii("Master"); case HEADPHONES: return QString::fromAscii("Headphones"); + case XFADERINPUT: + return QString::fromAscii("Crossfader input"); case DECK: return QString::fromAscii("Deck"); case VINYLCONTROL: @@ -174,7 +173,10 @@ * Returns a translated string given an AudioPathType. * @note This method is static. */ -QString AudioPath::getTrStringFromType(AudioPathType type) { +QString AudioPath::getTrStringFromType(AudioPathType type, unsigned char index) { + QString str_type; + QString str_index = QString::number(index + 1); + switch (type) { case INVALID: // this shouldn't happen but g++ complains if I don't @@ -184,16 +186,37 @@ return QString(QObject::tr("Master")); case HEADPHONES: return QString(QObject::tr("Headphones")); + case XFADERINPUT: + str_type = QObject::tr("Crossfader input"); + switch (index) { + case EngineChannel::LEFT: + str_index = QObject::tr("left"); + break; + case EngineChannel::CENTER: + str_index = QObject::tr("center"); + break; + case EngineChannel::RIGHT: + str_index = QObject::tr("right"); + break; + default: + break; + } + break; case DECK: - return QString(QObject::tr("Deck")); + str_type = QObject::tr("Deck"); + break; case VINYLCONTROL: - return QString(QObject::tr("Vinyl Control")); + str_type = QObject::tr("Vinyl Control"); + break; case MICROPHONE: return QString(QObject::tr("Microphone")); case EXTPASSTHROUGH: - return QString(QObject::tr("Passthrough")); + str_type = QObject::tr("Passthrough"); + break; + default: + return QString(QObject::tr("Unknown path type %1")).arg(type); } - return QString(QObject::tr("Unknown path type %1")).arg(type); + return QString("%1 %2").arg(str_type, str_index); } /** @@ -206,6 +229,8 @@ return AudioPath::MASTER; } else if (string == AudioPath::getStringFromType(AudioPath::HEADPHONES).toLower()) { return AudioPath::HEADPHONES; + } else if (string == AudioPath::getStringFromType(AudioPath::XFADERINPUT).toLower()) { + return AudioPath::XFADERINPUT; } else if (string == AudioPath::getStringFromType(AudioPath::DECK).toLower()) { return AudioPath::DECK; } else if (string == AudioPath::getStringFromType(AudioPath::VINYLCONTROL).toLower()) { @@ -225,6 +250,7 @@ */ bool AudioPath::isIndexed(AudioPathType type) { switch (type) { + case XFADERINPUT: case DECK: case VINYLCONTROL: case EXTPASSTHROUGH: @@ -308,6 +334,7 @@ QList types; types.append(MASTER); types.append(HEADPHONES); + types.append(XFADERINPUT); types.append(DECK); return types; } === modified file 'mixxx/src/soundmanagerutil.h' --- mixxx/src/soundmanagerutil.h 2011-05-30 06:04:23 +0000 +++ mixxx/src/soundmanagerutil.h 2012-04-27 10:58:14 +0000 @@ -55,6 +55,7 @@ enum AudioPathType { MASTER, HEADPHONES, + XFADERINPUT, DECK, VINYLCONTROL, MICROPHONE, @@ -70,7 +71,7 @@ bool channelsClash(const AudioPath &other) const; QString getString() const; static QString getStringFromType(AudioPathType type); - static QString getTrStringFromType(AudioPathType type); + static QString getTrStringFromType(AudioPathType type, unsigned char index); static AudioPathType getTypeFromString(QString string); static bool isIndexed(AudioPathType type); static AudioPathType getTypeFromInt(int typeInt);