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::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::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 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::saveTrack() { if (!m_pLoadedTrack) return; m_pLoadedTrack->setTitle(txtTrackName->text()); m_pLoadedTrack->setArtist(txtArtist->text()); m_pLoadedTrack->setAlbum(txtAlbum->text()); m_pLoadedTrack->setAlbumArtist(txtAlbumArtist->text()); m_pLoadedTrack->setGenre(txtGenre->text()); m_pLoadedTrack->setComposer(txtComposer->text()); m_pLoadedTrack->setGrouping(txtGrouping->text()); m_pLoadedTrack->setYear(txtYear->text()); m_pLoadedTrack->setTrackNumber(txtTrackNumber->text()); m_pLoadedTrack->setComment(txtComment->toPlainText()); if (!m_pLoadedTrack->hasBpmLock()) { m_pLoadedTrack->setBpm(spinBpm->value()); } QSet<int> updatedRows; for (int row = 0; row < cueTable->rowCount(); ++row) { QTableWidgetItem* rowItem = cueTable->item(row, 0); QTableWidgetItem* hotcueItem = cueTable->item(row, 2); QTableWidgetItem* labelItem = cueTable->item(row, 3); if (!rowItem || !hotcueItem || !labelItem) continue; int oldRow = rowItem->data(Qt::DisplayRole).toInt(); Cue* pCue = m_cueMap.value(oldRow, NULL); if (pCue == NULL) { continue; } updatedRows.insert(oldRow); QVariant vHotcue = hotcueItem->data(Qt::DisplayRole); if (vHotcue.canConvert<int>()) { int iTableHotcue = vHotcue.toInt(); // The GUI shows hotcues as 1-indexed, but they are actually // 0-indexed, so subtract 1 pCue->setHotCue(iTableHotcue-1); } else { pCue->setHotCue(-1); } QString label = labelItem->data(Qt::DisplayRole).toString(); pCue->setLabel(label); } QMutableHashIterator<int,Cue*> it(m_cueMap); // Everything that was not processed above was removed. while (it.hasNext()) { it.next(); int oldRow = it.key(); // If cue's old row is not in updatedRows then it must have been // deleted. if (updatedRows.contains(oldRow)) { continue; } Cue* pCue = it.value(); it.remove(); qDebug() << "Deleting cue" << pCue->getId() << pCue->getHotCue(); m_pLoadedTrack->removeCue(pCue); } }
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); }