Пример #1
0
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);
        }
    }
}
Пример #2
0
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);
        }
    }
}
Пример #3
0
void TrackInfoObject::setAnalyserProgress(int progress) {
    // progress in 0 .. 1000. QAtomicInt so no need for lock.
    if (progress != load_atomic(m_analyserProgress)) {
        m_analyserProgress = progress;
        emit(analyserProgress(progress));
    }
}
Пример #4
0
void BulkReader::run() {
    m_stop = 0;
    unsigned char data[255];

    while (load_atomic(m_stop) == 0) {
        // Blocked polling: The only problem with this is that we can't close
        // the device until the block is released, which means the controller
        // has to send more data
        //result = hid_read_timeout(m_pHidDevice, data, 255, -1);

        // This relieves that at the cost of higher CPU usage since we only
        // block for a short while (500ms)
        int transferred;
        int result;

        result = libusb_bulk_transfer(m_phandle,
                                      m_in_epaddr,
                                      data, sizeof(data),
                                      &transferred, 500);
        Trace timeout("BulkReader timeout");
        if (result >= 0) {
            Trace process("BulkReader process packet");
            //qDebug() << "Read" << result << "bytes, pointer:" << data;
            QByteArray outData((char*)data, transferred);
            emit(incomingData(outData, Time::elapsed()));
        }
    }
    qDebug() << "Stopped Reader";
}
Пример #5
0
void TrackExportWorker::run() {
    int i = 0;
    for (const auto& track : m_tracks) {
        auto fileinfo = track->getFileInfo();
        emit(progress(fileinfo.fileName(), i, m_tracks.size()));
        exportTrack(track);
        if (load_atomic(m_bStop)) {
            emit(canceled());
            return;
        }
        ++i;
        emit(progress(fileinfo.fileName(), i, m_tracks.size()));
    }
}
Пример #6
0
void TrackExportWorker::run() {
    int i = 0;
    QMap<QString, QFileInfo> copy_list = createCopylist(m_tracks);
    for (auto it = copy_list.constBegin(); it != copy_list.constEnd(); ++it) {
        // We emit progress twice per loop, which may seem excessive, but it
        // guarantees that we emit a sane progress before we start and after
        // we end.  In between, each filename will get its own visible tick
        // on the bar, which looks really nice.
        emit(progress(it->fileName(), i, copy_list.size()));
        copyFile(*it, it.key());
        if (load_atomic(m_bStop)) {
            emit(canceled());
            return;
        }
        ++i;
        emit(progress(it->fileName(), i, copy_list.size()));
    }
}
Пример #7
0
TrackExportWorker::OverwriteAnswer TrackExportWorker::makeOverwriteRequest(
        QString filename) {
    // QT's QFuture is not quite right for this type of threaded question-and-answer.
    // std::future works fine, even with signals and slots.
    QScopedPointer<std::promise<OverwriteAnswer>> mode_promise(
            new std::promise<OverwriteAnswer>());
    std::future<OverwriteAnswer> mode_future = mode_promise->get_future();

    emit(askOverwriteMode(filename, mode_promise.data()));

    // Block until the user tells us the answer.
    mode_future.wait();

    // We can be either canceled from the other thread, or as a return value
    // from this call.  First check for a call from the other thread.
    if (load_atomic(m_bStop)) {
        return OverwriteAnswer::CANCEL;
    }

    if (!mode_future.valid()) {
        qWarning() << "TrackExportWorker::makeOverwriteRequest invalid answer from future";
        m_errorMessage = tr("Error exporting tracks");
        stop();
        return OverwriteAnswer::CANCEL;
    }

    OverwriteAnswer answer = mode_future.get();
    switch (answer) {
    case OverwriteAnswer::SKIP_ALL:
        m_overwriteMode = OverwriteMode::SKIP_ALL;
        break;
    case OverwriteAnswer::OVERWRITE_ALL:
        m_overwriteMode = OverwriteMode::OVERWRITE_ALL;
        break;
    case OverwriteAnswer::CANCEL:
        // Handle cancelation as a result of the question.
        m_errorMessage = tr("Export process was canceled");
        stop();
        break;
    default:;
    }

    return answer;
}
Пример #8
0
void HidReader::run() {
    m_stop = 0;
    unsigned char *data = new unsigned char[255];
    while (load_atomic(m_stop) == 0) {
        // Blocked polling: The only problem with this is that we can't close
        // the device until the block is released, which means the controller
        // has to send more data
        //result = hid_read_timeout(m_pHidDevice, data, 255, -1);

        // This relieves that at the cost of higher CPU usage since we only
        // block for a short while (500ms)
        int result = hid_read_timeout(m_pHidDevice, data, 255, 500);
        Trace timeout("HidReader timeout");
        if (result > 0) {
            Trace process("HidReader process packet");
            //qDebug() << "Read" << result << "bytes, pointer:" << data;
            QByteArray outData(reinterpret_cast<char*>(data), result);
            emit(incomingData(outData));
        }
    }
    delete [] data;
}
Пример #9
0
int TrackInfoObject::getAnalyserProgress() const {
    // QAtomicInt so no need for lock.
    return load_atomic(m_analyserProgress);
}
Пример #10
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
}