Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4f5acf7
Merge branch 'master' into master_sync
rryan Jul 18, 2013
88132b7
Remove BpmControl::pickSyncTarget since this is now in EngineControl.
rryan Jul 18, 2013
f100b85
Remove unused method.
rryan Jul 18, 2013
76d2e34
Rename incrementPseudoPosition to be more clear about when it's calle…
rryan Jul 18, 2013
01504a6
Move channel processing to a helper method to simplify EngineMaster::…
rryan Jul 18, 2013
efdbcb9
Remove unused method.
rryan Jul 18, 2013
3dd24fc
Add general support for tracking the sync state of any group instaed …
rryan Jul 18, 2013
d766101
Get rid of void arguments.
rryan Jul 18, 2013
00bc659
Disconnect the specific connection, otherwise you disconnect all conn…
rryan Jul 18, 2013
9fed2b4
Delete EngineSync.
rryan Jul 18, 2013
61f6649
Remove unused stub.
rryan Jul 18, 2013
c961e3c
Store EngineChannel in SyncChannel so we don't have to look it up fro…
rryan Jul 18, 2013
2646349
Avoid getChannel lookups to EngineMaster by passing SyncChannels arou…
rryan Jul 18, 2013
dd2965c
Remove EngineSync dependence on EngineMaster.
rryan Jul 18, 2013
972ba93
Keep track of SyncChannel instead of EngineChannel as the channel mas…
rryan Jul 18, 2013
3a4aea7
Merge branch 'master_sync' of github.com:mixxxdj/mixxx into master_sync
rryan Jul 19, 2013
049f535
Delete SyncChannel control.
rryan Jul 19, 2013
8bf4272
Handle the case where a channel is set to master via control but sett…
rryan Jul 19, 2013
7e4425a
Delete SyncChannel in ~EngineSync.
rryan Jul 19, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 1 addition & 39 deletions src/engine/bpmcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ BpmControl::BpmControl(const char* _group,
this, SLOT(slotMasterBpmChanged(double)),
Qt::DirectConnection);

