예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
// 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;
        }
    }
}
예제 #5
0
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();
}
예제 #6
0
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";
}
예제 #7
0
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();
}
예제 #8
0
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);
    }
}
예제 #9
0
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;
}
예제 #10
0
// 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;
}
예제 #11
0
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);
        }
    }
}
예제 #12
0
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;
}
예제 #13
0
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();
    }
예제 #14
0
// 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);
        }
    }
}
예제 #15
0
// 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;
        }
    }
}
예제 #16
0
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;
}
예제 #17
0
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;
        }
    }
}