annotate data/fileio/BQAFileReader.cpp @ 1881:b504df98c3be

Ensure completion on output model is started at zero, so if it's checked before the input model has become ready and the transform has begun, it is not accidentally reported as complete (affected re-aligning models in Sonic Lineup when replacing the session)
author Chris Cannam
date Fri, 26 Jun 2020 11:45:39 +0100
parents 14747f24ad04
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