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 PlayerInfo::setTrackInfo(const QString& group, const TrackPointer& track) { QMutexLocker locker(&m_mutex); TrackPointer pOld = m_loadedTrackMap.value(group); if (pOld) { emit(trackUnloaded(group, pOld)); } m_loadedTrackMap.insert(group, track); emit(trackLoaded(group, track)); }
void BpmControl::trackLoaded(TrackPointer pTrack) { trackUnloaded(m_pTrack); if (pTrack) { m_pTrack = pTrack; m_pBeats = m_pTrack->getBeats(); connect(m_pTrack.data(), SIGNAL(beatsUpdated()), this, SLOT(slotUpdatedTrackBeats())); } }
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); }
// Create the temporary auto-DJ-crates table. // Done the first time it's used, since the user might not even make // use of this feature. void AutoDJCratesDAO::createAutoDjCratesDatabase() { // If the use of tracks that haven't been played in a while has changed, // then the active-tracks view must be recreated. bool bUseIgnoreTime = (bool) m_pConfig->getValueString( ConfigKey("[Auto DJ]", "UseIgnoreTime"), "0").toInt(); if (m_bAutoDjCratesDbCreated) { if (m_bUseIgnoreTime != bUseIgnoreTime) { // Do all this in a single transaction. ScopedTransaction oTransaction(m_rDatabase); // Get rid of the old active-tracks view. QSqlQuery oQuery(m_rDatabase); oQuery.exec ("DROP VIEW IF EXISTS " AUTODJACTIVETRACKS_TABLE); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return; } // Create the new active-tracks view. if (!createActiveTracksView (bUseIgnoreTime)) { return; } // Remember the new setting. m_bUseIgnoreTime = bUseIgnoreTime; // Commit these changes. oTransaction.commit(); } } else { m_bUseIgnoreTime = bUseIgnoreTime; } // If this database has already been created, skip this. if (m_bAutoDjCratesDbCreated) { return; } // Do all of this in a single transaction. ScopedTransaction oTransaction(m_rDatabase); // The auto-DJ-crates table contains the track ID, the number of references // to that track ID in all of the auto-DJ crates, the number of times that // track has been played, and the number of references to the track in the // auto-DJ playlist (or in loaded decks). It filters out tracks that have // been deleted from the database (i.e. "hidden" tracks). // Create an empty table. QSqlQuery oQuery(m_rDatabase); // CREATE TEMP TABLE temp_autodj_crates (track_id INTEGER UNIQUE, craterefs INTEGER, timesplayed INTEGER, autodjrefs INTEGER, lastplayed DATETIME); //oQuery.exec ("DROP TABLE IF EXISTS " AUTODJCRATES_TABLE); QString strQuery("CREATE TEMP TABLE " AUTODJCRATES_TABLE " (" AUTODJCRATESTABLE_TRACKID " INTEGER UNIQUE, " AUTODJCRATESTABLE_CRATEREFS " INTEGER, " AUTODJCRATESTABLE_TIMESPLAYED " INTEGER, " AUTODJCRATESTABLE_AUTODJREFS " INTEGER, " AUTODJCRATESTABLE_LASTPLAYED " DATETIME)"); oQuery.prepare(strQuery); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return; } // Fill out the first three columns. // Supply default values for the last two. // INSERT INTO temp_autodj_crates (track_id, craterefs, timesplayed, autodjrefs, lastplayed) SELECT crate_tracks.track_id, COUNT (*), library.timesplayed, 0, "" FROM crate_tracks, library WHERE crate_tracks.crate_id IN (SELECT id FROM crates WHERE autodj = 1) AND crate_tracks.track_id = library.id AND library.mixxx_deleted = 0 GROUP BY crate_tracks.track_id, library.timesplayed; strQuery = QString("INSERT INTO " AUTODJCRATES_TABLE " (" AUTODJCRATESTABLE_TRACKID ", " AUTODJCRATESTABLE_CRATEREFS ", " AUTODJCRATESTABLE_TIMESPLAYED ", " AUTODJCRATESTABLE_AUTODJREFS ", " AUTODJCRATESTABLE_LASTPLAYED ") SELECT " CRATE_TRACKS_TABLE ".%1 , COUNT (*), " LIBRARY_TABLE ".%2, 0, \"\" FROM " CRATE_TRACKS_TABLE ", " LIBRARY_TABLE " WHERE " CRATE_TRACKS_TABLE ".%4 IN (SELECT %5 FROM " CRATE_TABLE " WHERE %6 = 1) AND " CRATE_TRACKS_TABLE ".%1 = " LIBRARY_TABLE ".%7 AND " LIBRARY_TABLE ".%3 == 0 GROUP BY " CRATE_TRACKS_TABLE ".%1, " LIBRARY_TABLE ".%2") .arg(CRATETRACKSTABLE_TRACKID, // %1 LIBRARYTABLE_TIMESPLAYED, // %2 LIBRARYTABLE_MIXXXDELETED, // %3 CRATETRACKSTABLE_CRATEID, // %4 CRATETABLE_ID, // %5 CRATETABLE_AUTODJ_SOURCE, // %6 LIBRARYTABLE_ID); // %7 oQuery.prepare(strQuery); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return; } // Fill out the number of auto-DJ-playlist references. if (!updateAutoDjPlaylistReferences()) { return; } // Fill out the last-played date/time. if (!updateLastPlayedDateTime()) { return; } // Create the active-tracks view. //oQuery.exec ("DROP VIEW IF EXISTS " AUTODJACTIVETRACKS_TABLE); if (!createActiveTracksView (m_bUseIgnoreTime)) { return; } // Make a list of the IDs of every set-log playlist. // SELECT id FROM Playlists WHERE hidden = 2; oQuery.prepare(QString("SELECT %1 FROM " PLAYLIST_TABLE " WHERE %2 = %3") .arg(PLAYLISTTABLE_ID, // %1 PLAYLISTTABLE_HIDDEN, // %2 QString::number(PlaylistDAO::PLHT_SET_LOG))); // %3 if (oQuery.exec()) { while (oQuery.next()) m_lstSetLogPlaylistIds.append(oQuery.value(0).toInt()); } else { LOG_FAILED_QUERY(oQuery); return; } // Now the auto-DJ crates database is initialized. // Externally-driven updates to the database from now on are driven by // signals. oTransaction.commit(); // Be notified when a track is modified. // We only care when the number of times it's been played changes. connect(&m_rTrackDAO, SIGNAL(trackDirty(int)), this, SLOT(slotTrackDirty(int))); // Be notified when the status of crates changes. // We only care about the crates labeled as auto-DJ, and tracks added to, // and removed from, such crates. connect(&m_rCrateDAO, SIGNAL(added(int)), this, SLOT(slotCrateAdded(int))); connect(&m_rCrateDAO, SIGNAL(deleted(int)), this, SLOT(slotCrateDeleted(int))); connect(&m_rCrateDAO, SIGNAL(autoDjChanged(int,bool)), this, SLOT(slotCrateAutoDjChanged(int,bool))); connect(&m_rCrateDAO, SIGNAL(trackAdded(int,int)), this, SLOT(slotCrateTrackAdded(int,int))); connect(&m_rCrateDAO, SIGNAL(trackRemoved(int,int)), this, SLOT(slotCrateTrackRemoved(int,int))); // Be notified when playlists are added/removed. // We only care about set-log playlists. connect(&m_rPlaylistDAO, SIGNAL(added(int)), this, SLOT(slotPlaylistAdded(int))); connect(&m_rPlaylistDAO, SIGNAL(deleted(int)), this, SLOT(slotPlaylistDeleted(int))); // Be notified when tracks are added/removed from playlists. // We only care about the auto-DJ playlist and the set-log playlists. connect(&m_rPlaylistDAO, SIGNAL(trackAdded(int,int,int)), this, SLOT(slotPlaylistTrackAdded(int,int,int))); connect(&m_rPlaylistDAO, SIGNAL(trackRemoved(int,int,int)), this, SLOT(slotPlaylistTrackRemoved(int,int,int))); // Be notified when tracks are loaded to, or unloaded from, a deck. // These count as auto-DJ references, i.e. prevent the track from being // selected randomly. connect(&PlayerInfo::Instance(), SIGNAL(trackLoaded(QString,TrackPointer)), this, SLOT(slotPlayerInfoTrackLoaded(QString,TrackPointer))); connect(&PlayerInfo::Instance(), SIGNAL(trackUnloaded(QString,TrackPointer)), this, SLOT(slotPlayerInfoTrackUnloaded(QString,TrackPointer))); // Remember that the auto-DJ-crates database has been created. m_bAutoDjCratesDbCreated = true; }
void RateControl::trackLoaded(TrackPointer pTrack) { if (m_pTrack) { trackUnloaded(m_pTrack); } m_pTrack = pTrack; }
BaseTrackPlayer::BaseTrackPlayer(QObject* pParent, ConfigObject<ConfigValue>* pConfig, EngineMaster* pMixingEngine, EffectsManager* pEffectsManager, EngineChannel::ChannelOrientation defaultOrientation, QString group, bool defaultMaster, bool defaultHeadphones) : BasePlayer(pParent, group), m_pConfig(pConfig), m_pLoadedTrack(), m_pLowFilter(NULL), m_pMidFilter(NULL), m_pHighFilter(NULL), m_pLowFilterKill(NULL), m_pMidFilterKill(NULL), m_pHighFilterKill(NULL), m_replaygainPending(false) { m_pChannel = new EngineDeck(getGroup(), pConfig, pMixingEngine, pEffectsManager, defaultOrientation); EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer(); pMixingEngine->addChannel(m_pChannel); // Set the routing option defaults for the master and headphone mixes. { ControlObject::set(ConfigKey(getGroup(), "master"), (double)defaultMaster); ControlObject::set(ConfigKey(getGroup(), "pfl"), (double)defaultHeadphones); } // Connect our signals and slots with the EngineBuffer's signals and // slots. This will let us know when the reader is done loading a track, and // let us request that the reader load a track. connect(this, SIGNAL(loadTrack(TrackPointer, bool)), pEngineBuffer, SLOT(slotLoadTrack(TrackPointer, bool))); connect(pEngineBuffer, SIGNAL(trackLoaded(TrackPointer)), this, SLOT(slotFinishLoading(TrackPointer))); connect(pEngineBuffer, SIGNAL(trackLoadFailed(TrackPointer, QString)), this, SLOT(slotLoadFailed(TrackPointer, QString))); connect(pEngineBuffer, SIGNAL(trackUnloaded(TrackPointer)), this, SLOT(slotUnloadTrack(TrackPointer))); // Get loop point control objects m_pLoopInPoint = new ControlObjectThread( getGroup(),"loop_start_position"); m_pLoopOutPoint = new ControlObjectThread( getGroup(),"loop_end_position"); // Duration of the current song, we create this one because nothing else does. m_pDuration = new ControlObject(ConfigKey(getGroup(), "duration")); // Waveform controls m_pWaveformZoom = new ControlPotmeter(ConfigKey(group, "waveform_zoom"), WaveformWidgetRenderer::s_waveformMinZoom, WaveformWidgetRenderer::s_waveformMaxZoom); m_pWaveformZoom->set(1.0); m_pWaveformZoom->setStepCount(WaveformWidgetRenderer::s_waveformMaxZoom - WaveformWidgetRenderer::s_waveformMinZoom); m_pWaveformZoom->setSmallStepCount(WaveformWidgetRenderer::s_waveformMaxZoom - WaveformWidgetRenderer::s_waveformMinZoom); m_pEndOfTrack = new ControlObject(ConfigKey(group, "end_of_track")); m_pEndOfTrack->set(0.); m_pPreGain = new ControlObjectSlave(ConfigKey(group, "pregain")); //BPM of the current song m_pBPM = new ControlObjectThread(group, "file_bpm"); m_pKey = new ControlObjectThread(group, "file_key"); m_pReplayGain = new ControlObjectThread(group, "replaygain"); m_pPlay = new ControlObjectThread(group, "play"); connect(m_pPlay, SIGNAL(valueChanged(double)), this, SLOT(slotPlayToggled(double))); }
BaseTrackPlayer::BaseTrackPlayer(QObject* pParent, ConfigObject<ConfigValue>* pConfig, EngineMaster* pMixingEngine, EngineChannel::ChannelOrientation defaultOrientation, QString group, bool defaultMaster, bool defaultHeadphones) : BasePlayer(pParent, group), m_pConfig(pConfig), m_pLoadedTrack() { // Need to strdup the string because EngineChannel will save the pointer, // but we might get deleted before the EngineChannel. TODO(XXX) // pSafeGroupName is leaked. It's like 5 bytes so whatever. const char* pSafeGroupName = strdup(getGroup().toAscii().constData()); m_pChannel = new EngineDeck(pSafeGroupName, pConfig, defaultOrientation); EngineBuffer* pEngineBuffer = m_pChannel->getEngineBuffer(); pMixingEngine->addChannel(m_pChannel); // Set the routing option defaults for the master and headphone mixes. { ControlObjectThreadMain* pMaster = new ControlObjectThreadMain( getGroup(), "master"); pMaster->slotSet(defaultMaster); delete pMaster; ControlObjectThreadMain* pHeadphones = new ControlObjectThreadMain( getGroup(), "pfl"); pHeadphones->slotSet(defaultHeadphones); delete pHeadphones; } // Connect our signals and slots with the EngineBuffer's signals and // slots. This will let us know when the reader is done loading a track, and // let us request that the reader load a track. connect(this, SIGNAL(loadTrack(TrackPointer, bool)), pEngineBuffer, SLOT(slotLoadTrack(TrackPointer, bool))); connect(pEngineBuffer, SIGNAL(trackLoaded(TrackPointer)), this, SLOT(slotFinishLoading(TrackPointer))); connect(pEngineBuffer, SIGNAL(trackLoadFailed(TrackPointer, QString)), this, SLOT(slotLoadFailed(TrackPointer, QString))); connect(pEngineBuffer, SIGNAL(trackUnloaded(TrackPointer)), this, SLOT(slotUnloadTrack(TrackPointer))); //Get cue point control object m_pCuePoint = new ControlObjectThreadMain( getGroup(),"cue_point"); // Get loop point control objects m_pLoopInPoint = new ControlObjectThreadMain( getGroup(),"loop_start_position"); m_pLoopOutPoint = new ControlObjectThreadMain( getGroup(),"loop_end_position"); //Playback position within the currently loaded track (in this player). m_pPlayPosition = new ControlObjectThreadMain( getGroup(), "playposition"); // Duration of the current song, we create this one because nothing else does. m_pDuration = new ControlObject(ConfigKey(getGroup(), "duration")); // Waveform controls m_pWaveformZoom = new ControlPotmeter(ConfigKey(group, "waveform_zoom"), WaveformWidgetRenderer::s_waveformMinZoom, WaveformWidgetRenderer::s_waveformMaxZoom); m_pWaveformZoom->set(1.0); m_pWaveformZoom->setStep(1.0); m_pWaveformZoom->setSmallStep(1.0); m_pEndOfTrack = new ControlObject(ConfigKey(group, "end_of_track")); m_pEndOfTrack->set(0.); //BPM of the current song m_pBPM = new ControlObjectThreadMain(group, "file_bpm"); m_pReplayGain = new ControlObjectThreadMain(group, "replaygain"); m_pPlay = new ControlObjectThreadMain(group, "play"); }