Chris@1583: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1583: Chris@1583: /* Chris@1583: Sonic Visualiser Chris@1583: An audio file viewer and annotation editor. Chris@1583: Centre for Digital Music, Queen Mary, University of London. Chris@1583: Chris@1583: This program is free software; you can redistribute it and/or Chris@1583: modify it under the terms of the GNU General Public License as Chris@1583: published by the Free Software Foundation; either version 2 of the Chris@1583: License, or (at your option) any later version. See the file Chris@1583: COPYING included with this distribution for more information. Chris@1583: */ Chris@1583: Chris@1583: #include "BQAFileReader.h" Chris@1583: Chris@1583: #include Chris@1583: #include Chris@1583: #include Chris@1583: Chris@1583: #include "base/Profiler.h" Chris@1583: #include "base/ProgressReporter.h" Chris@1583: Chris@1583: #include Chris@1583: Chris@1583: using namespace std; Chris@1583: Chris@1583: BQAFileReader::BQAFileReader(FileSource source, Chris@1583: DecodeMode decodeMode, Chris@1583: CacheMode mode, Chris@1583: sv_samplerate_t targetRate, Chris@1583: bool normalised, Chris@1583: ProgressReporter *reporter) : Chris@1583: CodedAudioFileReader(mode, targetRate, normalised), Chris@1583: m_source(source), Chris@1583: m_path(source.getLocalFilename()), Chris@1583: m_cancelled(false), Chris@1583: m_completion(0), Chris@1583: m_reporter(reporter), Chris@1583: m_decodeThread(0) Chris@1583: { Chris@1583: SVDEBUG << "BQAFileReader: local path: \"" << m_path Chris@1583: << "\", decode mode: " << decodeMode << " (" Chris@1583: << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded") Chris@1583: << ")" << endl; Chris@1583: Chris@1583: m_channelCount = 0; Chris@1583: m_fileRate = 0; Chris@1583: Chris@1583: Profiler profiler("BQAFileReader::BQAFileReader"); Chris@1583: Chris@1583: try { Chris@1583: m_stream = breakfastquay::AudioReadStreamFactory::createReadStream Chris@1583: (m_path.toUtf8().data()); Chris@1583: } catch (const std::exception &e) { Chris@1583: m_error = e.what(); Chris@1595: SVDEBUG << "BQAFileReader: createReadStream failed: " << m_error << endl; Chris@1583: m_stream = 0; Chris@1583: return; Chris@1583: } Chris@1583: Chris@1584: m_channelCount = int(m_stream->getChannelCount()); Chris@1584: m_fileRate = sv_samplerate_t(m_stream->getSampleRate()); Chris@1587: m_title = QString::fromUtf8(m_stream->getTrackName().c_str()); Chris@1587: m_maker = QString::fromUtf8(m_stream->getArtistName().c_str()); Chris@1583: Chris@1583: initialiseDecodeCache(); Chris@1583: Chris@1583: if (decodeMode == DecodeAtOnce) { Chris@1583: Chris@1583: if (m_reporter) { Chris@1583: connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); Chris@1583: m_reporter->setMessage Chris@1583: (tr("Decoding %1...").arg(QFileInfo(m_path).fileName())); Chris@1583: } Chris@1583: Chris@1583: sv_frame_t blockSize = 65536; Chris@1583: floatvec_t block(blockSize * m_channelCount, 0.f); Chris@1583: Chris@1583: while (true) { Chris@1583: try { Chris@1583: sv_frame_t retrieved = Chris@1583: m_stream->getInterleavedFrames(blockSize, block.data()); Chris@1583: Chris@1583: addSamplesToDecodeCache(block.data(), retrieved); Chris@1583: Chris@1583: if (retrieved < blockSize) { Chris@1583: break; Chris@1583: } Chris@1583: } catch (const breakfastquay::InvalidFileFormat &f) { Chris@1583: m_error = f.what(); Chris@1595: SVDEBUG << "BQAFileReader: init failed: " << m_error << endl; Chris@1583: break; Chris@1583: } Chris@1583: Chris@1583: if (m_cancelled) break; Chris@1583: } Chris@1583: Chris@1583: if (isDecodeCacheInitialised()) finishDecodeCache(); Chris@1583: endSerialised(); Chris@1583: Chris@1583: if (m_reporter) m_reporter->setProgress(100); Chris@1583: Chris@1583: delete m_stream; Chris@1583: m_stream = 0; Chris@1583: Chris@1583: } else { Chris@1583: Chris@1583: if (m_reporter) m_reporter->setProgress(100); Chris@1583: Chris@1583: m_decodeThread = new DecodeThread(this); Chris@1583: m_decodeThread->start(); Chris@1583: } Chris@1583: } Chris@1583: Chris@1583: BQAFileReader::~BQAFileReader() Chris@1583: { Chris@1583: if (m_decodeThread) { Chris@1583: m_cancelled = true; Chris@1583: m_decodeThread->wait(); Chris@1583: delete m_decodeThread; Chris@1583: } Chris@1583: Chris@1583: delete m_stream; Chris@1583: } Chris@1583: Chris@1583: void Chris@1583: BQAFileReader::cancelled() Chris@1583: { Chris@1583: m_cancelled = true; Chris@1583: } Chris@1583: Chris@1583: void Chris@1583: BQAFileReader::DecodeThread::run() Chris@1583: { Chris@1583: if (m_reader->m_cacheMode == CacheInTemporaryFile) { Chris@1583: m_reader->startSerialised("BQAFileReader::Decode"); Chris@1583: } Chris@1583: Chris@1583: sv_frame_t blockSize = 65536; Chris@1583: floatvec_t block(blockSize * m_reader->getChannelCount(), 0.f); Chris@1583: Chris@1583: while (true) { Chris@1583: try { Chris@1583: sv_frame_t retrieved = Chris@1583: m_reader->m_stream->getInterleavedFrames Chris@1583: (blockSize, block.data()); Chris@1583: Chris@1583: m_reader->addSamplesToDecodeCache(block.data(), retrieved); Chris@1583: Chris@1583: if (retrieved < blockSize) { Chris@1583: break; Chris@1583: } Chris@1583: } catch (const breakfastquay::InvalidFileFormat &f) { Chris@1583: m_reader->m_error = f.what(); Chris@1595: SVDEBUG << "BQAFileReader: decode failed: " << m_reader->m_error << endl; Chris@1583: break; Chris@1583: } Chris@1583: Chris@1583: if (m_reader->m_cancelled) break; Chris@1583: } Chris@1583: Chris@1583: if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); Chris@1583: m_reader->m_completion = 100; Chris@1583: Chris@1583: m_reader->endSerialised(); Chris@1583: Chris@1583: delete m_reader->m_stream; Chris@1583: m_reader->m_stream = 0; Chris@1583: } Chris@1583: Chris@1583: void Chris@1583: BQAFileReader::getSupportedExtensions(set &extensions) Chris@1583: { Chris@1583: vector exts = Chris@1583: breakfastquay::AudioReadStreamFactory::getSupportedFileExtensions(); Chris@1583: for (auto e: exts) { Chris@1583: extensions.insert(QString::fromUtf8(e.c_str())); Chris@1583: } Chris@1583: } Chris@1583: Chris@1583: bool Chris@1583: BQAFileReader::supportsExtension(QString extension) Chris@1583: { Chris@1583: set extensions; Chris@1583: getSupportedExtensions(extensions); Chris@1583: return (extensions.find(extension.toLower()) != extensions.end()); Chris@1583: } Chris@1583: Chris@1583: bool Chris@1604: BQAFileReader::supportsContentType(QString type) Chris@1583: { Chris@1604: // extremely optimistic, but it's better than rejecting everything Chris@1604: //!!! todo: be more sensible Chris@1604: return (type.startsWith("audio/")); Chris@1583: } Chris@1583: Chris@1583: bool Chris@1583: BQAFileReader::supports(FileSource &source) Chris@1583: { Chris@1583: return (supportsExtension(source.getExtension()) || Chris@1583: supportsContentType(source.getContentType())); Chris@1583: } Chris@1583: