Chris@297: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@297: 
Chris@297: /*
Chris@297:     Sonic Visualiser
Chris@297:     An audio file viewer and annotation editor.
Chris@297:     Centre for Digital Music, Queen Mary, University of London.
Chris@297:     This file copyright 2007 QMUL.
Chris@297:     
Chris@297:     This program is free software; you can redistribute it and/or
Chris@297:     modify it under the terms of the GNU General Public License as
Chris@297:     published by the Free Software Foundation; either version 2 of the
Chris@297:     License, or (at your option) any later version.  See the file
Chris@297:     COPYING included with this distribution for more information.
Chris@297: */
Chris@297: 
Chris@823: #include "DecodingWavFileReader.h"
Chris@297: 
Chris@297: #include "WavFileReader.h"
Chris@297: #include "base/Profiler.h"
Chris@392: #include "base/ProgressReporter.h"
Chris@297: 
Chris@297: #include <QFileInfo>
Chris@297: 
Chris@1096: using namespace std;
Chris@1096: 
Chris@823: DecodingWavFileReader::DecodingWavFileReader(FileSource source,
Chris@1097:                                              DecodeMode decodeMode,
Chris@920:                                              CacheMode mode,
Chris@1040:                                              sv_samplerate_t targetRate,
Chris@920:                                              bool normalised,
Chris@920:                                              ProgressReporter *reporter) :
Chris@920:     CodedAudioFileReader(mode, targetRate, normalised),
Chris@316:     m_source(source),
Chris@316:     m_path(source.getLocalFilename()),
Chris@297:     m_cancelled(false),
Chris@297:     m_processed(0),
Chris@297:     m_completion(0),
Chris@1582:     m_original(nullptr),
Chris@392:     m_reporter(reporter),
Chris@1582:     m_decodeThread(nullptr)
Chris@297: {
Chris@1279:     SVDEBUG << "DecodingWavFileReader: local path: \"" << m_path
Chris@1279:             << "\", decode mode: " << decodeMode << " ("
Chris@1279:             << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded")
Chris@1279:             << ")" << endl;
Chris@1279: 
Chris@297:     m_channelCount = 0;
Chris@297:     m_fileRate = 0;
Chris@297: 
Chris@1295:     Profiler profiler("DecodingWavFileReader::DecodingWavFileReader");
Chris@297: 
Chris@316:     m_original = new WavFileReader(m_path);
Chris@297:     if (!m_original->isOK()) {
Chris@297:         m_error = m_original->getError();
Chris@297:         return;
Chris@297:     }
Chris@297: 
Chris@297:     m_channelCount = m_original->getChannelCount();
Chris@297:     m_fileRate = m_original->getSampleRate();
Chris@297: 
Chris@1592:     m_title = m_original->getTitle();
Chris@1592:     m_maker = m_original->getMaker();
Chris@1592: 
Chris@297:     initialiseDecodeCache();
Chris@297: 
Chris@1097:     if (decodeMode == DecodeAtOnce) {
Chris@297: 
Chris@392:         if (m_reporter) {
Chris@392:             connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@392:             m_reporter->setMessage
Chris@823:                 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@327:         }
Chris@297: 
Chris@1038:         sv_frame_t blockSize = 16384;
Chris@1038:         sv_frame_t total = m_original->getFrameCount();
Chris@297: 
Chris@1326:         floatvec_t block;
Chris@297: 
Chris@1038:         for (sv_frame_t i = 0; i < total; i += blockSize) {
Chris@297: 
Chris@1038:             sv_frame_t count = blockSize;
Chris@297:             if (i + count > total) count = total - i;
Chris@297: 
Chris@1041:             block = m_original->getInterleavedFrames(i, count);
Chris@297:             addBlock(block);
Chris@297: 
Chris@297:             if (m_cancelled) break;
Chris@297:         }
Chris@297: 
Chris@297:         if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@398:         endSerialised();
Chris@297: 
Chris@403:         if (m_reporter) m_reporter->setProgress(100);
Chris@403: 
Chris@297:         delete m_original;
Chris@1582:         m_original = nullptr;
Chris@297: 
Chris@392:     } else {
Chris@297: 
Chris@392:         if (m_reporter) m_reporter->setProgress(100);
Chris@297: 
Chris@297:         m_decodeThread = new DecodeThread(this);
Chris@297:         m_decodeThread->start();
Chris@297:     }
Chris@297: }
Chris@297: 
Chris@823: DecodingWavFileReader::~DecodingWavFileReader()
Chris@297: {
Chris@297:     if (m_decodeThread) {
Chris@297:         m_cancelled = true;
Chris@297:         m_decodeThread->wait();
Chris@297:         delete m_decodeThread;
Chris@297:     }
Chris@297:     
Chris@297:     delete m_original;
Chris@297: }
Chris@297: 
Chris@297: void
Chris@823: DecodingWavFileReader::cancelled()
Chris@392: {
Chris@392:     m_cancelled = true;
Chris@392: }
Chris@392: 
Chris@392: void
Chris@823: DecodingWavFileReader::DecodeThread::run()
Chris@297: {
Chris@297:     if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@823:         m_reader->startSerialised("DecodingWavFileReader::Decode");
Chris@297:     }
Chris@297: 
Chris@1038:     sv_frame_t blockSize = 16384;
Chris@1038:     sv_frame_t total = m_reader->m_original->getFrameCount();
Chris@297:     
Chris@1326:     floatvec_t block;
Chris@297:     
Chris@1038:     for (sv_frame_t i = 0; i < total; i += blockSize) {
Chris@297:         
Chris@1038:         sv_frame_t count = blockSize;
Chris@297:         if (i + count > total) count = total - i;
Chris@297:         
Chris@1041:         block = m_reader->m_original->getInterleavedFrames(i, count);
Chris@297:         m_reader->addBlock(block);
Chris@297: 
Chris@297:         if (m_reader->m_cancelled) break;
Chris@297:     }
Chris@297:     
Chris@297:     if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@297:     m_reader->m_completion = 100;
Chris@297: 
Chris@297:     m_reader->endSerialised();
Chris@297: 
Chris@297:     delete m_reader->m_original;
Chris@1582:     m_reader->m_original = nullptr;
Chris@297: } 
Chris@297: 
Chris@297: void
Chris@1326: DecodingWavFileReader::addBlock(const floatvec_t &frames)
Chris@297: {
Chris@297:     addSamplesToDecodeCache(frames);
Chris@297: 
Chris@297:     m_processed += frames.size();
Chris@297: 
Chris@1038:     double ratio = double(m_sampleRate) / double(m_fileRate);
Chris@403: 
Chris@1038:     int progress = int(lrint((double(m_processed) * ratio * 100) /
Chris@1038:                              double(m_original->getFrameCount())));
Chris@297: 
Chris@297:     if (progress > 99) progress = 99;
Chris@297:     m_completion = progress;
Chris@297:     
Chris@392:     if (m_reporter) {
Chris@392:         m_reporter->setProgress(progress);
Chris@297:     }
Chris@297: }
Chris@297: 
Chris@297: void
Chris@1096: DecodingWavFileReader::getSupportedExtensions(set<QString> &extensions)
Chris@297: {
Chris@297:     WavFileReader::getSupportedExtensions(extensions);
Chris@297: }
Chris@297: 
Chris@316: bool
Chris@823: DecodingWavFileReader::supportsExtension(QString extension)
Chris@316: {
Chris@316:     return WavFileReader::supportsExtension(extension);
Chris@316: }
Chris@297: 
Chris@316: bool
Chris@823: DecodingWavFileReader::supportsContentType(QString type)
Chris@316: {
Chris@316:     return WavFileReader::supportsContentType(type);
Chris@316: }
Chris@316: 
Chris@316: bool
Chris@823: DecodingWavFileReader::supports(FileSource &source)
Chris@316: {
Chris@316:     return WavFileReader::supports(source);
Chris@316: }
Chris@316: 
Chris@316: