# HG changeset patch # User Chris Cannam # Date 1181147095 0 # Node ID e08f486e8d8ca459bf40064da32360eca34bd61d # Parent 260032c26c4f7d254551001ef5b3b3d87fd69cfb * Enable threaded decoding for Ogg and MP3 files. Needs some work on reducing updates to the overview widget diff -r 260032c26c4f -r e08f486e8d8c data/fileio/AudioFileReader.h --- a/data/fileio/AudioFileReader.h Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/AudioFileReader.h Wed Jun 06 16:24:55 2007 +0000 @@ -42,6 +42,10 @@ virtual void getInterleavedFrames(size_t start, size_t count, SampleBlock &frames) const = 0; + // only subclasses that do not know exactly how long the audio + // file is until it's been completely decoded should implement this + virtual int getDecodeCompletion() const { return 100; } // % + virtual bool isUpdating() const { return false; } signals: diff -r 260032c26c4f -r e08f486e8d8c data/fileio/AudioFileReaderFactory.cpp --- a/data/fileio/AudioFileReaderFactory.cpp Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/AudioFileReaderFactory.cpp Wed Jun 06 16:24:55 2007 +0000 @@ -74,7 +74,7 @@ if (extensions.find(ext) != extensions.end()) { reader = new MP3FileReader (path, - MP3FileReader::DecodeAtOnce, + MP3FileReader::DecodeThreaded, MP3FileReader::CacheInTemporaryFile); } } @@ -87,7 +87,7 @@ if (extensions.find(ext) != extensions.end()) { reader = new OggVorbisFileReader (path, - OggVorbisFileReader::DecodeAtOnce, + OggVorbisFileReader::DecodeThreaded, OggVorbisFileReader::CacheInTemporaryFile); } } @@ -124,7 +124,7 @@ #ifdef HAVE_FISHSOUND reader = new OggVorbisFileReader (path, - OggVorbisFileReader::DecodeAtOnce, + OggVorbisFileReader::DecodeThreaded, OggVorbisFileReader::CacheInTemporaryFile); if (reader->isOK()) return reader; if (reader->getError() != "") { @@ -141,7 +141,7 @@ #ifdef HAVE_MAD reader = new MP3FileReader (path, - MP3FileReader::DecodeAtOnce, + MP3FileReader::DecodeThreaded, MP3FileReader::CacheInTemporaryFile); if (reader->isOK()) return reader; if (reader->getError() != "") { diff -r 260032c26c4f -r e08f486e8d8c data/fileio/CodedAudioFileReader.cpp --- a/data/fileio/CodedAudioFileReader.cpp Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/CodedAudioFileReader.cpp Wed Jun 06 16:24:55 2007 +0000 @@ -73,10 +73,27 @@ m_cacheFileWritePtr = sf_open(m_cacheFileName.toLocal8Bit(), SFM_WRITE, &fileInfo); - if (!m_cacheFileWritePtr) { + if (m_cacheFileWritePtr) { + + //!!! really want to do this now only if we're in a + //threaded mode -- creating the reader later if we're + //not threaded -- but we don't have access to that + //information here + + m_cacheFileReader = new WavFileReader(m_cacheFileName); + + if (!m_cacheFileReader->isOK()) { + std::cerr << "ERROR: CodedAudioFileReader::initialiseDecodeCache: Failed to construct WAV file reader for temporary file: " << m_cacheFileReader->getError().toStdString() << std::endl; + delete m_cacheFileReader; + m_cacheFileReader = 0; + m_cacheMode = CacheInMemory; + sf_close(m_cacheFileWritePtr); + } + } else { std::cerr << "CodedAudioFileReader::initialiseDecodeCache: failed to open cache file \"" << m_cacheFileName.toStdString() << "\" (" << m_channelCount << " channels, sample rate " << m_sampleRate << " for writing, falling back to in-memory cache" << std::endl; m_cacheMode = CacheInMemory; } + } catch (DirectoryCreationFailed f) { std::cerr << "CodedAudioFileReader::initialiseDecodeCache: failed to create temporary directory! Falling back to in-memory cache" << std::endl; m_cacheMode = CacheInMemory; @@ -112,6 +129,11 @@ m_cacheWriteBufferSize); m_cacheWriteBufferIndex = 0; + + if (m_cacheWriteBufferIndex % 10240 == 0 && + m_cacheFileReader) { + m_cacheFileReader->updateFrameCount(); + } } break; @@ -154,13 +176,16 @@ sf_close(m_cacheFileWritePtr); m_cacheFileWritePtr = 0; + m_cacheFileReader->updateFrameCount(); +/* m_cacheFileReader = new WavFileReader(m_cacheFileName); if (!m_cacheFileReader->isOK()) { std::cerr << "ERROR: CodedAudioFileReader::finishDecodeCache: Failed to construct WAV file reader for temporary file: " << m_cacheFileReader->getError().toStdString() << std::endl; delete m_cacheFileReader; m_cacheFileReader = 0; - } + }*/ + break; case CacheInMemory: @@ -176,7 +201,10 @@ //!!! we want to ensure this doesn't require a lock -- at the // moment it does need one, but it doesn't have one... - if (!m_initialised) return; + if (!m_initialised) { + std::cerr << "CodedAudioFileReader::getInterleavedFrames: not initialised" << std::endl; + return; + } switch (m_cacheMode) { diff -r 260032c26c4f -r e08f486e8d8c data/fileio/MP3FileReader.cpp --- a/data/fileio/MP3FileReader.cpp Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/MP3FileReader.cpp Wed Jun 06 16:24:55 2007 +0000 @@ -42,6 +42,7 @@ m_bitrateDenom = 0; m_frameCount = 0; m_cancelled = false; + m_completion = 0; m_done = false; m_progress = 0; @@ -127,6 +128,7 @@ MP3FileReader::~MP3FileReader() { if (m_decodeThread) { + m_cancelled = true; m_decodeThread->wait(); delete m_decodeThread; } @@ -145,6 +147,7 @@ if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); m_reader->m_done = true; + m_reader->m_completion = 100; } bool @@ -210,10 +213,11 @@ double duration = double(m_fileSize * 8) / bitrate; double elapsed = double(m_frameCount) / m_sampleRate; double percent = ((elapsed * 100.0) / duration); + int progress = int(percent); + if (progress < 1) progress = 1; + if (progress > 99) progress = 99; + m_completion = progress; if (m_progress) { - int progress = int(percent); - if (progress < 1) progress = 1; - if (progress > 99) progress = 99; if (progress > m_progress->value()) { m_progress->setValue(progress); m_progress->show(); diff -r 260032c26c4f -r e08f486e8d8c data/fileio/MP3FileReader.h --- a/data/fileio/MP3FileReader.h Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/MP3FileReader.h Wed Jun 06 16:24:55 2007 +0000 @@ -42,6 +42,8 @@ static void getSupportedExtensions(std::set &extensions); + virtual int getDecodeCompletion() const { return m_completion; } + virtual bool isUpdating() const { return m_decodeThread && m_decodeThread->isRunning(); } @@ -52,6 +54,7 @@ size_t m_fileSize; double m_bitrateNum; size_t m_bitrateDenom; + int m_completion; bool m_done; unsigned char *m_filebuffer; diff -r 260032c26c4f -r e08f486e8d8c data/fileio/OggVorbisFileReader.cpp --- a/data/fileio/OggVorbisFileReader.cpp Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/OggVorbisFileReader.cpp Wed Jun 06 16:24:55 2007 +0000 @@ -41,6 +41,7 @@ m_fileSize(0), m_bytesRead(0), m_cancelled(false), + m_completion(0), m_decodeThread(0) { m_frameCount = 0; @@ -102,6 +103,7 @@ { std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl; if (m_decodeThread) { + m_cancelled = true; m_decodeThread->wait(); delete m_decodeThread; } @@ -118,6 +120,7 @@ m_reader->m_oggz = 0; if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); + m_reader->m_completion = 100; } int @@ -130,13 +133,15 @@ fish_sound_decode(fs, packet->packet, packet->bytes); reader->m_bytesRead += packet->bytes; + + // The number of bytes read by this function is smaller than + // the file size because of the packet headers + int progress = lrint(double(reader->m_bytesRead) * 114 / + double(reader->m_fileSize)); + if (progress > 99) progress = 99; + reader->m_completion = progress; if (reader->m_fileSize > 0 && reader->m_progress) { - // The number of bytes read by this function is smaller than - // the file size because of the packet headers - int progress = lrint(double(reader->m_bytesRead) * 114 / - double(reader->m_fileSize)); - if (progress > 99) progress = 99; if (progress > reader->m_progress->value()) { reader->m_progress->setValue(progress); reader->m_progress->show(); @@ -146,7 +151,7 @@ reader->m_cancelled = true; } } - } + } if (reader->m_cancelled) return 1; return 0; diff -r 260032c26c4f -r e08f486e8d8c data/fileio/OggVorbisFileReader.h --- a/data/fileio/OggVorbisFileReader.h Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/OggVorbisFileReader.h Wed Jun 06 16:24:55 2007 +0000 @@ -45,6 +45,8 @@ static void getSupportedExtensions(std::set &extensions); + virtual int getDecodeCompletion() const { return m_completion; } + virtual bool isUpdating() const { return m_decodeThread && m_decodeThread->isRunning(); } @@ -59,6 +61,7 @@ size_t m_fileSize; size_t m_bytesRead; bool m_cancelled; + int m_completion; static int readPacket(OGGZ *, ogg_packet *, long, void *); static int acceptFrames(FishSound *, float **, long, void *); diff -r 260032c26c4f -r e08f486e8d8c data/fileio/WavFileReader.h --- a/data/fileio/WavFileReader.h Fri Jun 01 13:56:35 2007 +0000 +++ b/data/fileio/WavFileReader.h Wed Jun 06 16:24:55 2007 +0000 @@ -40,6 +40,8 @@ static void getSupportedExtensions(std::set &extensions); + virtual int getDecodeCompletion() const { return 100; } + bool isUpdating() const { return m_updating; } void updateFrameCount(); diff -r 260032c26c4f -r e08f486e8d8c data/model/WaveFileModel.cpp --- a/data/model/WaveFileModel.cpp Fri Jun 01 13:56:35 2007 +0000 +++ b/data/model/WaveFileModel.cpp Wed Jun 06 16:24:55 2007 +0000 @@ -96,7 +96,15 @@ { bool ready = (isOK() && (m_fillThread == 0)); double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame()); - if (completion) *completion = int(c * 100.0 + 0.01); + if (completion) { + *completion = int(c * 100.0 + 0.01); + if (m_reader) { + int decodeCompletion = m_reader->getDecodeCompletion(); +// std::cerr << "decodeCompletion " << decodeCompletion << ", completion " << *completion << std::endl; +// if (decodeCompletion < *completion) *completion = decodeCompletion; + if (decodeCompletion < 100) *completion = decodeCompletion; + } + } #ifdef DEBUG_WAVE_FILE_MODEL std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl; #endif @@ -486,10 +494,14 @@ while (frame < m_frameCount) { +// std::cerr << "WaveFileModel::fill inner loop: frame = " << frame << ", count = " << m_frameCount << ", blocksize " << readBlockSize << std::endl; + if (updating && (frame + readBlockSize > m_frameCount)) break; m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block); +// std::cerr << "block is " << block.size() << std::endl; + for (size_t i = 0; i < readBlockSize; ++i) { if (channels * i + channels > block.size()) break; @@ -538,9 +550,12 @@ m_fillExtent = frame; } +// std::cerr << "WaveFileModel: inner loop ended" << std::endl; + first = false; if (m_model.m_exiting) break; if (updating) { +// std::cerr << "sleeping..." << std::endl; sleep(1); } }