void CueControl::trackLoaded(TrackPointer pTrack) { QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) trackUnloaded(m_pLoadedTrack); if (!pTrack) { return; } m_pLoadedTrack = pTrack; connect(pTrack.data(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); Cue* loadCue = NULL; const QList<Cue*>& cuePoints = pTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; } else if (pCue->getType() != Cue::CUE) { continue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) attachCue(pCue, hotcue); } double loadCuePoint = 0.0; // If cue recall is ON in the prefs, then we're supposed to seek to the cue // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF. bool cueRecall = (getConfig()->getValueString( ConfigKey("[Controls]","CueRecall"), "0").toInt() == 0); if (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); if (cueRecall) { loadCuePoint = loadCue->getPosition(); } } else { // If no cue point is stored, set one at track start m_pCuePoint->set(0.0); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); // If cueRecall is on, seek to it even if we didn't find a cue value (we'll // seek to 0. if (cueRecall) { seekExact(loadCuePoint); } else if (!(m_pVinylControlEnabled->get() && m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) { // If cuerecall is off, seek to zero unless // vinylcontrol is on and set to absolute. This allows users to // load tracks and have the needle-drop be maintained. seekExact(0.0); } }
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; Cue* pCue = pControl->getCue(); if (v) { if (pCue && pCue->getPosition() != -1) { m_iCurrentlyPreviewingHotcues++; int iPosition = pCue->getPosition(); m_pPlayButton->set(1.0); m_bPreviewingHotcue = true; pControl->setPreviewing(true); pControl->setPreviewingPosition(iPosition); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(iPosition); } } else if (m_bPreviewingHotcue) { // This is a activate release and we are previewing at least one // hotcue. If this hotcue is previewing: if (pControl->isPreviewing()) { // Mark this hotcue as not previewing. int iPosition = pControl->getPreviewingPosition(); pControl->setPreviewing(false); pControl->setPreviewingPosition(-1); // If this is the last hotcue to leave preview. if (--m_iCurrentlyPreviewingHotcues == 0) { bool bHotcueCancel = m_bHotcueCancel; m_bPreviewingHotcue = false; m_bHotcueCancel = false; // If hotcue cancel is marked then do not snap back to the // hotcue and stop. Otherwise, seek back to the start point and // stop. if (bHotcueCancel) { // Re-trigger the play button value so controllers get the correct one // after. m_pPlayButton->set(m_pPlayButton->get()); } else { m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(iPosition); } } } } }
void CueControl::trackLoaded(TrackPointer pTrack) { QMutexLocker lock(&m_mutex); if (m_pLoadedTrack) trackUnloaded(m_pLoadedTrack); if (!pTrack) { return; } m_pLoadedTrack = pTrack; connect(pTrack.data(), SIGNAL(cuesUpdated()), this, SLOT(trackCuesUpdated()), Qt::DirectConnection); Cue* loadCue = NULL; const QList<Cue*>& cuePoints = pTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOAD) { loadCue = pCue; } else if (pCue->getType() != Cue::CUE) { continue; } int hotcue = pCue->getHotCue(); if (hotcue != -1) attachCue(pCue, hotcue); } double loadCuePoint = 0.0; if (loadCue != NULL) { m_pCuePoint->set(loadCue->getPosition()); // If cue recall is ON in the prefs, then we're supposed to seek to the cue // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF. if (!getConfig()->getValueString( ConfigKey("[Controls]","CueRecall")).toInt()) { loadCuePoint = loadCue->getPosition(); } } else { // If no cue point is stored, set one at track start m_pCuePoint->set(0.0); } // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(loadCuePoint); }
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) { QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } Cue* pCue = pControl->getCue(); if (v) { if (pCue && pCue->getPosition() != -1) { m_iCurrentlyPreviewingHotcues++; int iPosition = pCue->getPosition(); m_bPreviewingHotcue = true; m_pPlayButton->set(1.0); pControl->setPreviewing(true); pControl->setPreviewingPosition(iPosition); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekAbs(iPosition); } } else if (m_bPreviewingHotcue) { // This is a activate release and we are previewing at least one // hotcue. If this hotcue is previewing: if (pControl->isPreviewing()) { // Mark this hotcue as not previewing. int iPosition = pControl->getPreviewingPosition(); pControl->setPreviewing(false); pControl->setPreviewingPosition(-1); // If this is the last hotcue to leave preview. if (--m_iCurrentlyPreviewingHotcues == 0) { bool bHotcueCancel = m_bHotcueCancel; m_bPreviewingHotcue = false; m_bHotcueCancel = false; // If hotcue cancel was not marked then snap back to the // hotcue and stop. if (!bHotcueCancel) { m_pPlayButton->set(0.0); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); seekExact(iPosition); } } } } }
void CueControl::hotcueActivate(HotcueControl* pControl, double v) { //qDebug() << "CueControl::hotcueActivate" << v; QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) { return; } Cue* pCue = pControl->getCue(); lock.unlock(); if (pCue) { if (v) { m_bHotcueCancel = false; if (pCue->getPosition() == -1) { hotcueSet(pControl, v); } else { if (!m_bPreviewingHotcue && m_pPlayButton->get() == 1.0) { hotcueGoto(pControl, v); } else { hotcueActivatePreview(pControl, v); } } } else { if (pCue->getPosition() != -1) { hotcueActivatePreview(pControl, v); } } } else { if (v) { // just in case m_bHotcueCancel = false; hotcueSet(pControl, v); } else if (m_bPreviewingHotcue) { // The cue is non-existent, yet we got a release for it and are // currently previewing a hotcue. This is indicative of a corner // case where the cue was detached while we were pressing it. Let // hotcueActivatePreview handle it. hotcueActivatePreview(pControl, v); } } }
void CueControl::trackCuesUpdated() { QMutexLocker lock(&m_mutex); QSet<int> active_hotcues; if (!m_pLoadedTrack) return; const QList<Cue*>& cuePoints = m_pLoadedTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() != Cue::CUE && pCue->getType() != Cue::LOAD) continue; int hotcue = pCue->getHotCue(); if (hotcue != -1) { HotcueControl* pControl = m_hotcueControl.value(hotcue, NULL); // Cue's hotcue doesn't have a hotcue control. if (pControl == NULL) { continue; } Cue* pOldCue = pControl->getCue(); // If the old hotcue is different than this one. if (pOldCue != pCue) { // If the old hotcue exists, detach it if (pOldCue != NULL) detachCue(hotcue); attachCue(pCue, hotcue); } else { // If the old hotcue is the same, then we only need to update double dOldPosition = pControl->getPosition()->get(); double dOldEnabled = pControl->getEnabled()->get(); double dPosition = pCue->getPosition(); double dEnabled = dPosition == -1 ? 0.0 : 1.0; if (dEnabled != dOldEnabled) { pControl->getEnabled()->set(dEnabled); } if (dPosition != dOldPosition) { pControl->getPosition()->set(dPosition); } } // Add the hotcue to the list of active hotcues active_hotcues.insert(hotcue); } } // Detach all hotcues that are no longer present for (int i = 0; i < m_iNumHotCues; ++i) { if (!active_hotcues.contains(i)) detachCue(i); } }
void CueControl::hotcueGoto(HotcueControl* pControl, double v) { if (!v) return; QMutexLocker lock(&m_mutex); if (!m_pLoadedTrack) return; Cue* pCue = pControl->getCue(); // Need to unlock before emitting any signals to prevent deadlock. lock.unlock(); if (pCue) { int position = pCue->getPosition(); if (position != -1) { seekAbs(position); } } }
void BaseTrackPlayer::slotFinishLoading(TrackPointer pTrackInfoObject) { // Read the tags if required if (!m_pLoadedTrack->getHeaderParsed()) { m_pLoadedTrack->parse(); } // m_pLoadedTrack->setPlayedAndUpdatePlaycount(true); // Actually the song is loaded but not played // Update the BPM and duration values that are stored in ControlObjects m_pDuration->set(m_pLoadedTrack->getDuration()); m_pBPM->slotSet(m_pLoadedTrack->getBpm()); m_pKey->slotSet(m_pLoadedTrack->getKey()); m_pReplayGain->slotSet(m_pLoadedTrack->getReplayGain()); // Update the PlayerInfo class that is used in EngineShoutcast to replace // the metadata of a stream PlayerInfo::instance().setTrackInfo(getGroup(), m_pLoadedTrack); // Reset the loop points. m_pLoopInPoint->slotSet(-1); m_pLoopOutPoint->slotSet(-1); const QList<Cue*> trackCues = pTrackInfoObject->getCuePoints(); QListIterator<Cue*> it(trackCues); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOOP) { int loopStart = pCue->getPosition(); int loopEnd = loopStart + pCue->getLength(); if (loopStart != -1 && loopEnd != -1 && even(loopStart) && even(loopEnd)) { m_pLoopInPoint->slotSet(loopStart); m_pLoopOutPoint->slotSet(loopEnd); break; } } } emit(newTrackLoaded(m_pLoadedTrack)); }
void VinylControlControl::slotControlVinylSeek(double change) { if (isnan(change) || change > 1.14 || change < -0.14) { // This seek is ridiculous. return; } double total_samples = getTotalSamples(); double new_playpos = round(change*total_samples); // Do nothing if no track is loaded. if (!m_pCurrentTrack) { return; } if (m_pControlVinylEnabled->get() > 0.0 && m_pControlVinylMode->get() == MIXXX_VCMODE_RELATIVE) { int cuemode = (int)m_pControlVinylCueing->get(); //if in preroll, always seek if (new_playpos < 0) { seek(change); return; } switch (cuemode) { case MIXXX_RELATIVE_CUE_OFF: return; // If off, do nothing. case MIXXX_RELATIVE_CUE_ONECUE: //if onecue, just seek to the regular cue seekExact(m_pCurrentTrack->getCuePoint()); return; case MIXXX_RELATIVE_CUE_HOTCUE: // Continue processing in this function. break; default: qWarning() << "Invalid vinyl cue setting"; return; } double distance = 0; int nearest_playpos = -1; QList<Cue*> cuePoints = m_pCurrentTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() != Cue::CUE || pCue->getHotCue() == -1) { continue; } int cue_position = pCue->getPosition(); //pick cues closest to new_playpos if ((nearest_playpos == -1) || (fabs(new_playpos - cue_position) < distance)) { nearest_playpos = cue_position; distance = fabs(new_playpos - cue_position); } } if (nearest_playpos == -1) { if (new_playpos >= 0) { //never found an appropriate cue, so don't seek? return; } //if negative, allow a seek by falling down to the bottom } else { m_bSeekRequested = true; seekExact(nearest_playpos); m_bSeekRequested = false; return; } } // Just seek where it wanted to originally. m_bSeekRequested = true; seek(change); m_bSeekRequested = false; }
void DlgTrackInfo::populateCues(TrackPointer pTrack) { int sampleRate = pTrack->getSampleRate(); QList<Cue*> listPoints; const QList<Cue*>& cuePoints = pTrack->getCuePoints(); QListIterator<Cue*> it(cuePoints); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::CUE || pCue->getType() == Cue::LOAD) { listPoints.push_back(pCue); } } it = QListIterator<Cue*>(listPoints); cueTable->setSortingEnabled(false); int row = 0; while (it.hasNext()) { Cue* pCue = it.next(); QString rowStr = QString("%1").arg(row); // All hotcues are stored in Cue's as 0-indexed, but the GUI presents // them to the user as 1-indexex. Add 1 here. rryan 9/2010 int iHotcue = pCue->getHotCue() + 1; QString hotcue = ""; if (iHotcue != -1) { hotcue = QString("%1").arg(iHotcue); } int position = pCue->getPosition(); double totalSeconds; if (position == -1) continue; else { totalSeconds = float(position) / float(sampleRate) / 2.0; } int fraction = 100*(totalSeconds - floor(totalSeconds)); int seconds = int(totalSeconds) % 60; int mins = int(totalSeconds) / 60; //int hours = mins / 60; //Not going to worry about this for now. :) //Construct a nicely formatted duration string now. QString duration = QString("%1:%2.%3").arg( QString::number(mins), QString("%1").arg(seconds, 2, 10, QChar('0')), QString("%1").arg(fraction, 2, 10, QChar('0'))); QTableWidgetItem* durationItem = new QTableWidgetItem(duration); // Make the duration read only durationItem->setFlags(Qt::NoItemFlags); m_cueMap[row] = pCue; cueTable->insertRow(row); cueTable->setItem(row, 0, new QTableWidgetItem(rowStr)); cueTable->setItem(row, 1, durationItem); cueTable->setItem(row, 2, new QTableWidgetItem(hotcue)); cueTable->setItem(row, 3, new QTableWidgetItem(pCue->getLabel())); row += 1; } cueTable->setSortingEnabled(true); }
void BaseTrackPlayerImpl::slotFinishLoading(TrackPointer pTrackInfoObject) { m_replaygainPending = false; // Read the tags if required if (!m_pLoadedTrack->getHeaderParsed()) { m_pLoadedTrack->parse(false); } // m_pLoadedTrack->setPlayedAndUpdatePlaycount(true); // Actually the song is loaded but not played // Update the BPM and duration values that are stored in ControlObjects m_pDuration->set(m_pLoadedTrack->getDuration()); m_pBPM->slotSet(m_pLoadedTrack->getBpm()); m_pKey->slotSet(m_pLoadedTrack->getKey()); m_pReplayGain->slotSet(m_pLoadedTrack->getReplayGain()); // Update the PlayerInfo class that is used in EngineShoutcast to replace // the metadata of a stream PlayerInfo::instance().setTrackInfo(getGroup(), m_pLoadedTrack); // Reset the loop points. m_pLoopInPoint->slotSet(-1); m_pLoopOutPoint->slotSet(-1); const QList<Cue*> trackCues = pTrackInfoObject->getCuePoints(); QListIterator<Cue*> it(trackCues); while (it.hasNext()) { Cue* pCue = it.next(); if (pCue->getType() == Cue::LOOP) { int loopStart = pCue->getPosition(); int loopEnd = loopStart + pCue->getLength(); if (loopStart != -1 && loopEnd != -1 && even(loopStart) && even(loopEnd)) { m_pLoopInPoint->slotSet(loopStart); m_pLoopOutPoint->slotSet(loopEnd); break; } } } if(m_pConfig->getValueString(ConfigKey("[Mixer Profile]", "EqAutoReset"), 0).toInt()) { if (m_pLowFilter != NULL) { m_pLowFilter->set(1.0); } if (m_pMidFilter != NULL) { m_pMidFilter->set(1.0); } if (m_pHighFilter != NULL) { m_pHighFilter->set(1.0); } if (m_pLowFilterKill != NULL) { m_pLowFilterKill->set(0.0); } if (m_pMidFilterKill != NULL) { m_pMidFilterKill->set(0.0); } if (m_pHighFilterKill != NULL) { m_pHighFilterKill->set(0.0); } m_pPreGain->set(1.0); } if(m_pConfig->getValueString(ConfigKey("[Controls]", "SpeedAutoReset"), 0).toInt()) { if (m_pSpeed != NULL) { m_pSpeed->set(0.0); } // Note: speed may effect pitch if (m_pPitch != NULL) { m_pPitch->set(0.0); } } emit(newTrackLoaded(m_pLoadedTrack)); }