annotate data/fileio/BQAFileReader.cpp @ 1858:14747f24ad04

Use cancellable serialiser; add some more profiling points
author Chris Cannam
date Thu, 14 May 2020 16:36:48 +0100
parents 8aa1447fe27e
children
rev   line source
Chris@1583 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1583 2
Chris@1583 3 /*
Chris@1583 4 Sonic Visualiser
Chris@1583 5 An audio file viewer and annotation editor.
Chris@1583 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1583 7
Chris@1583 8 This program is free software; you can redistribute it and/or
Chris@1583 9 modify it under the terms of the GNU General Public License as
Chris@1583 10 published by the Free Software Foundation; either version 2 of the
Chris@1583 11 License, or (at your option) any later version. See the file
Chris@1583 12 COPYING included with this distribution for more information.
Chris@1583 13 */
Chris@1583 14
Chris@1583 15 #include "BQAFileReader.h"
Chris@1583 16
Chris@1583 17 #include <bqaudiostream/AudioReadStreamFactory.h>
Chris@1583 18 #include <bqaudiostream/AudioReadStream.h>
Chris@1583 19 #include <bqaudiostream/Exceptions.h>
Chris@1583 20
Chris@1583 21 #include "base/Profiler.h"
Chris@1583 22 #include "base/ProgressReporter.h"
Chris@1583 23
Chris@1583 24 #include <QFileInfo>
Chris@1583 25
Chris@1583 26 using namespace std;
Chris@1583 27
Chris@1583 28 BQAFileReader::BQAFileReader(FileSource source,
Chris@1583 29 DecodeMode decodeMode,
Chris@1583 30 CacheMode mode,
Chris@1583 31 sv_samplerate_t targetRate,
Chris@1583 32 bool normalised,
Chris@1583 33 ProgressReporter *reporter) :
Chris@1583 34 CodedAudioFileReader(mode, targetRate, normalised),
Chris@1583 35 m_source(source),
Chris@1583 36 m_path(source.getLocalFilename()),
Chris@1583 37 m_cancelled(false),
Chris@1583 38 m_completion(0),
Chris@1583 39 m_reporter(reporter),
Chris@1583 40 m_decodeThread(0)
Chris@1583 41 {
Chris@1583 42 SVDEBUG << "BQAFileReader: local path: \"" << m_path
Chris@1583 43 << "\", decode mode: " << decodeMode << " ("
Chris@1583 44 << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded")
Chris@1583 45 << ")" << endl;
Chris@1583 46
Chris@1583 47 m_channelCount = 0;
Chris@1583 48 m_fileRate = 0;
Chris@1583 49
Chris@1583 50 Profiler profiler("BQAFileReader::BQAFileReader");
Chris@1583 51
Chris@1583 52 try {
Chris@1583 53 m_stream = breakfastquay::AudioReadStreamFactory::createReadStream
Chris@1583 54 (m_path.toUtf8().data());
Chris@1583 55 } catch (const std::exception &e) {
Chris@1583 56 m_error = e.what();
Chris@1595 57 SVDEBUG << "BQAFileReader: createReadStream failed: " << m_error << endl;
Chris@1583 58 m_stream = 0;
Chris@1583 59 return;
Chris@1583 60 }
Chris@1583 61
Chris@1584 62 m_channelCount = int(m_stream->getChannelCount());
Chris@1584 63 m_fileRate = sv_samplerate_t(m_stream->getSampleRate());
Chris@1587 64 m_title = QString::fromUtf8(m_stream->getTrackName().c_str());
Chris@1587 65 m_maker = QString::fromUtf8(m_stream->getArtistName().c_str());
Chris@1583 66
Chris@1583 67 initialiseDecodeCache();
Chris@1583 68
Chris@1583 69 if (decodeMode == DecodeAtOnce) {
Chris@1583 70
Chris@1583 71 if (m_reporter) {
Chris@1583 72 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@1583 73 m_reporter->setMessage
Chris@1583 74 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@1583 75 }
Chris@1583 76
Chris@1583 77 sv_frame_t blockSize = 65536;
Chris@1583 78 floatvec_t block(blockSize * m_channelCount, 0.f);
Chris@1583 79
Chris@1583 80 while (true) {
Chris@1583 81 try {
Chris@1583 82 sv_frame_t retrieved =
Chris@1583 83 m_stream->getInterleavedFrames(blockSize, block.data());
Chris@1583 84
Chris@1583 85 addSamplesToDecodeCache(block.data(), retrieved);
Chris@1583 86
Chris@1583 87 if (retrieved < blockSize) {
Chris@1583 88 break;
Chris@1583 89 }
Chris@1583 90 } catch (const breakfastquay::InvalidFileFormat &f) {
Chris@1583 91 m_error = f.what();
Chris@1595 92 SVDEBUG << "BQAFileReader: init failed: " << m_error << endl;
Chris@1583 93 break;
Chris@1583 94 }
Chris@1583 95
Chris@1583 96 if (m_cancelled) break;
Chris@1583 97 }
Chris@1583 98
Chris@1583 99 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@1583 100 endSerialised();
Chris@1583 101
Chris@1583 102 if (m_reporter) m_reporter->setProgress(100);
Chris@1583 103
Chris@1583 104 delete m_stream;
Chris@1583 105 m_stream = 0;
Chris@1583 106
Chris@1583 107 } else {
Chris@1583 108
Chris@1583 109 if (m_reporter) m_reporter->setProgress(100);
Chris@1583 110
Chris@1583 111 m_decodeThread = new DecodeThread(this);
Chris@1583 112 m_decodeThread->start();
Chris@1583 113 }
Chris@1583 114 }
Chris@1583 115
Chris@1583 116 BQAFileReader::~BQAFileReader()
Chris@1583 117 {
Chris@1858 118 Profiler profiler("BQAFileReader::~BQAFileReader");
Chris@1858 119
Chris@1583 120 if (m_decodeThread) {
Chris@1583 121 m_cancelled = true;
Chris@1583 122 m_decodeThread->wait();
Chris@1583 123 delete m_decodeThread;
Chris@1583 124 }
Chris@1858 125
Chris@1583 126 delete m_stream;
Chris@1583 127 }
Chris@1583 128
Chris@1583 129 void
Chris@1583 130 BQAFileReader::cancelled()
Chris@1583 131 {
Chris@1583 132 m_cancelled = true;
Chris@1583 133 }
Chris@1583 134
Chris@1583 135 void
Chris@1583 136 BQAFileReader::DecodeThread::run()
Chris@1583 137 {
Chris@1583 138 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@1858 139 m_reader->startSerialised("BQAFileReader::Decode",
Chris@1858 140 &m_reader->m_cancelled);
Chris@1858 141 if (m_reader->m_cancelled) {
Chris@1858 142 return;
Chris@1858 143 }
Chris@1583 144 }
Chris@1583 145
Chris@1583 146 sv_frame_t blockSize = 65536;
Chris@1583 147 floatvec_t block(blockSize * m_reader->getChannelCount(), 0.f);
Chris@1583 148
Chris@1583 149 while (true) {
Chris@1583 150 try {
Chris@1583 151 sv_frame_t retrieved =
Chris@1583 152 m_reader->m_stream->getInterleavedFrames
Chris@1583 153 (blockSize, block.data());
Chris@1583 154
Chris@1583 155 m_reader->addSamplesToDecodeCache(block.data(), retrieved);
Chris@1583 156
Chris@1583 157 if (retrieved < blockSize) {
Chris@1583 158 break;
Chris@1583 159 }
Chris@1583 160 } catch (const breakfastquay::InvalidFileFormat &f) {
Chris@1583 161 m_reader->m_error = f.what();
Chris@1595 162 SVDEBUG << "BQAFileReader: decode failed: " << m_reader->m_error << endl;
Chris@1583 163 break;
Chris@1583 164 }
Chris@1583 165
Chris@1583 166 if (m_reader->m_cancelled) break;
Chris@1583 167 }
Chris@1583 168
Chris@1583 169 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@1583 170 m_reader->m_completion = 100;
Chris@1583 171
Chris@1583 172 m_reader->endSerialised();
Chris@1583 173
Chris@1583 174 delete m_reader->m_stream;
Chris@1583 175 m_reader->m_stream = 0;
Chris@1583 176 }
Chris@1583 177
Chris@1583 178 void
Chris@1583 179 BQAFileReader::getSupportedExtensions(set<QString> &extensions)
Chris@1583 180 {
Chris@1583 181 vector<string> exts =
Chris@1583 182 breakfastquay::AudioReadStreamFactory::getSupportedFileExtensions();
Chris@1583 183 for (auto e: exts) {
Chris@1583 184 extensions.insert(QString::fromUtf8(e.c_str()));
Chris@1583 185 }
Chris@1583 186 }
Chris@1583 187
Chris@1583 188 bool
Chris@1583 189 BQAFileReader::supportsExtension(QString extension)
Chris@1583 190 {
Chris@1583 191 set<QString> extensions;
Chris@1583 192 getSupportedExtensions(extensions);
Chris@1583 193 return (extensions.find(extension.toLower()) != extensions.end());
Chris@1583 194 }
Chris@1583 195
Chris@1583 196 bool
Chris@1604 197 BQAFileReader::supportsContentType(QString type)
Chris@1583 198 {
Chris@1604 199 // extremely optimistic, but it's better than rejecting everything
Chris@1604 200 //!!! todo: be more sensible
Chris@1604 201 return (type.startsWith("audio/"));
Chris@1583 202 }
Chris@1583 203
Chris@1583 204 bool
Chris@1583 205 BQAFileReader::supports(FileSource &source)
Chris@1583 206 {
Chris@1583 207 return (supportsExtension(source.getExtension()) ||
Chris@1583 208 supportsContentType(source.getContentType()));
Chris@1583 209 }
Chris@1583 210