TrackPointer BaseExternalPlaylistModel::getTrack(const QModelIndex& index) const {
    QString location = index.sibling(
            index.row(), fieldIndex("location")).data().toString();

    if (location.isEmpty()) {
        // Track is lost
        return TrackPointer();
    }

    TrackDAO& track_dao = m_pTrackCollection->getTrackDAO();
    int track_id = track_dao.getTrackId(location);
    bool track_already_in_library = track_id >= 0;
    if (track_id < 0) {
        // Add Track to library
        track_id = track_dao.addTrack(location, true);
    }

    TrackPointer pTrack;
    if (track_id < 0) {
        // Add Track to library failed, create a transient TrackInfoObject
        pTrack = TrackPointer(new TrackInfoObject(location), &QObject::deleteLater);
    } else {
        pTrack = track_dao.getTrack(track_id);
    }

    // If this track was not in the Mixxx library it is now added and will be
    // saved with the metadata from iTunes. If it was already in the library
    // then we do not touch it so that we do not over-write the user's metadata.
    if (!track_already_in_library) {
        QString artist = index.sibling(
                index.row(), fieldIndex("artist")).data().toString();
        pTrack->setArtist(artist);

        QString title = index.sibling(
                index.row(), fieldIndex("title")).data().toString();
        pTrack->setTitle(title);

        QString album = index.sibling(
                index.row(), fieldIndex("album")).data().toString();
        pTrack->setAlbum(album);

        QString year = index.sibling(
                index.row(), fieldIndex("year")).data().toString();
        pTrack->setYear(year);

        QString genre = index.sibling(
                index.row(), fieldIndex("genre")).data().toString();
        pTrack->setGenre(genre);

        float bpm = index.sibling(
                index.row(), fieldIndex("bpm")).data().toString().toFloat();
        pTrack->setBpm(bpm);
    }
    return pTrack;
}
Example #2
0
void CachingReader::run() {
    TrackPointer pLoadTrack;

    m_newTrackMutex.lock();
    if (m_newTrack) {
        pLoadTrack = m_newTrack;
        m_newTrack = TrackPointer();
    }
    m_newTrackMutex.unlock();

    if (pLoadTrack) {
        loadTrack(pLoadTrack);
    } else {
        // Read the requested chunks.
        ChunkReadRequest request;
        ReaderStatusUpdate status;
        while (m_chunkReadRequestFIFO.read(&request, 1) == 1) {
            processChunkReadRequest(&request, &status);
            m_readerStatusFIFO.writeBlocking(&status, 1);
        }
    }

    // Notify the EngineWorkerScheduler that the work we did is done.
    setActive(false);
}
Example #3
0
TrackPointer GlobalTrackCache::revive(
        GlobalTrackCacheEntryPointer entryPtr) {

    TrackPointer savingPtr = entryPtr->getSavingWeakPtr().lock();
    if (savingPtr) {
        if (traceLogEnabled()) {
            kLogger.trace()
                    << "Found alive track"
                    << entryPtr->getPlainPtr();
        }
        return savingPtr;
    }

    // We are here if another thread is preempted during the
    // destructor of the last savingPtr referencing this
    // track, after the reference counter drops to zero and
    // before locking the cache. We need to revive it to abort
    // the deleter in the other thread.
    if (debugLogEnabled()) {
        kLogger.debug()
                << "Reviving zombie track"
                << entryPtr->getPlainPtr();
    }
    DEBUG_ASSERT(entryPtr->getSavingWeakPtr().expired());

    savingPtr = TrackPointer(entryPtr->getPlainPtr(),
            EvictAndSaveFunctor(entryPtr));
    entryPtr->setSavingWeakPtr(savingPtr);
    return savingPtr;
}
Example #4
0
TrackPointer GlobalTrackCache::lookupByRef(
        const TrackRef& trackRef) {
    if (trackRef.hasId()) {
        return lookupById(trackRef.getId());
    } else {
        const auto canonicalLocation = trackRef.getCanonicalLocation();
        const auto trackByCanonicalLocation(
                m_tracksByCanonicalLocation.find(canonicalLocation));
        if (m_tracksByCanonicalLocation.end() != trackByCanonicalLocation) {
            // Cache hit
            if (traceLogEnabled()) {
                kLogger.trace()
                        << "Cache hit for"
                        << canonicalLocation
                        << trackByCanonicalLocation->second->getPlainPtr();
            }
            return revive(trackByCanonicalLocation->second);
        } else {
            // Cache miss
            if (traceLogEnabled()) {
                kLogger.trace()
                        << "Cache miss for"
                        << canonicalLocation;
            }
            return TrackPointer();
        }
    }
}
void CachingReaderWorker::run() {
    unsigned static id = 0; //the id of this thread, for debugging purposes
    QThread::currentThread()->setObjectName(QString("CachingReaderWorker %1").arg(++id));

    CachingReaderChunkReadRequest request;

    Event::start(m_tag);
    while (!load_atomic(m_stop)) {
        if (m_newTrack) {
            TrackPointer pLoadTrack;
            { // locking scope
                QMutexLocker locker(&m_newTrackMutex);
                pLoadTrack = m_newTrack;
                m_newTrack = TrackPointer();
            } // implicitly unlocks the mutex
            loadTrack(pLoadTrack);
        } else if (m_pChunkReadRequestFIFO->read(&request, 1) == 1) {
            // Read the requested chunk and send the result
            const ReaderStatusUpdate update(processReadRequest(request));
            m_pReaderStatusFIFO->writeBlocking(&update, 1);
        } else {
            Event::end(m_tag);
            m_semaRun.acquire();
            Event::start(m_tag);
        }
    }
}
Example #6
0
void EngineRecord::process(const CSAMPLE* pBuffer, const int iBufferSize) {
    // if recording is disabled
    if (m_recReady->get() == RECORD_OFF) {
        //qDebug("Setting record flag to: OFF");
        if (fileOpen()) {
            closeFile();    //close file and free encoder
            emit(isRecording(false));
        }
    }

    // if we are ready for recording, i.e, the output file has been selected, we
    // open a new file
    if (m_recReady->get() == RECORD_READY) {
        updateFromPreferences();	//update file location from pref
        if (openFile()) {
            qDebug("Setting record flag to: ON");
            m_recReady->slotSet(RECORD_ON);
            emit(isRecording(true)); //will notify the RecordingManager

            // Since we just started recording, timeout and clear the metadata.
            m_iMetaDataLife = kMetaDataLifeTimeout;
            m_pCurrentTrack = TrackPointer();

            if (m_bCueIsEnabled) {
                openCueFile();
                m_cuesamplepos = 0;
                m_cuetrack = 0;
            }
        } else { // Maybe the encoder could not be initialized
            qDebug("Setting record flag to: OFF");
            m_recReady->slotSet(RECORD_OFF);
            emit(isRecording(false));
        }
    }

    // If recording is enabled process audio to compressed or uncompressed data.
    if (m_recReady->get() == RECORD_ON) {
        if (m_Encoding == ENCODING_WAVE || m_Encoding == ENCODING_AIFF) {
            if (m_sndfile != NULL) {
                sf_write_float(m_sndfile, pBuffer, iBufferSize);
                emit(bytesRecorded(iBufferSize));
            }
        } else {
            if (m_encoder) {
                // Compress audio. Encoder will call method 'write()' below to
                // write a file stream
                m_encoder->encodeBuffer(pBuffer, iBufferSize);
            }
        }

        if (m_bCueIsEnabled) {
            if (metaDataHasChanged()) {
                m_cuetrack++;
                writeCueLine();
                m_cuefile.flush();
            }
            m_cuesamplepos += iBufferSize;
        }
  	}
}
Example #7
0
EncoderFfmpegCore::EncoderFfmpegCore(EncoderCallback* pCallback, CodecID codec)
#endif
{
    m_bStreamInitialized = false;
    m_pCallback = pCallback;
    m_strMetaDataTitle = NULL;
    m_strMetaDataArtist = NULL;
    m_strMetaDataAlbum = NULL;
    m_pMetaData = TrackPointer(NULL);

    m_pEncodeFormatCtx = NULL;
    m_pEncoderAudioStream = NULL;
    m_pEncoderAudioCodec = NULL;
    m_pEncoderFormat = NULL;


    m_pSamples = NULL;
    m_pFltSamples = NULL;
    m_iAudioInputFrameSize = -1;

    memset(m_SBuffer, 0x00, (65355 * 2));
    m_lBufferSize = 0;
    m_iAudioCpyLen = 0;
    m_iFltAudioCpyLen = 0;

    m_SCcodecId = codec;
    m_lBitrate = 128000;
    m_lDts = 0;
    m_lPts = 0;
    m_lRecordedBytes = 0;

}
Example #8
0
TrackPointer PlayerInfo::getCurrentPlayingTrack() {
    int deck = getCurrentPlayingDeck();
    if (deck >= 0) {
        return getTrackInfo(PlayerManager::groupForDeck(deck));
    }
    return TrackPointer();
}
TrackPointer BaseExternalTrackModel::getTrack(const QModelIndex& index) const {
    QString artist = index.sibling(index.row(), fieldIndex("artist")).data().toString();
    QString title = index.sibling(index.row(), fieldIndex("title")).data().toString();
    QString album = index.sibling(index.row(), fieldIndex("album")).data().toString();
    QString year = index.sibling(index.row(), fieldIndex("year")).data().toString();
    QString genre = index.sibling(index.row(), fieldIndex("genre")).data().toString();
    float bpm = index.sibling(index.row(), fieldIndex("bpm")).data().toString().toFloat();

    QString location = index.sibling(index.row(), fieldIndex("location")).data().toString();

    if (location.isEmpty()) {
        // Track is lost
        return TrackPointer();
    }

    bool track_already_in_library = false;
    TrackPointer pTrack = m_pTrackCollection->getTrackDAO()
            .getOrAddTrack(location, true, &track_already_in_library);

    // If this track was not in the Mixxx library it is now added and will be
    // saved with the metadata from iTunes. If it was already in the library
    // then we do not touch it so that we do not over-write the user's metadata.
    if (pTrack && !track_already_in_library) {
        pTrack->setArtist(artist);
        pTrack->setTitle(title);
        pTrack->setAlbum(album);
        pTrack->setYear(year);
        pTrack->setGenre(genre);
        pTrack->setBpm(bpm);
    }
    return pTrack;
}
void CachingReaderWorker::run() {
    unsigned static id = 0; //the id of this thread, for debugging purposes
    QThread::currentThread()->setObjectName(QString("CachingReaderWorker %1").arg(++id));

    TrackPointer pLoadTrack;
    ChunkReadRequest request;
    ReaderStatusUpdate status;

    Event::start(m_tag);
    while (!load_atomic(m_stop)) {
        if (m_newTrack) {
            m_newTrackMutex.lock();
            pLoadTrack = m_newTrack;
            m_newTrack = TrackPointer();
            m_newTrackMutex.unlock();
            loadTrack(pLoadTrack);
        } else if (m_pChunkReadRequestFIFO->read(&request, 1) == 1) {
            // Read the requested chunks.
            processChunkReadRequest(&request, &status);
            m_pReaderStatusFIFO->writeBlocking(&status, 1);
        } else {
            Event::end(m_tag);
            m_semaRun.acquire();
            Event::start(m_tag);
        }
    }
}
Example #11
0
TrackPointer BaseTrackCache::lookupCachedTrack(TrackId trackId) const {
    // Only get the track from the TrackDAO if it's in the cache and marked as
    // dirty.
    if (m_bIsCaching && m_dirtyTracks.contains(trackId)) {
        return m_trackDAO.getTrack(trackId, true);
    }
    return TrackPointer();
}
Example #12
0
TrackPointer PlayerInfo::getTrackInfo(const QString& group) {
    QMutexLocker locker(&m_mutex);

    if (m_loadedTrackMap.contains(group)) {
        return m_loadedTrackMap[group];
    }

    return TrackPointer();
}
Example #13
0
//static
TrackPointer Track::newTemporary(
        const QFileInfo& fileInfo,
        const SecurityTokenPointer& pSecurityToken) {
    Track* pTrack =
            new Track(
                    fileInfo,
                    pSecurityToken,
                    TrackId());
    return TrackPointer(pTrack);
}
Example #14
0
//static
TrackPointer TrackInfoObject::newTemporary(
        const QFileInfo& fileInfo,
        const SecurityTokenPointer& pSecurityToken) {
    return TrackPointer(
            new TrackInfoObject(
                    fileInfo,
                    pSecurityToken,
                    TrackId()),
            &QObject::deleteLater);
}
Example #15
0
//static
TrackPointer TrackInfoObject::newDummy(
        const QFileInfo& fileInfo,
        TrackId trackId) {
    return TrackPointer(
            new TrackInfoObject(
                    fileInfo,
                    SecurityTokenPointer(),
                    trackId),
            &QObject::deleteLater);
}
Example #16
0
//static
TrackPointer Track::newDummy(
        const QFileInfo& fileInfo,
        TrackId trackId) {
    Track* pTrack =
            new Track(
                    fileInfo,
                    SecurityTokenPointer(),
                    trackId);
    return TrackPointer(pTrack);
}
Example #17
0
TrackPointer BrowseTableModel::getTrack(const QModelIndex& index) const {
    QString track_location = getTrackLocation(index);
    if (m_pRecordingManager->getRecordingLocation() == track_location) {
        QMessageBox::critical(
            0, tr("Mixxx Library"),
            tr("Could not load the following file because"
               " it is in use by Mixxx or another application.")
            + "\n" +track_location);
        return TrackPointer();
    }
    return m_pTrackCollection->getTrackDAO()
            .getOrAddTrack(track_location, true, NULL);
}
Example #18
0
/** Do a non-recursive import of all the songs in a directory. Does NOT decend into subdirectories.
    @param trackDao The track data access object which provides a connection to the database. We use this parameter in order to make this function callable from separate threads. You need to use a different DB connection for each thread.
    @return true if the scan completed without being cancelled. False if the scan was cancelled part-way through.
*/
bool TrackCollection::importDirectory(const QString& directory, TrackDAO& trackDao,
                                      const QStringList& nameFilters,
                                      volatile bool* cancel) {
    //qDebug() << "TrackCollection::importDirectory(" << directory<< ")";

    emit(startedLoading());
    // QFileInfoList files;

    //get a list of the contents of the directory and go through it.
    QDirIterator it(directory, nameFilters, QDir::Files | QDir::NoDotAndDotDot);
    while (it.hasNext()) {

        //If a flag was raised telling us to cancel the library scan then stop.
        if (*cancel) {
            return false;
        }

        QString absoluteFilePath = it.next();

        // If the track is in the database, mark it as existing. This code gets exectuted
        // when other files in the same directory have changed (the directory hash has changed).
        trackDao.markTrackLocationAsVerified(absoluteFilePath);

        // If the file already exists in the database, continue and go on to
        // the next file.

        // If the file doesn't already exist in the database, then add
        // it. If it does exist in the database, then it is either in the
        // user's library OR the user has "removed" the track via
        // "Right-Click -> Remove". These tracks stay in the library, but
        // their mixxx_deleted column is 1.
        if (!trackDao.trackExistsInDatabase(absoluteFilePath)) {
            //qDebug() << "Loading" << it.fileName();
            emit(progressLoading(it.fileName()));

            TrackPointer pTrack = TrackPointer(new TrackInfoObject(
                                                   absoluteFilePath), &QObject::deleteLater);

            if (trackDao.addTracksAdd(pTrack.data(), false)) {
                // Successful added
                // signal the main instance of TrackDao, that there is a
                // new Track in the database
                m_trackDao->databaseTrackAdded(pTrack);
            } else {
                qDebug() << "Track ("+absoluteFilePath+") could not be added";
            }
        }
    }
    emit(finishedLoading());
    return true;
}
Example #19
0
void Library::slotLoadLocationToPlayer(QString location, QString group) {
    TrackDAO& track_dao = m_pTrackCollection->getTrackDAO();
    int track_id = track_dao.getTrackId(location);
    if (track_id < 0) {
        // Add Track to library
        track_id = track_dao.addTrack(location, true);
    }

    TrackPointer pTrack;
    if (track_id < 0) {
        // Add Track to library failed, create a transient TrackInfoObject
        pTrack = TrackPointer(new TrackInfoObject(location), &QObject::deleteLater);
    } else {
        pTrack = track_dao.getTrack(track_id);
    }
    emit(loadTrackToPlayer(pTrack, group));
}
Example #20
0
// This is called from the AnalyserQueue thread
TrackPointer AnalyserQueue::dequeueNextBlocking() {
    m_qm.lock();
    if (m_tioq.isEmpty()) {
        Event::end("AnalyserQueue process");
        m_qwait.wait(&m_qm);
        Event::start("AnalyserQueue process");

        if (m_exit) {
            m_qm.unlock();
            return TrackPointer();
        }
    }

    const PlayerInfo& info = PlayerInfo::instance();
    TrackPointer pLoadTrack;
    QMutableListIterator<TrackPointer> it(m_tioq);
    while (it.hasNext()) {
        TrackPointer& pTrack = it.next();
        if (!pTrack) {
            it.remove();
            continue;
        }
        // Prioritize tracks that are loaded.
        if (info.isTrackLoaded(pTrack)) {
            qDebug() << "Prioritizing" << pTrack->getTitle() << pTrack->getLocation();
            pLoadTrack = pTrack;
            it.remove();
            break;
        }
    }

    if (!pLoadTrack && !m_tioq.isEmpty()) {
        pLoadTrack = m_tioq.dequeue();
    }

    m_qm.unlock();

    if (pLoadTrack) {
        qDebug() << "Analyzing" << pLoadTrack->getTitle() << pLoadTrack->getLocation();
    }
    // pTrack might be NULL, up to the caller to check.
    return pLoadTrack;
}
Example #21
0
void CachingReaderWorker::run() {
    TrackPointer pLoadTrack;
    ChunkReadRequest request;
    ReaderStatusUpdate status;

    while (!deref(m_stop)) {
        if (m_newTrack) {
            m_newTrackMutex.lock();
            pLoadTrack = m_newTrack;
            m_newTrack = TrackPointer();
            m_newTrackMutex.unlock();
            loadTrack(pLoadTrack);
        } else if (m_pChunkReadRequestFIFO->read(&request, 1) == 1) {
            // Read the requested chunks.
            processChunkReadRequest(&request, &status);
            m_pReaderStatusFIFO->writeBlocking(&status, 1);
        } else {
            m_semaRun.acquire();
        }
    }
}
Example #22
0
TrackPointer GlobalTrackCache::lookupById(
        const TrackId& trackId) {
    const auto trackById(m_tracksById.find(trackId));
    if (m_tracksById.end() != trackById) {
        // Cache hit
        if (traceLogEnabled()) {
            kLogger.trace()
                    << "Cache hit for"
                    << trackId
                    << trackById->second->getPlainPtr();
        }
        return revive(trackById->second);
    } else {
        // Cache miss
        if (traceLogEnabled()) {
            kLogger.trace()
                    << "Cache miss for"
                    << trackId;
        }
        return TrackPointer();
    }
}
Example #23
0
TrackPointer BaseTrackPlayerImpl::unloadTrack() {
    if (!m_pLoadedTrack) {
        // nothing to do
        return TrackPointer();
    }

    // Save the loops that are currently set in a loop cue. If no loop cue is
    // currently on the track, then create a new one.
    double loopStart = m_pLoopInPoint->get();
    double loopEnd = m_pLoopOutPoint->get();
    if (loopStart != kNoTrigger && loopEnd != kNoTrigger && loopStart <= loopEnd) {
        CuePointer pLoopCue;
        QList<CuePointer> cuePoints(m_pLoadedTrack->getCuePoints());
        QListIterator<CuePointer> it(cuePoints);
        while (it.hasNext()) {
            CuePointer pCue(it.next());
            if (pCue->getType() == Cue::LOOP) {
                pLoopCue = pCue;
            }
        }
        if (!pLoopCue) {
            pLoopCue = m_pLoadedTrack->createAndAddCue();
            pLoopCue->setType(Cue::LOOP);
        }
        pLoopCue->setPosition(loopStart);
        pLoopCue->setLength(loopEnd - loopStart);
    }

    disconnectLoadedTrack();

    // Do not reset m_pReplayGain here, because the track might be still
    // playing and the last buffer will be processed.

    m_pPlay->set(0.0);

    TrackPointer pUnloadedTrack(std::move(m_pLoadedTrack));
    DEBUG_ASSERT(!m_pLoadedTrack);
    return pUnloadedTrack;
}
Example #24
0
void AnalyserQueue::run() {
    unsigned static id = 0; //the id of this thread, for debugging purposes
    QThread::currentThread()->setObjectName(QString("AnalyserQueue %1").arg(++id));

    // If there are no analyzers, don't waste time running.
    if (m_aq.size() == 0)
        return;

    m_progressInfo.current_track = TrackPointer();
    m_progressInfo.track_progress = 0;
    m_progressInfo.queue_size = 0;
    m_progressInfo.sema.release(); // Initalise with one

    while (!m_exit) {
        TrackPointer nextTrack = dequeueNextBlocking();

        // It's important to check for m_exit here in case we decided to exit
        // while blocking for a new track.
        if (m_exit)
            return;

        // If the track is NULL, try to get the next one.
        // Could happen if the track was queued but then deleted.
        // Or if dequeueNextBlocking is unblocked by exit == true
        if (!nextTrack) {
            m_qm.lock();
            m_queue_size = m_tioq.size();
            m_qm.unlock();
            if (m_queue_size == 0) {
                emit(queueEmpty()); // emit asynchrony for no deadlock
            }
            continue;
        }

        Trace trace("AnalyserQueue analyzing track");

        // Get the audio
        SoundSourceProxy soundSource(nextTrack);
        soundSource.open(); //Open the file for reading
        int iNumSamples = soundSource.length();
        int iSampleRate = soundSource.getSampleRate();

        if (iNumSamples == 0 || iSampleRate == 0) {
            qDebug() << "Skipping invalid file:" << nextTrack->getLocation();
            continue;
        }

        QListIterator<Analyser*> it(m_aq);
        bool processTrack = false;
        while (it.hasNext()) {
            // Make sure not to short-circuit initialise(...)
            if (it.next()->initialise(nextTrack, iSampleRate, iNumSamples)) {
                processTrack = true;
            }
        }

        m_qm.lock();
        m_queue_size = m_tioq.size();
        m_qm.unlock();

        if (processTrack) {
            emitUpdateProgress(nextTrack, 0);
            bool completed = doAnalysis(nextTrack, &soundSource);
            if (!completed) {
                //This track was cancelled
                QListIterator<Analyser*> itf(m_aq);
                while (itf.hasNext()) {
                    itf.next()->cleanup(nextTrack);
                }
                queueAnalyseTrack(nextTrack);
                emitUpdateProgress(nextTrack, 0);
            } else {
                // 100% - FINALIZE_PERCENT finished
                emitUpdateProgress(nextTrack, 1000 - FINALIZE_PERCENT);
                // This takes around 3 sec on a Atom Netbook
                QListIterator<Analyser*> itf(m_aq);
                while (itf.hasNext()) {
                    itf.next()->finalise(nextTrack);
                }
                emit(trackDone(nextTrack));
                emitUpdateProgress(nextTrack, 1000); // 100%
            }
        } else {
            emitUpdateProgress(nextTrack, 1000); // 100%
            qDebug() << "Skipping track analysis because no analyzer initialized.";
        }

        m_qm.lock();
        m_queue_size = m_tioq.size();
        m_qm.unlock();
        if (m_queue_size == 0) {
            emit(queueEmpty()); // emit asynchrony for no deadlock
        }
    }
    emit(queueEmpty()); // emit in case of exit;
}
Example #25
0
TEST_F(CoverArtUtilTest, searchImage) {
    // creating a temp track directory
    QString trackdir(QDir::tempPath() % "/TrackDir");
    ASSERT_FALSE(QDir().exists(trackdir)); // it must start empty
    ASSERT_TRUE(QDir().mkpath(trackdir));

    TrackPointer pTrack(Track::newTemporary(kTrackLocationTest));
    SoundSourceProxy(pTrack).loadTrackMetadata();
    QLinkedList<QFileInfo> covers;
    CoverArt res;
    // looking for cover in an empty directory
    res = CoverArtUtils::selectCoverArtForTrack(pTrack.data(), covers);
    CoverArt expected;
    expected.info.source = CoverInfo::GUESSED;
    EXPECT_EQ(expected, res);

    // Looking for a track with embedded cover.
    pTrack = TrackPointer(Track::newTemporary(kTrackLocationTest));
    SoundSourceProxy(pTrack).loadTrackMetadataAndCoverArt();
    expected = CoverArt();
    expected.image = pTrack->getCoverArt().image;
    expected.info.type = CoverInfo::METADATA;
    expected.info.source = CoverInfo::GUESSED;
    expected.info.coverLocation = QString();
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    EXPECT_EQ(expected, pTrack->getCoverArt());

    const char* format("jpg");
    const QString qFormat(format);

    // Since we already parsed this image from the matadata in
    // kTrackLocationTest, hang on to it since we use it as a template for
    // stuff below.
    const QImage img = expected.image;


    QString trackBaseName = "cover-test";
    QString trackAlbum = "album_name";

    // Search Strategy
    // 0. If we have just one file, we will get it.
    // 1. %track-file-base%.jpg in the track directory for %track-file-base%.mp3
    // 2. %album%.jpg
    // 3. cover.jpg
    // 4. front.jpg
    // 5. album.jpg
    // 6. folder.jpg
    // 7. if just one file exists take that otherwise none.

    // All the following expect the same image/hash to be selected.
    expected.image = img;
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);

    // All the following expect FILE and GUESSED.
    expected.info.type = CoverInfo::FILE;
    expected.info.source = CoverInfo::GUESSED;

    // 0. saving just one cover in our temp track dir
    QString cLoc_foo = QString(trackdir % "/" % "foo." % qFormat);
    EXPECT_TRUE(img.save(cLoc_foo, format));

    // looking for cover in an directory with one image will select that one.
    expected.image = QImage(cLoc_foo);
    expected.info.coverLocation = "foo.jpg";
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    covers << QFileInfo(cLoc_foo);
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                covers);
    EXPECT_EQ(expected, res);
    QFile::remove(cLoc_foo);

    QStringList extraCovers;
    // adding some extra images (bigger) just to populate the track dir.
    QString cLoc_big1 = QString(trackdir % "/" % "big1." % qFormat);
    EXPECT_TRUE(img.scaled(1000,1000).save(cLoc_big1, format));
    extraCovers << cLoc_big1;
    QString cLoc_big2 = QString(trackdir % "/" % "big2." % qFormat);
    EXPECT_TRUE(img.scaled(900,900).save(cLoc_big2, format));
    extraCovers << cLoc_big2;
    QString cLoc_big3 = QString(trackdir % "/" % "big3." % qFormat);
    EXPECT_TRUE(img.scaled(800,800).save(cLoc_big3, format));
    extraCovers << cLoc_big3;

    // saving more covers using the preferred names in the right order
    QLinkedList<QFileInfo> prefCovers;
    // 1. track_filename.jpg
    QString cLoc_filename = QString(trackdir % "/cover-test." % qFormat);
    EXPECT_TRUE(img.scaled(500,500).save(cLoc_filename, format));
    prefCovers << QFileInfo(cLoc_filename);
    // 2. album_name.jpg
    QString cLoc_albumName = QString(trackdir % "/album_name." % qFormat);
    EXPECT_TRUE(img.scaled(500,500).save(cLoc_albumName, format));
    prefCovers << QFileInfo(cLoc_albumName);
    // 3. cover.jpg
    QString cLoc_cover = QString(trackdir % "/" % "cover." % qFormat);
    EXPECT_TRUE(img.scaled(400,400).save(cLoc_cover, format));
    prefCovers << QFileInfo(cLoc_cover);
    // 4. front.jpg
    QString cLoc_front = QString(trackdir % "/" % "front." % qFormat);
    EXPECT_TRUE(img.scaled(300,300).save(cLoc_front, format));
    prefCovers << QFileInfo(cLoc_front);
    // 5. album.jpg
    QString cLoc_album = QString(trackdir % "/" % "album." % qFormat);
    EXPECT_TRUE(img.scaled(100,100).save(cLoc_album, format));
    prefCovers << QFileInfo(cLoc_album);
    // 6. folder.jpg
    QString cLoc_folder = QString(trackdir % "/" % "folder." % qFormat);
    EXPECT_TRUE(img.scaled(100,100).save(cLoc_folder, format));
    prefCovers << QFileInfo(cLoc_folder);
    // 8. other1.jpg
    QString cLoc_other1 = QString(trackdir % "/" % "other1." % qFormat);
    EXPECT_TRUE(img.scaled(10,10).save(cLoc_other1, format));
    prefCovers << QFileInfo(cLoc_other1);
    // 7. other2.jpg
    QString cLoc_other2 = QString(trackdir % "/" % "other2." % qFormat);
    EXPECT_TRUE(img.scaled(10,10).save(cLoc_other2, format));
    prefCovers << QFileInfo(cLoc_other2);

    // we must find covers in the right order
    EXPECT_EQ(8, prefCovers.size());

    // Remove the covers one by one from the front, checking that each one is
    // selected as we remove the previously-most-preferable cover.
    while (!prefCovers.isEmpty()) {
        QFileInfo cover = prefCovers.first();

        // We expect no cover selected for other1 since there are 2 covers,
        // neither of which match our preferred cover names. other2 will be
        // selected once we get to it since it is the only cover available.
        if (cover.baseName() == "other1") {
            expected.image = QImage();
            expected.info.type = CoverInfo::NONE;
            expected.info.coverLocation = QString();
            expected.info.hash = 0;
        } else {
            expected.image = QImage(cover.filePath());
            expected.info.type = CoverInfo::FILE;
            expected.info.coverLocation = cover.fileName();
            expected.info.hash = CoverArtUtils::calculateHash(expected.image);
        }
        res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                    prefCovers);
        EXPECT_QSTRING_EQ(expected.info.coverLocation, res.info.coverLocation);
        EXPECT_QSTRING_EQ(expected.info.hash, res.info.hash);
        EXPECT_EQ(expected, res);

        QFile::remove(cover.filePath());
        prefCovers.pop_front();
    }

    //
    // Additional tests
    //

    // what is chosen when cover.jpg and cover.JPG exists?
    // (it must always prefer the lighter cover)
    QString cLoc_coverJPG = trackdir % "/" % "cover." % "JPG";
    EXPECT_TRUE(img.scaled(200,200).save(cLoc_coverJPG, "JPG"));
    prefCovers.append(QFileInfo(cLoc_coverJPG));
    QString cLoc_coverjpg = trackdir % "/" % "cover." % "jpg";
    EXPECT_TRUE(img.scaled(400,400).save(cLoc_coverjpg, "jpg"));
    prefCovers.append(QFileInfo(cLoc_coverjpg));
    extraCovers << cLoc_coverJPG << cLoc_coverjpg;

    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_coverJPG);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = "cover.JPG";
    EXPECT_EQ(expected, res);

    // As we are looking for %album%.jpg and %base_track.jpg%,
    // we need to check if everything works with UTF8 chars.
    trackBaseName = QString::fromUtf8("track_ðÑöæäî");
    trackAlbum = QString::fromUtf8("öæäîðÑ_album");

    prefCovers.clear();

    // 2. album_name.jpg
    cLoc_albumName = QString(trackdir % "/" % trackAlbum % "." % qFormat);
    EXPECT_TRUE(img.save(cLoc_albumName, format));
    prefCovers.append(QFileInfo(cLoc_albumName));
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_albumName);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = trackAlbum % ".jpg";
    EXPECT_EQ(expected, res);

    // 1. track_filename.jpg
    cLoc_filename = QString(trackdir % "/" % trackBaseName % "." % qFormat);
    EXPECT_TRUE(img.save(cLoc_filename, format));
    prefCovers.append(QFileInfo(cLoc_filename));
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_filename);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = trackBaseName % ".jpg";
    EXPECT_EQ(expected, res);

    QFile::remove(cLoc_filename);
    QFile::remove(cLoc_albumName);

    // cleaning temp dir
    foreach (QString loc, extraCovers) {
        QFile::remove(loc);
    }
