Example #1
0
// This is called from the AnalyserQueue thread
bool AnalyserQueue::doAnalysis(TrackPointer tio, SoundSourceProxy* pSoundSource) {
    int totalSamples = pSoundSource->length();
    //qDebug() << tio->getFilename() << " has " << totalSamples << " samples.";
    int processedSamples = 0;

    QTime progressUpdateInhibitTimer;
    progressUpdateInhibitTimer.start(); // Inhibit Updates for 60 milliseconds

    int read = 0;
    bool dieflag = false;
    bool cancelled = false;
    int progress; // progress in 0 ... 100

    do {
        ScopedTimer t("AnalyserQueue::doAnalysis block");
        read = pSoundSource->read(kAnalysisBlockSize, m_pSamplesPCM);

        // To compare apples to apples, let's only look at blocks that are the
        // full block size.
        if (read != kAnalysisBlockSize) {
            t.cancel();
        }

        // Safety net in case something later barfs on 0 sample input
        if (read == 0) {
            t.cancel();
            break;
        }

        // If we get more samples than length, ask the analysers to process
        // up to the number we promised, then stop reading - AD
        if (read + processedSamples > totalSamples) {
            qDebug() << "While processing track of length " << totalSamples << " actually got "
                     << read + processedSamples << " samples, truncating analysis at expected length";
            read = totalSamples - processedSamples;
            dieflag = true;
        }

        // Normalize the samples from [SHRT_MIN, SHRT_MAX] to [-1.0, 1.0].
        // TODO(rryan): Change the SoundSource API to do this for us.
        for (int i = 0; i < read; ++i) {
            m_pSamples[i] = static_cast<CSAMPLE>(m_pSamplesPCM[i]) / SHRT_MAX;
        }

        QListIterator<Analyser*> it(m_aq);

        while (it.hasNext()) {
            Analyser* an =  it.next();
            //qDebug() << typeid(*an).name() << ".process()";
            an->process(m_pSamples, read);
            //qDebug() << "Done " << typeid(*an).name() << ".process()";
        }

        // emit progress updates
        // During the doAnalysis function it goes only to 100% - FINALIZE_PERCENT
        // because the finalise functions will take also some time
        processedSamples += read;
        //fp div here prevents insane signed overflow
        progress = (int)(((float)processedSamples)/totalSamples *
                         (1000 - FINALIZE_PERCENT));

        if (m_progressInfo.track_progress != progress) {
            if (progressUpdateInhibitTimer.elapsed() > 60) {
                // Inhibit Updates for 60 milliseconds
                emitUpdateProgress(tio, progress);
                progressUpdateInhibitTimer.start();
            }
        }

        // Since this is a background analysis queue, we should co-operatively
        // yield every now and then to try and reduce CPU contention. The
        // analyser queue is CPU intensive so we want to get out of the way of
        // the audio callback thread.
        //QThread::yieldCurrentThread();
        //QThread::usleep(10);

        //has something new entered the queue?
        if (load_atomic(m_aiCheckPriorities)) {
            m_aiCheckPriorities = false;
            if (isLoadedTrackWaiting(tio)) {
                qDebug() << "Interrupting analysis to give preference to a loaded track.";
                dieflag = true;
                cancelled = true;
            }
        }

        if (m_exit) {
            dieflag = true;
            cancelled = true;
        }

        // Ignore blocks in which we decided to bail for stats purposes.
        if (dieflag || cancelled) {
            t.cancel();
        }
    } while(read == kAnalysisBlockSize && !dieflag);

    return !cancelled; //don't return !dieflag or we might reanalyze over and over
}
Example #2
0
// This is called from the AnalyserQueue thread
bool AnalyserQueue::doAnalysis(TrackPointer tio, SoundSourceProxy* pSoundSource) {
    // TonalAnalyser requires a block size of 65536. Using a different value
    // breaks the tonal analyser. We need to use a smaller block size becuase on
    // Linux, the AnalyserQueue can starve the CPU of its resources, resulting
    // in xruns.. A block size of 8192 seems to do fine.
    const int ANALYSISBLOCKSIZE = 8192;

    int totalSamples = pSoundSource->length();
    //qDebug() << tio->getFilename() << " has " << totalSamples << " samples.";
    int processedSamples = 0;

    SAMPLE* data16 = new SAMPLE[ANALYSISBLOCKSIZE];
    CSAMPLE* samples = new CSAMPLE[ANALYSISBLOCKSIZE];

    QTime progressUpdateInhibitTimer;
    progressUpdateInhibitTimer.start(); // Inhibit Updates for 60 milliseconds

    int read = 0;
    bool dieflag = false;
    bool cancelled = false;
    int progress; // progress in 0 ... 100

    do {
        ScopedTimer t("AnalyserQueue::doAnalysis block");
        read = pSoundSource->read(ANALYSISBLOCKSIZE, data16);

        // To compare apples to apples, let's only look at blocks that are the
        // full block size.
        if (read != ANALYSISBLOCKSIZE) {
            t.cancel();
        }

        // Safety net in case something later barfs on 0 sample input
        if (read == 0) {
            t.cancel();
            break;
        }

        // If we get more samples than length, ask the analysers to process
        // up to the number we promised, then stop reading - AD
        if (read + processedSamples > totalSamples) {
            qDebug() << "While processing track of length " << totalSamples << " actually got "
                     << read + processedSamples << " samples, truncating analysis at expected length";
            read = totalSamples - processedSamples;
            dieflag = true;
        }

        for (int i = 0; i < read; ++i) {
            samples[i] = ((float)data16[i])/32767.0f;
        }

        QListIterator<Analyser*> it(m_aq);

        while (it.hasNext()) {
            Analyser* an =  it.next();
            //qDebug() << typeid(*an).name() << ".process()";
            an->process(samples, read);
            //qDebug() << "Done " << typeid(*an).name() << ".process()";
        }

        // emit progress updates
        // During the doAnalysis function it goes only to 100% - FINALIZE_PERCENT
        // because the finalise functions will take also some time
        processedSamples += read;
        //fp div here prevents insane signed overflow
        progress = (int)(((float)processedSamples)/totalSamples *
                         (1000 - FINALIZE_PERCENT));

        if (m_progressInfo.track_progress != progress) {
            if (progressUpdateInhibitTimer.elapsed() > 60) {
                // Inhibit Updates for 60 milliseconds
                emitUpdateProgress(tio, progress);
                progressUpdateInhibitTimer.start();
            }
        }

        // Since this is a background analysis queue, we should co-operatively
        // yield every now and then to try and reduce CPU contention. The
        // analyser queue is CPU intensive so we want to get out of the way of
        // the audio callback thread.
        //QThread::yieldCurrentThread();
        //QThread::usleep(10);

        //has something new entered the queue?
        if (m_aiCheckPriorities) {
            m_aiCheckPriorities = false;
            if (isLoadedTrackWaiting(tio)) {
                qDebug() << "Interrupting analysis to give preference to a loaded track.";
                dieflag = true;
                cancelled = true;
            }
        }

        if (m_exit) {
            dieflag = true;
            cancelled = true;
        }

        // Ignore blocks in which we decided to bail for stats purposes.
        if (dieflag || cancelled) {
            t.cancel();
        }
    } while(read == ANALYSISBLOCKSIZE && !dieflag);

    delete[] data16;
    delete[] samples;

    return !cancelled; //don't return !dieflag or we might reanalyze over and over
}