m_pSyncMasterEnabled = new ControlPushButton(ConfigKey(_group, "sync_master"));
m_pSyncMasterEnabled = new ControlPushButton(ConfigKey(_group, "sync_master"));
m_pSyncMasterEnabled->setButtonMode(ControlPushButton::TOGGLE);
connect(m_pSyncMasterEnabled, SIGNAL(valueChanged(double)),
this, SLOT(slotSyncMasterChanged(double)),
Expand Down Expand Up @@ -324,44 +324,6 @@ bool BpmControl::syncTempo() {
return false;
}

EngineBuffer* BpmControl::pickSyncTarget() {
EngineMaster* pMaster = getEngineMaster();
if (!pMaster) {
return NULL;
}
QString group = getGroup();
QStringList deckGroups;
EngineBuffer* pFirstNonplayingDeck = NULL;

for (int i = 0; i < m_pNumDecks->get(); ++i) {
// TODO(XXX) format from PlayerManager
QString deckGroup = QString("[Channel%1]").arg(i+1);
if (deckGroup == group) {
continue;
}
EngineChannel* pChannel = pMaster->getChannel(deckGroup);
// Only consider channels that have a track loaded and are in the master
// mix.
if (pChannel && pChannel->isActive() && pChannel->isMaster()) {
EngineBuffer* pBuffer = pChannel->getEngineBuffer();
if (pBuffer && pBuffer->getBpm() > 0) {
// If the deck is playing then go with it immediately.
if (fabs(pBuffer->getRate()) > 0) {
return pBuffer;
}
// Otherwise hold out for a deck that might be playing but
// remember the first deck that matched our criteria.
if (pFirstNonplayingDeck == NULL) {
pFirstNonplayingDeck = pBuffer;
}
}
}
}
// No playing decks have a BPM. Go with the first deck that was stopped but
// had a BPM.
return pFirstNonplayingDeck;
}

void BpmControl::slotMasterBpmChanged(double syncbpm) {
// Vinyl overrides
if (m_pVCEnabled && m_pVCEnabled->get() > 0) {
Expand Down
1 change: 0 additions & 1 deletion src/engine/bpmcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class BpmControl : public EngineControl {

private:
double getBeatDistance(double dThisPosition) const;
EngineBuffer* pickSyncTarget();
bool syncTempo();
bool syncPhase();

Expand Down
116 changes: 55 additions & 61 deletions src/engine/enginemaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ EngineMaster::EngineMaster(ConfigObject<ConfigValue> * _config,
m_pMasterRate = new ControlPotmeter(ConfigKey(group, "rate"), -1.0, 1.0);

// Master sync controller
m_pMasterSync = new EngineSync(this, _config);
m_pMasterSync = new EngineSync(_config);
// TODO(owen): save / restore default bpm
ControlObject::getControl(ConfigKey("[Master]","sync_bpm"))->set(124.0);
ControlObject::getControl(ConfigKey("[Master]","rate"))->set(124.0);
Expand Down Expand Up @@ -134,6 +134,7 @@ EngineMaster::~EngineMaster()
delete xFaderCurve;
delete xFaderMode;

delete m_pMasterSync;
delete m_pMasterSampleRate;
delete m_pMasterLatency;
delete m_pMasterAudioBufferSize;
Expand Down Expand Up @@ -166,16 +167,6 @@ const CSAMPLE* EngineMaster::getHeadphoneBuffer() const
return m_pHead;
}

EngineSync* EngineMaster::getMasterSync(void)
{
return m_pMasterSync;
}

void EngineMaster::setMasterSync(QString deck)
{
m_pMasterSync->setDeckMaster(deck);
}

void EngineMaster::mixChannels(unsigned int channelBitvector, unsigned int maxChannels,
CSAMPLE* pOutput, unsigned int iBufferSize,
GainCalculator* pGainCalculator) {
Expand Down Expand Up @@ -339,71 +330,45 @@ void EngineMaster::mixChannels(unsigned int channelBitvector, unsigned int maxCh
}
}

void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize) {
static bool haveSetName = false;
if (!haveSetName) {
QThread::currentThread()->setObjectName("Engine");
haveSetName = true;
}
ScopedTimer t("EngineMaster::process");

CSAMPLE **pOutput = (CSAMPLE**)pOut;
Q_UNUSED(pOutput);

// Prepare each channel for output

// Bitvector of enabled channels
const unsigned int maxChannels = 32;
unsigned int masterOutput = 0;
unsigned int headphoneOutput = 0;

// Compute headphone mix
// Head phone left/right mix
CSAMPLE cf_val = head_mix->get();
CSAMPLE chead_gain = 0.5*(-cf_val+1.);
CSAMPLE cmaster_gain = 0.5*(cf_val+1.);
// qDebug() << "head val " << cf_val << ", head " << chead_gain
// << ", master " << cmaster_gain;

// Increment internal buffer first in case it is the master
m_pMasterSync->incrementPseudoPosition(iBufferSize);

// TODO(owen): MIDI goes here, probably.

//find the Sync Master and process it first
//then process all the slaves (and skip the master)
void EngineMaster::processChannels(unsigned int* masterOutput,
unsigned int* headphoneOutput,
int iBufferSize) {
ScopedTimer timer("EngineMaster::processChannels");

Timer timer("EngineMaster::process channels");
QList<ChannelInfo*>::iterator it = m_channels.begin();
QList<ChannelInfo*>::iterator master_it = NULL;
if (m_pMasterSync->getMaster() != NULL) {

// Find the Sync Master and process it first then process all the slaves
// (and skip the master).

EngineChannel* pMasterChannel = m_pMasterSync->getMaster();
if (pMasterChannel != NULL) {
for (unsigned int channel_number = 0;
it != m_channels.end(); ++it, ++channel_number) {
ChannelInfo* pChannelInfo = *it;
EngineChannel* pChannel = pChannelInfo->m_pChannel;
if (!pChannel || !pChannel->isActive()) {
continue;
}
EngineBuffer* pBuffer = pChannel->getEngineBuffer();
if (pBuffer == m_pMasterSync->getMaster()->getEngineBuffer()) {

if (pMasterChannel == pChannel) {
master_it = it;

//proceed with the processing as below
// Proceed with the processing as below.
bool needsProcessing = false;
if (pChannel->isMaster()) {
masterOutput |= (1 << channel_number);
*masterOutput |= (1 << channel_number);
needsProcessing = true;
}

// If the channel is enabled for previewing in headphones, copy it
// over to the headphone buffer
if (pChannel->isPFL()) {
headphoneOutput |= (1 << channel_number);
*headphoneOutput |= (1 << channel_number);
needsProcessing = true;
}

// Process the buffer if necessary, which it damn well better be
Q_ASSERT(needsProcessing);
if (needsProcessing) {
pChannel->process(NULL, pChannelInfo->m_pBuffer, iBufferSize);
}
Expand All @@ -418,25 +383,26 @@ void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBuff
ChannelInfo* pChannelInfo = *it;
EngineChannel* pChannel = pChannelInfo->m_pChannel;

// Skip the master since we already processed it.
if (it == master_it) {
// We already processed this.
continue;
}

if (!pChannel->isActive()) {
// Skip inactive channels.
if (!pChannel || !pChannel->isActive()) {
continue;
}

bool needsProcessing = false;
if (pChannel->isMaster()) {
masterOutput |= (1 << channel_number);
*masterOutput |= (1 << channel_number);
needsProcessing = true;
}

// If the channel is enabled for previewing in headphones, copy it
// over to the headphone buffer
if (pChannel->isPFL()) {
headphoneOutput |= (1 << channel_number);
*headphoneOutput |= (1 << channel_number);
needsProcessing = true;
}

Expand All @@ -445,7 +411,38 @@ void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBuff
pChannel->process(NULL, pChannelInfo->m_pBuffer, iBufferSize);
}
}
timer.elapsed(true);
}

void EngineMaster::process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize) {
static bool haveSetName = false;
if (!haveSetName) {
QThread::currentThread()->setObjectName("Engine");
haveSetName = true;
}
ScopedTimer t("EngineMaster::process");

// Notify EngineSync that we are starting the callback.
m_pMasterSync->onCallbackStart(iBufferSize);

CSAMPLE **pOutput = (CSAMPLE**)pOut;
Q_UNUSED(pOutput);

// Bitvector of enabled channels
const unsigned int maxChannels = 32;
unsigned int masterOutput = 0;
unsigned int headphoneOutput = 0;

// Prepare each channel for output
processChannels(&masterOutput, &headphoneOutput, iBufferSize);

// Compute headphone mix
// Head phone left/right mix
CSAMPLE cf_val = head_mix->get();
CSAMPLE chead_gain = 0.5*(-cf_val+1.);
CSAMPLE cmaster_gain = 0.5*(cf_val+1.);
// qDebug() << "head val " << cf_val << ", head " << chead_gain
// << ", master " << cmaster_gain;


// Mix all the enabled headphone channels together.
m_headphoneGain.setGain(chead_gain);
Expand Down Expand Up @@ -522,7 +519,7 @@ void EngineMaster::addChannel(EngineChannel* pChannel) {
SampleUtil::applyGain(pChannelInfo->m_pBuffer, 0, MAX_BUFFER_LEN);
m_channels.push_back(pChannelInfo);

m_pMasterSync->addDeck(pChannel->getGroup());
m_pMasterSync->addChannel(pChannel);

EngineBuffer* pBuffer = pChannelInfo->m_pChannel->getEngineBuffer();
if (pBuffer != NULL) {
Expand All @@ -542,9 +539,6 @@ EngineChannel* EngineMaster::getChannel(QString group) {
return NULL;
}

int EngineMaster::numChannels() const {
return m_channels.size();
}
const CSAMPLE* EngineMaster::getDeckBuffer(unsigned int i) const {
return getChannelBuffer(PlayerManager::groupForDeck(i));
}
Expand Down
12 changes: 8 additions & 4 deletions src/engine/enginemaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ class EngineMaster : public EngineObject, public AudioSource {

// Get access to the sample buffers. None of these are thread safe. Only to
// be called by SoundManager.
int numChannels() const;
const CSAMPLE* buffer(AudioOutput output) const;

void process(const CSAMPLE *, const CSAMPLE *pOut, const int iBufferSize);

EngineSync* getMasterSync(void);
void setMasterSync(QString deck);

// Add an EngineChannel to the mixing engine. This is not thread safe --
// only call it before the engine has started mixing.
Expand Down Expand Up @@ -136,6 +132,14 @@ class EngineMaster : public EngineObject, public AudioSource {
void mixChannels(unsigned int channelBitvector, unsigned int maxChannels,
CSAMPLE* pOutput, unsigned int iBufferSize, GainCalculator* pGainCalculator);

// Processes active channels. The master sync channel (if any) is processed
// first and all others are processed after. Sets the i'th bit of
// masterOutput and headphoneOutput if the i'th channel is enabled for the
// master output or headphone output, respectively.
void processChannels(unsigned int* masterOutput,
unsigned int* headphoneOutput,
int iBufferSize);

QList<ChannelInfo*> m_channels;

CSAMPLE *m_pMaster, *m_pHead;
Expand Down
Loading