changeset 265:e08f486e8d8c

* Enable threaded decoding for Ogg and MP3 files. Needs some work on reducing updates to the overview widget
author Chris Cannam
date Wed, 06 Jun 2007 16:24:55 +0000
parents 260032c26c4f
children 2268963dabd1
files data/fileio/AudioFileReader.h data/fileio/AudioFileReaderFactory.cpp data/fileio/CodedAudioFileReader.cpp data/fileio/MP3FileReader.cpp data/fileio/MP3FileReader.h data/fileio/OggVorbisFileReader.cpp data/fileio/OggVorbisFileReader.h data/fileio/WavFileReader.h data/model/WaveFileModel.cpp
diffstat 9 files changed, 81 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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() != "") {
--- 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) {
 
--- 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();
--- 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<QString> &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;
--- 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;
--- 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<QString> &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 *);
--- 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<QString> &extensions);
 
+    virtual int getDecodeCompletion() const { return 100; }
+
     bool isUpdating() const { return m_updating; }
 
     void updateFrameCount();
--- 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);
         }
     }