bool EngineShoutcast::metaDataHasChanged() { TrackPointer pTrack; if (m_iMetaDataLife < 16) { m_iMetaDataLife++; return false; } m_iMetaDataLife = 0; pTrack = PlayerInfo::Instance().getCurrentPlayingTrack(); if (!pTrack) return false; if (m_pMetaData) { if ((pTrack->getId() == -1) || (m_pMetaData->getId() == -1)) { if ((pTrack->getArtist() == m_pMetaData->getArtist()) && (pTrack->getTitle() == m_pMetaData->getArtist())) { return false; } } else if (pTrack->getId() == m_pMetaData->getId()) { return false; } } m_pMetaData = pTrack; return true; }
bool EngineRecord::metaDataHasChanged() { if (m_iMetaDataLife < kMetaDataLifeTimeout) { m_iMetaDataLife++; return false; } m_iMetaDataLife = 0; TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); if ( !pTrack ) return false; if ( m_pCurrentTrack ) { if ((pTrack->getId() == -1) || (m_pCurrentTrack->getId() == -1)) { if ((pTrack->getArtist() == m_pCurrentTrack->getArtist()) && (pTrack->getTitle() == m_pCurrentTrack->getArtist())) { return false; } } else if (pTrack->getId() == m_pCurrentTrack->getId()) { return false; } } m_pCurrentTrack = pTrack; return true; }
bool EngineShoutcast::metaDataHasChanged() { TrackPointer pTrack; // TODO(rryan): This is latency and buffer size dependent. Should be based // on time. if (m_iMetaDataLife < 16) { m_iMetaDataLife++; return false; } m_iMetaDataLife = 0; pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); if (!pTrack) return false; if (m_pMetaData) { if ((pTrack->getId() == -1) || (m_pMetaData->getId() == -1)) { if ((pTrack->getArtist() == m_pMetaData->getArtist()) && (pTrack->getTitle() == m_pMetaData->getArtist())) { return false; } } else if (pTrack->getId() == m_pMetaData->getId()) { return false; } } m_pMetaData = pTrack; return true; }
// Signaled by the PlayerInfo singleton when a track is loaded to a deck. void AutoDJCratesDAO::slotPlayerInfoTrackLoaded(QString a_strGroup, TrackPointer a_pTrack) { // This gets called with a null track during an unload. Filter that out. if (a_pTrack == NULL) { return; } // This counts as an auto-DJ reference. The idea is to prevent tracks that // are loaded into a deck from being randomly chosen. int iTrackId = a_pTrack->getId(); unsigned int numDecks = PlayerManager::numDecks(); for (unsigned int i = 0; i < numDecks; ++i) { if (a_strGroup == PlayerManager::groupForDeck(i)) { // Update the number of auto-DJ-playlist references to this track. QSqlQuery oQuery(m_rDatabase); // UPDATE temp_autodj_crates SET autodjrefs = autodjrefs + 1 WHERE track_id = :track_id; oQuery.prepare("UPDATE " AUTODJCRATES_TABLE " SET " AUTODJCRATESTABLE_AUTODJREFS " = " AUTODJCRATESTABLE_AUTODJREFS " + 1 WHERE " AUTODJCRATESTABLE_TRACKID " = :track_id"); oQuery.bindValue(":track_id", iTrackId); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return; } return; } } }
void CrateFeature::slotTrackSelected(TrackPointer pTrack) { m_pSelectedTrack = pTrack; TrackId trackId(pTrack.isNull() ? TrackId() : pTrack->getId()); m_crateDao.getCratesTrackIsIn(trackId, &m_cratesSelectedTrackIsIn); TreeItem* rootItem = m_childModel.getItem(QModelIndex()); if (rootItem == nullptr) { return; } // Set all crates the track is in bold (or if there is no track selected, // clear all the bolding). int row = 0; for (QList<QPair<int, QString> >::const_iterator it = m_crateList.begin(); it != m_crateList.end(); ++it, ++row) { TreeItem* crate = rootItem->child(row); if (crate == nullptr) { continue; } int crateId = it->first; bool shouldBold = m_cratesSelectedTrackIsIn.contains(crateId); crate->setBold(shouldBold); } m_childModel.triggerRepaint(); }
void AnalyzerWaveform::finalize(TrackPointer tio) { if (m_skipProcessing) { return; } // Force completion to waveform size if (m_waveform) { m_waveform->setCompletion(m_waveform->getDataSize()); m_waveform->setVersion(WaveformFactory::currentWaveformVersion()); m_waveform->setDescription(WaveformFactory::currentWaveformDescription()); // Since clear() could delete the waveform, clear our pointer to the // waveform's vector data first. m_waveformData = nullptr; m_waveform.clear(); } // Force completion to waveform size if (m_waveformSummary) { m_waveformSummary->setCompletion(m_waveformSummary->getDataSize()); m_waveformSummary->setVersion(WaveformFactory::currentWaveformSummaryVersion()); m_waveformSummary->setDescription(WaveformFactory::currentWaveformSummaryDescription()); // Since clear() could delete the waveform, clear our pointer to the // waveform's vector data first. m_waveformSummaryData = nullptr; m_waveformSummary.clear(); } #ifdef TEST_HEAT_MAP test_heatMap->save("heatMap.png"); #endif qDebug() << "Waveform generation for track" << tio->getId() << "done" << m_timer.elapsed()/1000.0 << "s"; }
void AnalyzerWaveform::finalize(TrackPointer tio) { if (m_skipProcessing) { return; } // Force completion to waveform size if (m_waveform) { m_waveform->setSaveState(Waveform::SaveState::SavePending); m_waveform->setCompletion(m_waveform->getDataSize()); m_waveform->setVersion(WaveformFactory::currentWaveformVersion()); m_waveform->setDescription(WaveformFactory::currentWaveformDescription()); // Since clear() could delete the waveform, clear our pointer to the // waveform's vector data first. m_waveformData = nullptr; m_waveform.clear(); } // Force completion to waveform size if (m_waveformSummary) { m_waveformSummary->setSaveState(Waveform::SaveState::SavePending); m_waveformSummary->setCompletion(m_waveformSummary->getDataSize()); m_waveformSummary->setVersion(WaveformFactory::currentWaveformSummaryVersion()); m_waveformSummary->setDescription(WaveformFactory::currentWaveformSummaryDescription()); // Since clear() could delete the waveform, clear our pointer to the // waveform's vector data first. m_waveformSummaryData = nullptr; m_waveformSummary.clear(); } #ifdef TEST_HEAT_MAP test_heatMap->save("heatMap.png"); #endif // Ensure that the analyses get saved. This is also called from // TrackDAO.updateTrack(), but it can happen that we analyze only the // waveforms (i.e. if the config setting was disabled in a previous scan) // and then it is not called. The other analyzers have signals which control // the update of their data. m_pAnalysisDao->saveTrackAnalyses( tio->getId(), tio->getWaveform(), tio->getWaveformSummary()); kLogger.debug() << "Waveform generation for track" << tio->getId() << "done" << m_timer.elapsed().debugSecondsWithUnit(); }
void SetlogFeature::slotPlayingTrackChanged(TrackPointer currentPlayingTrack) { if (!currentPlayingTrack) { return; } TrackId currentPlayingTrackId(currentPlayingTrack->getId()); bool track_played_recently = false; if (currentPlayingTrackId.isValid()) { // Remove the track from the recent tracks list if it's present and put // at the front of the list. track_played_recently = m_recentTracks.removeOne(currentPlayingTrackId); m_recentTracks.push_front(currentPlayingTrackId); // Keep a window of 6 tracks (inspired by 2 decks, 4 samplers) const int kRecentTrackWindow = 6; while (m_recentTracks.size() > kRecentTrackWindow) { m_recentTracks.pop_back(); } } // If the track was recently played, don't increment the playcount or // add it to the history. if (track_played_recently) { return; } // If the track is not present in the recent tracks list, mark it // played and update its playcount. currentPlayingTrack->updatePlayCounter(); // We can only add tracks that are Mixxx library tracks, not external // sources. if (!currentPlayingTrackId.isValid()) { return; } if (m_pPlaylistTableModel->getPlaylist() == m_playlistId) { // View needs a refresh WTrackTableView* view = dynamic_cast<WTrackTableView*>(m_libraryWidget->getActiveView()); if (view != nullptr) { // We have a active view on the history. The user may have some // important active selection. For example putting track into crates // while the song changes trough autodj. The selection is then lost // and dataloss occurs const QList<TrackId> trackIds = view->getSelectedTrackIds(); m_pPlaylistTableModel->appendTrack(currentPlayingTrackId); view->setSelectedTracks(trackIds); } else { m_pPlaylistTableModel->appendTrack(currentPlayingTrackId); } } else { // TODO(XXX): Care whether the append succeeded. m_playlistDao.appendTrackToPlaylist(currentPlayingTrackId, m_playlistId); } }
bool AnalyzerWaveform::isDisabledOrLoadStoredSuccess(TrackPointer tio) const { ConstWaveformPointer pTrackWaveform = tio->getWaveform(); ConstWaveformPointer pTrackWaveformSummary = tio->getWaveformSummary(); ConstWaveformPointer pLoadedTrackWaveform; ConstWaveformPointer pLoadedTrackWaveformSummary; TrackId trackId = tio->getId(); bool missingWaveform = pTrackWaveform.isNull(); bool missingWavesummary = pTrackWaveformSummary.isNull(); if (trackId.isValid() && (missingWaveform || missingWavesummary)) { QList<AnalysisDao::AnalysisInfo> analyses = m_pAnalysisDao->getAnalysesForTrack(trackId); QListIterator<AnalysisDao::AnalysisInfo> it(analyses); while (it.hasNext()) { const AnalysisDao::AnalysisInfo& analysis = it.next(); WaveformFactory::VersionClass vc; if (analysis.type == AnalysisDao::TYPE_WAVEFORM) { vc = WaveformFactory::waveformVersionToVersionClass(analysis.version); if (missingWaveform && vc == WaveformFactory::VC_USE) { pLoadedTrackWaveform = ConstWaveformPointer( WaveformFactory::loadWaveformFromAnalysis(analysis)); missingWaveform = false; } else if (vc != WaveformFactory::VC_KEEP) { // remove all other Analysis except that one we should keep m_pAnalysisDao->deleteAnalysis(analysis.analysisId); } } if (analysis.type == AnalysisDao::TYPE_WAVESUMMARY) { vc = WaveformFactory::waveformSummaryVersionToVersionClass(analysis.version); if (missingWavesummary && vc == WaveformFactory::VC_USE) { pLoadedTrackWaveformSummary = ConstWaveformPointer( WaveformFactory::loadWaveformFromAnalysis(analysis)); missingWavesummary = false; } else if (vc != WaveformFactory::VC_KEEP) { // remove all other Analysis except that one we should keep m_pAnalysisDao->deleteAnalysis(analysis.analysisId); } } } } // If we don't need to calculate the waveform/wavesummary, skip. if (!missingWaveform && !missingWavesummary) { kLogger.debug() << "loadStored - Stored waveform loaded"; if (pLoadedTrackWaveform) { tio->setWaveform(pLoadedTrackWaveform); } if (pLoadedTrackWaveformSummary) { tio->setWaveformSummary(pLoadedTrackWaveformSummary); } return true; } return false; }
// Update the number of auto-DJ-playlist references to each track in the // auto-DJ-crates database. bool AutoDJCratesDAO::updateAutoDjPlaylistReferences() { QSqlQuery oQuery(m_rDatabase); // Rebuild the auto-DJ-playlist reference count. // INSERT OR REPLACE INTO temp_autodj_crates (track_id, craterefs, timesplayed, autodjrefs) SELECT * FROM (SELECT PlaylistTracks.track_id, craterefs, timesplayed, COUNT (*) AS newautodjrefs FROM PlaylistTracks, temp_autodj_crates WHERE PlaylistTracks.playlist_id IN (SELECT id FROM Playlists WHERE hidden = 1) AND PlaylistTracks.track_id = temp_autodj_crates.track_id GROUP BY PlaylistTracks.track_id) WHERE newautodjrefs > 0; QString strHidden; strHidden.setNum(PlaylistDAO::PLHT_AUTO_DJ); QString strQuery(QString ("INSERT OR REPLACE INTO " AUTODJCRATES_TABLE " (" AUTODJCRATESTABLE_TRACKID ", " AUTODJCRATESTABLE_CRATEREFS ", " AUTODJCRATESTABLE_TIMESPLAYED ", " AUTODJCRATESTABLE_AUTODJREFS ")" " SELECT * FROM (SELECT " PLAYLIST_TRACKS_TABLE ".%1, " AUTODJCRATESTABLE_CRATEREFS ", " AUTODJCRATESTABLE_TIMESPLAYED ", COUNT (*) AS new" AUTODJCRATESTABLE_AUTODJREFS " FROM " PLAYLIST_TRACKS_TABLE ", " AUTODJCRATES_TABLE " WHERE " PLAYLIST_TRACKS_TABLE ".%2 IN (SELECT %3 FROM " PLAYLIST_TABLE " WHERE %4 = %5) AND " PLAYLIST_TRACKS_TABLE ".%1 = " AUTODJCRATES_TABLE "." AUTODJCRATESTABLE_TRACKID " GROUP BY " PLAYLIST_TRACKS_TABLE ".%1) WHERE new" AUTODJCRATESTABLE_AUTODJREFS " > 0") .arg(PLAYLISTTRACKSTABLE_TRACKID, // %1 PLAYLISTTRACKSTABLE_PLAYLISTID, // %2 PLAYLISTTABLE_ID, // %3 PLAYLISTTABLE_HIDDEN, // %4 strHidden)); // %5 oQuery.prepare(strQuery); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return false; } // Incorporate all tracks loaded into decks. // Each track has to be done as a separate database query, in case the same // track is loaded into multiple decks. int iDecks = (int) PlayerManager::numDecks(); for (int i = 0; i < iDecks; ++i) { QString group = PlayerManager::groupForDeck(i); TrackPointer pTrack = PlayerInfo::Instance().getTrackInfo(group); if (pTrack) { int iTrackId = pTrack->getId(); // UPDATE temp_autodj_crates SET autodjrefs = autodjrefs + 1 WHERE track_id IN (:track_id); oQuery.prepare("UPDATE " AUTODJCRATES_TABLE " SET " AUTODJCRATESTABLE_AUTODJREFS " = " AUTODJCRATESTABLE_AUTODJREFS " + 1 WHERE " AUTODJCRATESTABLE_TRACKID " IN (:track_id)"); oQuery.bindValue(":track_id", iTrackId); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return false; } } } return true; }
void SetlogFeature::slotPlayingDeckChanged(int deck) { if (deck > -1) { QString chan = PlayerManager::groupForDeck(deck); TrackPointer currentPlayingTrack = PlayerInfo::instance().getTrackInfo(chan); if (!currentPlayingTrack) { return; } int currentPlayingTrackId = currentPlayingTrack->getId(); bool track_played_recently = false; if (currentPlayingTrackId >= 0) { // Remove the track from the recent tracks list if it's present and put // at the front of the list. track_played_recently = m_recentTracks.removeOne(currentPlayingTrackId); m_recentTracks.push_front(currentPlayingTrackId); // Keep a window of 6 tracks (inspired by 2 decks, 4 samplers) const int kRecentTrackWindow = 6; while (m_recentTracks.size() > kRecentTrackWindow) { m_recentTracks.pop_back(); } } // If the track was recently played, don't increment the playcount or // add it to the history. if (track_played_recently) { return; } // If the track is not present in the recent tracks list, mark it // played and update its playcount. currentPlayingTrack->setPlayedAndUpdatePlaycount(true); // We can only add tracks that are Mixxx library tracks, not external // sources. if (currentPlayingTrackId < 0) { return; } if (m_pPlaylistTableModel->getPlaylist() == m_playlistId) { // View needs a refresh m_pPlaylistTableModel->appendTrack(currentPlayingTrackId); } else { // TODO(XXX): Care whether the append succeeded. m_playlistDao.appendTrackToPlaylist(currentPlayingTrackId, m_playlistId); } } }
bool EngineRecord::metaDataHasChanged() { //Originally, m_iMetaDataLife was used so that getCurrentPlayingTrack was called //less often, because it was calculating it. //Nowadays (since Mixxx 1.11), it just accesses a map on a thread safe method. TrackPointer pTrack = PlayerInfo::instance().getCurrentPlayingTrack(); if (!pTrack) { m_iMetaDataLife = kMetaDataLifeTimeout; return false; } //The counter is kept so that changes back and forth with the faders/crossfader //(like in scratching or other effects) are not counted as multiple track changes //in the cue file. A better solution could consist of a signal from PlayerInfo and //a slot that decides if the changes received are valid or are to be ignored once //the next process call comes. This could also help improve the time written in the CUE. if (m_iMetaDataLife < kMetaDataLifeTimeout) { m_iMetaDataLife++; return false; } m_iMetaDataLife = 0; if (m_pCurrentTrack) { if (!pTrack->getId().isValid() || !m_pCurrentTrack->getId().isValid()) { if ((pTrack->getArtist() == m_pCurrentTrack->getArtist()) && (pTrack->getTitle() == m_pCurrentTrack->getArtist())) { return false; } } else if (pTrack->getId() == m_pCurrentTrack->getId()) { return false; } } m_pCurrentTrack = pTrack; return true; }
void BaseSqlTableModel::trackLoaded(QString group, TrackPointer pTrack) { if (group == m_previewDeckGroup) { // If there was a previously loaded track, refresh its rows so the // preview state will update. if (m_previewDeckTrackId.isValid()) { const int numColumns = columnCount(); QLinkedList<int> rows = getTrackRows(m_previewDeckTrackId); m_previewDeckTrackId = TrackId(); // invalidate foreach (int row, rows) { QModelIndex left = index(row, 0); QModelIndex right = index(row, numColumns); emit(dataChanged(left, right)); } } m_previewDeckTrackId = pTrack ? pTrack->getId() : TrackId(); }
// This is a common function for all external Librarys copied to Mixxx DB void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex(QList<int>* trackIds, QString* pPlaylist) { if (!m_lastRightClickedIndex.isValid()) { return; } // Qt::UserRole asks TreeItemModel for the TreeItem's dataPath. We need to // use the dataPath because models with nested playlists need to use the // full path/name of the playlist. *pPlaylist = m_lastRightClickedIndex.data(Qt::UserRole).toString(); QScopedPointer<BaseSqlTableModel> pPlaylistModelToAdd( getPlaylistModelForPlaylist(*pPlaylist)); if (!pPlaylistModelToAdd || !pPlaylistModelToAdd->initialized()) { qDebug() << "BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex " "could not initialize a playlist model for playlist:" << *pPlaylist; return; } pPlaylistModelToAdd->setSort(pPlaylistModelToAdd->fieldIndex( ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder); pPlaylistModelToAdd->select(); // Copy Tracks int rows = pPlaylistModelToAdd->rowCount(); for (int i = 0; i < rows; ++i) { QModelIndex index = pPlaylistModelToAdd->index(i,0); if (index.isValid()) { qDebug() << pPlaylistModelToAdd->getTrackLocation(index); TrackPointer track = pPlaylistModelToAdd->getTrack(index); if (!track) { continue; } int trackId = track->getId(); if (trackId == -1) { continue; } trackIds->append(trackId); } } }
// Signaled by the PlayerInfo singleton when a track is unloaded from a deck. void AutoDJCratesDAO::slotPlayerInfoTrackUnloaded(QString group, TrackPointer pTrack) { // This counts as an auto-DJ reference. The idea is to prevent tracks that // are loaded into a deck from being randomly chosen. int iTrackId = pTrack->getId(); unsigned int numDecks = PlayerManager::numDecks(); for (unsigned int i = 0; i < numDecks; ++i) { if (group == PlayerManager::groupForDeck(i)) { // Get rid of the ID of the track in this deck. QSqlQuery oQuery(m_rDatabase); // UPDATE temp_autodj_crates SET autodjrefs = autodjrefs - 1 WHERE track_id = :track_id; oQuery.prepare("UPDATE " AUTODJCRATES_TABLE " SET " AUTODJCRATESTABLE_AUTODJREFS " = " AUTODJCRATESTABLE_AUTODJREFS " - 1 WHERE " AUTODJCRATESTABLE_TRACKID " = :track_id"); oQuery.bindValue(":track_id", iTrackId); if (!oQuery.exec()) { LOG_FAILED_QUERY(oQuery); return; } return; } } }
bool BaseTrackCache::updateIndexWithTrackpointer(TrackPointer pTrack) { if (sDebug) { qDebug() << "updateIndexWithTrackpointer:" << pTrack->getLocation(); } if (!pTrack) { return false; } int numColumns = columnCount(); TrackId trackId(pTrack->getId()); if (trackId.isValid()) { // m_trackInfo[id] will insert a QVector<QVariant> into the // m_trackInfo HashTable with the key "id" QVector<QVariant>& record = m_trackInfo[trackId]; // prealocate memory for all columns at once record.resize(numColumns); for (int i = 0; i < numColumns; ++i) { getTrackValueForColumn(pTrack, i, record[i]); } } return true; }
void BansheeFeature::appendTrackIdsFromRightClickIndex(QList<TrackId>* trackIds, QString* pPlaylist) { if (m_lastRightClickedIndex.isValid()) { TreeItem *item = static_cast<TreeItem*>(m_lastRightClickedIndex.internalPointer()); *pPlaylist = item->getLabel(); int playlistID = item->getData().toInt(); qDebug() << "BansheeFeature::appendTrackIdsFromRightClickIndex " << *pPlaylist << " " << playlistID; if (playlistID > 0) { BansheePlaylistModel* pPlaylistModelToAdd = new BansheePlaylistModel(this, m_pTrackCollection, &m_connection); pPlaylistModelToAdd->setTableModel(playlistID); // Copy Tracks int rows = pPlaylistModelToAdd->rowCount(); for (int i = 0; i < rows; ++i) { QModelIndex index = pPlaylistModelToAdd->index(i,0); if (index.isValid()) { //qDebug() << pPlaylistModelToAdd->getTrackLocation(index); TrackPointer track = pPlaylistModelToAdd->getTrack(index); trackIds->append(track->getId()); } } delete pPlaylistModelToAdd; } } }