Example #26
0
void WWaveformViewer::onTrackUnloaded( TrackPointer /*track*/) {
    if (m_waveformWidget)
        m_waveformWidget->setTrack(TrackPointer(0));
}
Example #27
0
void GlobalTrackCache::resolve(
        GlobalTrackCacheResolver* /*in/out*/ pCacheResolver,
        QFileInfo /*in*/ fileInfo,
        TrackId trackId,
        SecurityTokenPointer pSecurityToken) {
    DEBUG_ASSERT(pCacheResolver);
    // Primary lookup by id (if available)
    if (trackId.isValid()) {
        if (debugLogEnabled()) {
            kLogger.debug()
                    << "Resolving track by id"
                    << trackId;
        }
        auto strongPtr = lookupById(trackId);
        if (strongPtr) {
            if (debugLogEnabled()) {
                kLogger.debug()
                        << "Cache hit - found track by id"
                        << trackId
                        << strongPtr.get();
            }
            TrackRef trackRef = createTrackRef(*strongPtr);
            pCacheResolver->initLookupResult(
                    GlobalTrackCacheLookupResult::HIT,
                    std::move(strongPtr),
                    std::move(trackRef));
            return;
        }
    }
    // Secondary lookup by canonical location
    // The TrackRef is constructed now after the lookup by ID failed to
    // avoid calculating the canonical file path if it is not needed.
    TrackRef trackRef = TrackRef::fromFileInfo(fileInfo, trackId);
    if (trackRef.hasCanonicalLocation()) {
        if (debugLogEnabled()) {
            kLogger.debug()
                    << "Resolving track by canonical location"
                    << trackRef.getCanonicalLocation();
        }
        auto strongPtr = lookupByRef(trackRef);
        if (strongPtr) {
            // Cache hit
            if (debugLogEnabled()) {
                kLogger.debug()
                        << "Cache hit - found track by canonical location"
                        << trackRef.getCanonicalLocation()
                        << strongPtr.get();
            }
            pCacheResolver->initLookupResult(
                    GlobalTrackCacheLookupResult::HIT,
                    std::move(strongPtr),
                    std::move(trackRef));
            return;
        }
    }
    if (!m_pSaver) {
        // Do not allocate any new tracks once the cache
        // has been deactivated
        DEBUG_ASSERT(isEmpty());
        kLogger.warning()
                << "Cache miss - caching has already been deactivated"
                << trackRef;
        return;
    }
    if (debugLogEnabled()) {
        kLogger.debug()
                << "Cache miss - allocating track"
                << trackRef;
    }
    auto deletingPtr = std::unique_ptr<Track, void (&)(Track*)>(
            new Track(
                    std::move(fileInfo),
                    std::move(pSecurityToken),
                    std::move(trackId)),
            deleteTrack);
    // Track objects live together with the cache on the main thread
    // and will be deleted later within the event loop. But this
    // function might be called from any thread, even from worker
    // threads without an event loop. We need to move the newly
    // created object to the target thread.
    deletingPtr->moveToThread(QApplication::instance()->thread());

    auto cacheEntryPtr = std::make_shared<GlobalTrackCacheEntry>(
            std::move(deletingPtr));
    auto savingPtr = TrackPointer(
            cacheEntryPtr->getPlainPtr(),
            EvictAndSaveFunctor(cacheEntryPtr));
    cacheEntryPtr->setSavingWeakPtr(savingPtr);

    if (debugLogEnabled()) {
        kLogger.debug()
                << "Cache miss - inserting new track into cache"
                << trackRef
                << deletingPtr.get();
    }

    if (trackRef.hasId()) {
        // Insert item by id
        DEBUG_ASSERT(m_tracksById.find(
                trackRef.getId()) == m_tracksById.end());
        m_tracksById.insert(std::make_pair(
                trackRef.getId(),
                cacheEntryPtr));
    }
    if (trackRef.hasCanonicalLocation()) {
        // Insert item by track location
        DEBUG_ASSERT(m_tracksByCanonicalLocation.find(
                trackRef.getCanonicalLocation()) == m_tracksByCanonicalLocation.end());
        m_tracksByCanonicalLocation.insert(std::make_pair(
                trackRef.getCanonicalLocation(),
                cacheEntryPtr));
    }
    pCacheResolver->initLookupResult(
            GlobalTrackCacheLookupResult::MISS,
            std::move(savingPtr),
            std::move(trackRef));
}
Example #28
0
TrackPointer ProxyTrackModel::getTrack(const QModelIndex& index) const {
    QModelIndex indexSource = mapToSource(index);
    return m_pTrackModel ? m_pTrackModel->getTrack(indexSource) : TrackPointer();
}
Example #29
0
void ClockControl::trackUnloaded(TrackPointer pTrack) {
    Q_UNUSED(pTrack)
    trackLoaded(TrackPointer());
}
Example #30
0
void SamplerBank::slotLoadSamplerBank(double v) {
    if (v == 0.0 || m_pPlayerManager == NULL) {
        return;
    }

    QString samplerBankPath = QFileDialog::getOpenFileName(
            NULL,
            tr("Load Sampler Bank"),
            QString(),
            tr("Mixxx Sampler Banks (*.xml)"));
    if (samplerBankPath.isEmpty()) {
        return;
    }

    // The user has picked a new directory via a file dialog. This means the
    // system sandboxer (if we are sandboxed) has granted us permission to this
    // folder. We don't need access to this file on a regular basis so we do not
    // register a security bookmark.

    QFile file(samplerBankPath);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(NULL,
                             tr("Error Reading Sampler Bank"),
                             tr("Could not open the sampler bank file '%1'.")
                             .arg(samplerBankPath));
        return;
    }

    QDomDocument doc;

    if (!doc.setContent(file.readAll())) {
        QMessageBox::warning(NULL,
                             tr("Error Reading Sampler Bank"),
                             tr("Could not read the sampler bank file '%1'.")
                             .arg(samplerBankPath));
        return;
    }

    QDomElement root = doc.documentElement();
    if(root.tagName() != "samplerbank") {
        QMessageBox::warning(NULL,
                             tr("Error Reading Sampler Bank"),
                             tr("Could not read the sampler bank file '%1'.")
                             .arg(samplerBankPath));
        return;
    }

    QDomNode n = root.firstChild();

    while (!n.isNull()) {
        QDomElement e = n.toElement();

        if (!e.isNull()) {
            if (e.tagName() == "sampler") {
                QString group = e.attribute("group", "");
                QString location = e.attribute("location", "");

                if (!group.isEmpty()) {
                    if (location.isEmpty()) {
                        m_pPlayerManager->slotLoadTrackToPlayer(TrackPointer(), group);
                    } else {
                        m_pPlayerManager->slotLoadToPlayer(location, group);
                    }
                }

            }
        }
        n = n.nextSibling();
    }

    file.close();
}