annotate data/fileio/DecodingWavFileReader.cpp @ 1290:fa574c909c3d 3.0-integration

Add MAD_BUFFER_GUARD padding at end of mp3 buffer, in order to ensure last frame is decoded successfully (otherwise the decoded audio is truncated). Another thing learned from madplay.
author Chris Cannam
date Thu, 24 Nov 2016 17:06:31 +0000
parents 0a9193dc136b
children 4704e834d0f9
rev   line source
Chris@297 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@297 2
Chris@297 3 /*
Chris@297 4 Sonic Visualiser
Chris@297 5 An audio file viewer and annotation editor.
Chris@297 6 Centre for Digital Music, Queen Mary, University of London.
Chris@297 7 This file copyright 2007 QMUL.
Chris@297 8
Chris@297 9 This program is free software; you can redistribute it and/or
Chris@297 10 modify it under the terms of the GNU General Public License as
Chris@297 11 published by the Free Software Foundation; either version 2 of the
Chris@297 12 License, or (at your option) any later version. See the file
Chris@297 13 COPYING included with this distribution for more information.
Chris@297 14 */
Chris@297 15
Chris@823 16 #include "DecodingWavFileReader.h"
Chris@297 17
Chris@297 18 #include "WavFileReader.h"
Chris@297 19 #include "base/Profiler.h"
Chris@392 20 #include "base/ProgressReporter.h"
Chris@297 21
Chris@297 22 #include <QFileInfo>
Chris@297 23
Chris@1096 24 using namespace std;
Chris@1096 25
Chris@823 26 DecodingWavFileReader::DecodingWavFileReader(FileSource source,
Chris@1097 27 DecodeMode decodeMode,
Chris@920 28 CacheMode mode,
Chris@1040 29 sv_samplerate_t targetRate,
Chris@920 30 bool normalised,
Chris@920 31 ProgressReporter *reporter) :
Chris@920 32 CodedAudioFileReader(mode, targetRate, normalised),
Chris@316 33 m_source(source),
Chris@316 34 m_path(source.getLocalFilename()),
Chris@297 35 m_cancelled(false),
Chris@297 36 m_processed(0),
Chris@297 37 m_completion(0),
Chris@297 38 m_original(0),
Chris@392 39 m_reporter(reporter),
Chris@297 40 m_decodeThread(0)
Chris@297 41 {
Chris@1279 42 SVDEBUG << "DecodingWavFileReader: local path: \"" << m_path
Chris@1279 43 << "\", decode mode: " << decodeMode << " ("
Chris@1279 44 << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded")
Chris@1279 45 << ")" << endl;
Chris@1279 46
Chris@297 47 m_channelCount = 0;
Chris@297 48 m_fileRate = 0;
Chris@297 49
Chris@823 50 Profiler profiler("DecodingWavFileReader::DecodingWavFileReader", true);
Chris@297 51
Chris@316 52 m_original = new WavFileReader(m_path);
Chris@297 53 if (!m_original->isOK()) {
Chris@297 54 m_error = m_original->getError();
Chris@297 55 return;
Chris@297 56 }
Chris@297 57
Chris@297 58 m_channelCount = m_original->getChannelCount();
Chris@297 59 m_fileRate = m_original->getSampleRate();
Chris@297 60
Chris@297 61 initialiseDecodeCache();
Chris@297 62
Chris@1097 63 if (decodeMode == DecodeAtOnce) {
Chris@297 64
Chris@392 65 if (m_reporter) {
Chris@392 66 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@392 67 m_reporter->setMessage
Chris@823 68 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@327 69 }
Chris@297 70
Chris@1038 71 sv_frame_t blockSize = 16384;
Chris@1038 72 sv_frame_t total = m_original->getFrameCount();
Chris@297 73
Chris@1096 74 vector<float> block;
Chris@297 75
Chris@1038 76 for (sv_frame_t i = 0; i < total; i += blockSize) {
Chris@297 77
Chris@1038 78 sv_frame_t count = blockSize;
Chris@297 79 if (i + count > total) count = total - i;
Chris@297 80
Chris@1041 81 block = m_original->getInterleavedFrames(i, count);
Chris@297 82 addBlock(block);
Chris@297 83
Chris@297 84 if (m_cancelled) break;
Chris@297 85 }
Chris@297 86
Chris@297 87 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@398 88 endSerialised();
Chris@297 89
Chris@403 90 if (m_reporter) m_reporter->setProgress(100);
Chris@403 91
Chris@297 92 delete m_original;
Chris@297 93 m_original = 0;
Chris@297 94
Chris@392 95 } else {
Chris@297 96
Chris@392 97 if (m_reporter) m_reporter->setProgress(100);
Chris@297 98
Chris@297 99 m_decodeThread = new DecodeThread(this);
Chris@297 100 m_decodeThread->start();
Chris@297 101 }
Chris@297 102 }
Chris@297 103
Chris@823 104 DecodingWavFileReader::~DecodingWavFileReader()
Chris@297 105 {
Chris@297 106 if (m_decodeThread) {
Chris@297 107 m_cancelled = true;
Chris@297 108 m_decodeThread->wait();
Chris@297 109 delete m_decodeThread;
Chris@297 110 }
Chris@297 111
Chris@297 112 delete m_original;
Chris@297 113 }
Chris@297 114
Chris@297 115 void
Chris@823 116 DecodingWavFileReader::cancelled()
Chris@392 117 {
Chris@392 118 m_cancelled = true;
Chris@392 119 }
Chris@392 120
Chris@392 121 void
Chris@823 122 DecodingWavFileReader::DecodeThread::run()
Chris@297 123 {
Chris@297 124 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@823 125 m_reader->startSerialised("DecodingWavFileReader::Decode");
Chris@297 126 }
Chris@297 127
Chris@1038 128 sv_frame_t blockSize = 16384;
Chris@1038 129 sv_frame_t total = m_reader->m_original->getFrameCount();
Chris@297 130
Chris@1096 131 vector<float> block;
Chris@297 132
Chris@1038 133 for (sv_frame_t i = 0; i < total; i += blockSize) {
Chris@297 134
Chris@1038 135 sv_frame_t count = blockSize;
Chris@297 136 if (i + count > total) count = total - i;
Chris@297 137
Chris@1041 138 block = m_reader->m_original->getInterleavedFrames(i, count);
Chris@297 139 m_reader->addBlock(block);
Chris@297 140
Chris@297 141 if (m_reader->m_cancelled) break;
Chris@297 142 }
Chris@297 143
Chris@297 144 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@297 145 m_reader->m_completion = 100;
Chris@297 146
Chris@297 147 m_reader->endSerialised();
Chris@297 148
Chris@297 149 delete m_reader->m_original;
Chris@297 150 m_reader->m_original = 0;
Chris@297 151 }
Chris@297 152
Chris@297 153 void
Chris@1096 154 DecodingWavFileReader::addBlock(const vector<float> &frames)
Chris@297 155 {
Chris@297 156 addSamplesToDecodeCache(frames);
Chris@297 157
Chris@297 158 m_processed += frames.size();
Chris@297 159
Chris@1038 160 double ratio = double(m_sampleRate) / double(m_fileRate);
Chris@403 161
Chris@1038 162 int progress = int(lrint((double(m_processed) * ratio * 100) /
Chris@1038 163 double(m_original->getFrameCount())));
Chris@297 164
Chris@297 165 if (progress > 99) progress = 99;
Chris@297 166 m_completion = progress;
Chris@297 167
Chris@392 168 if (m_reporter) {
Chris@392 169 m_reporter->setProgress(progress);
Chris@297 170 }
Chris@297 171 }
Chris@297 172
Chris@297 173 void
Chris@1096 174 DecodingWavFileReader::getSupportedExtensions(set<QString> &extensions)
Chris@297 175 {
Chris@297 176 WavFileReader::getSupportedExtensions(extensions);
Chris@297 177 }
Chris@297 178
Chris@316 179 bool
Chris@823 180 DecodingWavFileReader::supportsExtension(QString extension)
Chris@316 181 {
Chris@316 182 return WavFileReader::supportsExtension(extension);
Chris@316 183 }
Chris@297 184
Chris@316 185 bool
Chris@823 186 DecodingWavFileReader::supportsContentType(QString type)
Chris@316 187 {
Chris@316 188 return WavFileReader::supportsContentType(type);
Chris@316 189 }
Chris@316 190
Chris@316 191 bool
Chris@823 192 DecodingWavFileReader::supports(FileSource &source)
Chris@316 193 {
Chris@316 194 return WavFileReader::supports(source);
Chris@316 195 }
Chris@316 196
Chris@316 197