changeset 825:69bde159744f tonioni

Merge from default branch
author Chris Cannam
date Wed, 17 Jul 2013 15:41:20 +0100
parents 54829c1e155e (current diff) f0558e69a074 (diff)
children f9f178efd6b8
files data/fileio/ResamplingWavFileReader.cpp data/fileio/ResamplingWavFileReader.h
diffstat 9 files changed, 342 insertions(+), 299 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/AudioFileReader.h	Fri Jul 12 13:10:28 2013 +0100
+++ b/data/fileio/AudioFileReader.h	Wed Jul 17 15:41:20 2013 +0100
@@ -65,6 +65,13 @@
     typedef std::map<QString, QString> TagMap;
     virtual TagMap getTags() const { return TagMap(); }
 
+    /**
+     * Return true if this file supports fast seek and random
+     * access. Typically this will be true for uncompressed formats
+     * and false for compressed ones.
+     */
+    virtual bool isQuicklySeekable() const = 0;
+
     /** 
      * Return interleaved samples for count frames from index start.
      * The resulting sample block will contain count *
--- a/data/fileio/AudioFileReaderFactory.cpp	Fri Jul 12 13:10:28 2013 +0100
+++ b/data/fileio/AudioFileReaderFactory.cpp	Wed Jul 17 15:41:20 2013 +0100
@@ -16,7 +16,7 @@
 #include "AudioFileReaderFactory.h"
 
 #include "WavFileReader.h"
-#include "ResamplingWavFileReader.h"
+#include "DecodingWavFileReader.h"
 #include "OggVorbisFileReader.h"
 #include "MP3FileReader.h"
 #include "QuickTimeFileReader.h"
@@ -98,20 +98,22 @@
 
         reader = new WavFileReader(source);
 
-        if (targetRate != 0 &&
-            reader->isOK() &&
-            reader->getSampleRate() != targetRate) {
+        int fileRate = reader->getSampleRate();
 
-            SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", creating resampling reader" << endl;
+        if (reader->isOK() &&
+            (!reader->isQuicklySeekable() ||
+             (targetRate != 0 && fileRate != targetRate))) {
+
+            SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", seekable " << reader->isQuicklySeekable() << ", creating decoding reader" << endl;
 
             delete reader;
-            reader = new ResamplingWavFileReader
+            reader = new DecodingWavFileReader
                 (source,
                  threading ?
-                 ResamplingWavFileReader::ResampleThreaded :
-                 ResamplingWavFileReader::ResampleAtOnce,
-                 ResamplingWavFileReader::CacheInTemporaryFile,
-                 targetRate,
+                 DecodingWavFileReader::ResampleThreaded :
+                 DecodingWavFileReader::ResampleAtOnce,
+                 DecodingWavFileReader::CacheInTemporaryFile,
+                 targetRate ? targetRate : fileRate,
                  reporter);
             if (!reader->isOK()) {
                 delete reader;
@@ -209,20 +211,22 @@
 
         reader = new WavFileReader(source);
 
-        if (targetRate != 0 &&
-            reader->isOK() &&
-            reader->getSampleRate() != targetRate) {
+        int fileRate = reader->getSampleRate();
 
-            SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", creating resampling reader" << endl;
+        if (reader->isOK() &&
+            (!reader->isQuicklySeekable() ||
+             (targetRate != 0 && fileRate != targetRate))) {
+
+            SVDEBUG << "AudioFileReaderFactory::createReader: WAV file rate: " << reader->getSampleRate() << ", seekable " << reader->isQuicklySeekable() << ", creating decoding reader" << endl;
 
             delete reader;
-            reader = new ResamplingWavFileReader
+            reader = new DecodingWavFileReader
                 (source,
                  threading ?
-                 ResamplingWavFileReader::ResampleThreaded :
-                 ResamplingWavFileReader::ResampleAtOnce,
-                 ResamplingWavFileReader::CacheInTemporaryFile,
-                 targetRate,
+                 DecodingWavFileReader::ResampleThreaded :
+                 DecodingWavFileReader::ResampleAtOnce,
+                 DecodingWavFileReader::CacheInTemporaryFile,
+                 targetRate ? targetRate : fileRate,
                  reporter);
         }
 
--- a/data/fileio/CodedAudioFileReader.h	Fri Jul 12 13:10:28 2013 +0100
+++ b/data/fileio/CodedAudioFileReader.h	Wed Jul 17 15:41:20 2013 +0100
@@ -43,6 +43,9 @@
 
     virtual size_t getNativeRate() const { return m_fileRate; }
 
+    /// Intermediate cache means all CodedAudioFileReaders are quickly seekable
+    virtual bool isQuicklySeekable() const { return true; }
+
 signals:
     void progress(int);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/DecodingWavFileReader.cpp	Wed Jul 17 15:41:20 2013 +0100
@@ -0,0 +1,192 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2007 QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "DecodingWavFileReader.h"
+
+#include "WavFileReader.h"
+#include "base/Profiler.h"
+#include "base/ProgressReporter.h"
+
+#include <QFileInfo>
+
+DecodingWavFileReader::DecodingWavFileReader(FileSource source,
+						 ResampleMode resampleMode,
+						 CacheMode mode,
+						 size_t targetRate,
+                                                 ProgressReporter *reporter) :
+    CodedAudioFileReader(mode, targetRate),
+    m_source(source),
+    m_path(source.getLocalFilename()),
+    m_cancelled(false),
+    m_processed(0),
+    m_completion(0),
+    m_original(0),
+    m_reporter(reporter),
+    m_decodeThread(0)
+{
+    m_channelCount = 0;
+    m_fileRate = 0;
+
+    SVDEBUG << "DecodingWavFileReader::DecodingWavFileReader(\""
+              << m_path << "\"): rate " << targetRate << endl;
+
+    Profiler profiler("DecodingWavFileReader::DecodingWavFileReader", true);
+
+    m_original = new WavFileReader(m_path);
+    if (!m_original->isOK()) {
+        m_error = m_original->getError();
+        return;
+    }
+
+    m_channelCount = m_original->getChannelCount();
+    m_fileRate = m_original->getSampleRate();
+
+    initialiseDecodeCache();
+
+    if (resampleMode == ResampleAtOnce) {
+
+        if (m_reporter) {
+            connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
+            m_reporter->setMessage
+                (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
+        }
+
+        size_t blockSize = 16384;
+        size_t total = m_original->getFrameCount();
+
+        SampleBlock block;
+
+        for (size_t i = 0; i < total; i += blockSize) {
+
+            size_t count = blockSize;
+            if (i + count > total) count = total - i;
+
+            m_original->getInterleavedFrames(i, count, block);
+            addBlock(block);
+
+            if (m_cancelled) break;
+        }
+
+        if (isDecodeCacheInitialised()) finishDecodeCache();
+        endSerialised();
+
+        if (m_reporter) m_reporter->setProgress(100);
+
+        delete m_original;
+        m_original = 0;
+
+    } else {
+
+        if (m_reporter) m_reporter->setProgress(100);
+
+        m_decodeThread = new DecodeThread(this);
+        m_decodeThread->start();
+    }
+}
+
+DecodingWavFileReader::~DecodingWavFileReader()
+{
+    if (m_decodeThread) {
+        m_cancelled = true;
+        m_decodeThread->wait();
+        delete m_decodeThread;
+    }
+    
+    delete m_original;
+}
+
+void
+DecodingWavFileReader::cancelled()
+{
+    m_cancelled = true;
+}
+
+void
+DecodingWavFileReader::DecodeThread::run()
+{
+    if (m_reader->m_cacheMode == CacheInTemporaryFile) {
+        m_reader->startSerialised("DecodingWavFileReader::Decode");
+    }
+
+    size_t blockSize = 16384;
+    size_t total = m_reader->m_original->getFrameCount();
+    
+    SampleBlock block;
+    
+    for (size_t i = 0; i < total; i += blockSize) {
+        
+        size_t count = blockSize;
+        if (i + count > total) count = total - i;
+        
+        m_reader->m_original->getInterleavedFrames(i, count, block);
+        m_reader->addBlock(block);
+
+        if (m_reader->m_cancelled) break;
+    }
+    
+    if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
+    m_reader->m_completion = 100;
+
+    m_reader->endSerialised();
+
+    delete m_reader->m_original;
+    m_reader->m_original = 0;
+} 
+
+void
+DecodingWavFileReader::addBlock(const SampleBlock &frames)
+{
+    addSamplesToDecodeCache(frames);
+
+    m_processed += frames.size();
+
+    float ratio = float(m_sampleRate) / float(m_fileRate);
+
+    int progress = lrint((float(m_processed) * ratio * 100) /
+                         float(m_original->getFrameCount()));
+
+    if (progress > 99) progress = 99;
+    m_completion = progress;
+    
+    if (m_reporter) {
+        m_reporter->setProgress(progress);
+    }
+}
+
+void
+DecodingWavFileReader::getSupportedExtensions(std::set<QString> &extensions)
+{
+    WavFileReader::getSupportedExtensions(extensions);
+}
+
+bool
+DecodingWavFileReader::supportsExtension(QString extension)
+{
+    return WavFileReader::supportsExtension(extension);
+}
+
+bool
+DecodingWavFileReader::supportsContentType(QString type)
+{
+    return WavFileReader::supportsContentType(type);
+}
+
+bool
+DecodingWavFileReader::supports(FileSource &source)
+{
+    return WavFileReader::supports(source);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/DecodingWavFileReader.h	Wed Jul 17 15:41:20 2013 +0100
@@ -0,0 +1,87 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2007 QMUL.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef _DECODING_WAV_FILE_READER_H_
+#define _DECODING_WAV_FILE_READER_H_
+
+#include "CodedAudioFileReader.h"
+
+#include "base/Thread.h"
+
+#include <set>
+
+class WavFileReader;
+class ProgressReporter;
+
+class DecodingWavFileReader : public CodedAudioFileReader
+{
+    Q_OBJECT
+public:
+    enum ResampleMode {
+        ResampleAtOnce, // resample the file on construction, with progress dialog
+        ResampleThreaded // resample in a background thread after construction
+    };
+
+    DecodingWavFileReader(FileSource source,
+                            ResampleMode resampleMode,
+                            CacheMode cacheMode,
+                            size_t targetRate = 0,
+                            ProgressReporter *reporter = 0);
+    virtual ~DecodingWavFileReader();
+
+    virtual QString getError() const { return m_error; }
+    virtual QString getLocation() const { return m_source.getLocation(); }
+    static void getSupportedExtensions(std::set<QString> &extensions);
+    static bool supportsExtension(QString ext);
+    static bool supportsContentType(QString type);
+    static bool supports(FileSource &source);
+
+    virtual int getDecodeCompletion() const { return m_completion; }
+
+    virtual bool isUpdating() const {
+        return m_decodeThread && m_decodeThread->isRunning();
+    }
+
+public slots:
+    void cancelled();
+
+protected:
+    FileSource m_source;
+    QString m_path;
+    QString m_error;
+    bool m_cancelled;
+    size_t m_processed;
+    int m_completion;
+
+    WavFileReader *m_original;
+    ProgressReporter *m_reporter;
+
+    void addBlock(const SampleBlock &frames);
+    
+    class DecodeThread : public Thread
+    {
+    public:
+        DecodeThread(DecodingWavFileReader *reader) : m_reader(reader) { }
+        virtual void run();
+
+    protected:
+        DecodingWavFileReader *m_reader;
+    };
+
+    DecodeThread *m_decodeThread;
+};
+
+#endif
+
--- a/data/fileio/ResamplingWavFileReader.cpp	Fri Jul 12 13:10:28 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2007 QMUL.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#include "ResamplingWavFileReader.h"
-
-#include "WavFileReader.h"
-#include "base/Profiler.h"
-#include "base/ProgressReporter.h"
-
-#include <QFileInfo>
-
-ResamplingWavFileReader::ResamplingWavFileReader(FileSource source,
-						 ResampleMode resampleMode,
-						 CacheMode mode,
-						 size_t targetRate,
-                                                 ProgressReporter *reporter) :
-    CodedAudioFileReader(mode, targetRate),
-    m_source(source),
-    m_path(source.getLocalFilename()),
-    m_cancelled(false),
-    m_processed(0),
-    m_completion(0),
-    m_original(0),
-    m_reporter(reporter),
-    m_decodeThread(0)
-{
-    m_channelCount = 0;
-    m_fileRate = 0;
-
-    SVDEBUG << "ResamplingWavFileReader::ResamplingWavFileReader(\""
-              << m_path << "\"): rate " << targetRate << endl;
-
-    Profiler profiler("ResamplingWavFileReader::ResamplingWavFileReader", true);
-
-    m_original = new WavFileReader(m_path);
-    if (!m_original->isOK()) {
-        m_error = m_original->getError();
-        return;
-    }
-
-    m_channelCount = m_original->getChannelCount();
-    m_fileRate = m_original->getSampleRate();
-
-    initialiseDecodeCache();
-
-    if (resampleMode == ResampleAtOnce) {
-
-        if (m_reporter) {
-            connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
-            m_reporter->setMessage
-                (tr("Resampling %1...").arg(QFileInfo(m_path).fileName()));
-        }
-
-        size_t blockSize = 16384;
-        size_t total = m_original->getFrameCount();
-
-        SampleBlock block;
-
-        for (size_t i = 0; i < total; i += blockSize) {
-
-            size_t count = blockSize;
-            if (i + count > total) count = total - i;
-
-            m_original->getInterleavedFrames(i, count, block);
-            addBlock(block);
-
-            if (m_cancelled) break;
-        }
-
-        if (isDecodeCacheInitialised()) finishDecodeCache();
-        endSerialised();
-
-        if (m_reporter) m_reporter->setProgress(100);
-
-        delete m_original;
-        m_original = 0;
-
-    } else {
-
-        if (m_reporter) m_reporter->setProgress(100);
-
-        m_decodeThread = new DecodeThread(this);
-        m_decodeThread->start();
-    }
-}
-
-ResamplingWavFileReader::~ResamplingWavFileReader()
-{
-    if (m_decodeThread) {
-        m_cancelled = true;
-        m_decodeThread->wait();
-        delete m_decodeThread;
-    }
-    
-    delete m_original;
-}
-
-void
-ResamplingWavFileReader::cancelled()
-{
-    m_cancelled = true;
-}
-
-void
-ResamplingWavFileReader::DecodeThread::run()
-{
-    if (m_reader->m_cacheMode == CacheInTemporaryFile) {
-        m_reader->startSerialised("ResamplingWavFileReader::Decode");
-    }
-
-    size_t blockSize = 16384;
-    size_t total = m_reader->m_original->getFrameCount();
-    
-    SampleBlock block;
-    
-    for (size_t i = 0; i < total; i += blockSize) {
-        
-        size_t count = blockSize;
-        if (i + count > total) count = total - i;
-        
-        m_reader->m_original->getInterleavedFrames(i, count, block);
-        m_reader->addBlock(block);
-
-        if (m_reader->m_cancelled) break;
-    }
-    
-    if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
-    m_reader->m_completion = 100;
-
-    m_reader->endSerialised();
-
-    delete m_reader->m_original;
-    m_reader->m_original = 0;
-} 
-
-void
-ResamplingWavFileReader::addBlock(const SampleBlock &frames)
-{
-    addSamplesToDecodeCache(frames);
-
-    m_processed += frames.size();
-
-    float ratio = float(m_sampleRate) / float(m_fileRate);
-
-    int progress = lrint((float(m_processed) * ratio * 100) /
-                         float(m_original->getFrameCount()));
-
-    if (progress > 99) progress = 99;
-    m_completion = progress;
-    
-    if (m_reporter) {
-        m_reporter->setProgress(progress);
-    }
-}
-
-void
-ResamplingWavFileReader::getSupportedExtensions(std::set<QString> &extensions)
-{
-    WavFileReader::getSupportedExtensions(extensions);
-}
-
-bool
-ResamplingWavFileReader::supportsExtension(QString extension)
-{
-    return WavFileReader::supportsExtension(extension);
-}
-
-bool
-ResamplingWavFileReader::supportsContentType(QString type)
-{
-    return WavFileReader::supportsContentType(type);
-}
-
-bool
-ResamplingWavFileReader::supports(FileSource &source)
-{
-    return WavFileReader::supports(source);
-}
-
-
--- a/data/fileio/ResamplingWavFileReader.h	Fri Jul 12 13:10:28 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
-
-/*
-    Sonic Visualiser
-    An audio file viewer and annotation editor.
-    Centre for Digital Music, Queen Mary, University of London.
-    This file copyright 2007 QMUL.
-    
-    This program is free software; you can redistribute it and/or
-    modify it under the terms of the GNU General Public License as
-    published by the Free Software Foundation; either version 2 of the
-    License, or (at your option) any later version.  See the file
-    COPYING included with this distribution for more information.
-*/
-
-#ifndef _RESAMPLING_WAV_FILE_READER_H_
-#define _RESAMPLING_WAV_FILE_READER_H_
-
-#include "CodedAudioFileReader.h"
-
-#include "base/Thread.h"
-
-#include <set>
-
-class WavFileReader;
-class ProgressReporter;
-
-class ResamplingWavFileReader : public CodedAudioFileReader
-{
-    Q_OBJECT
-public:
-    enum ResampleMode {
-        ResampleAtOnce, // resample the file on construction, with progress dialog
-        ResampleThreaded // resample in a background thread after construction
-    };
-
-    ResamplingWavFileReader(FileSource source,
-                            ResampleMode resampleMode,
-                            CacheMode cacheMode,
-                            size_t targetRate = 0,
-                            ProgressReporter *reporter = 0);
-    virtual ~ResamplingWavFileReader();
-
-    virtual QString getError() const { return m_error; }
-    virtual QString getLocation() const { return m_source.getLocation(); }
-    static void getSupportedExtensions(std::set<QString> &extensions);
-    static bool supportsExtension(QString ext);
-    static bool supportsContentType(QString type);
-    static bool supports(FileSource &source);
-
-    virtual int getDecodeCompletion() const { return m_completion; }
-
-    virtual bool isUpdating() const {
-        return m_decodeThread && m_decodeThread->isRunning();
-    }
-
-public slots:
-    void cancelled();
-
-protected:
-    FileSource m_source;
-    QString m_path;
-    QString m_error;
-    bool m_cancelled;
-    size_t m_processed;
-    int m_completion;
-
-    WavFileReader *m_original;
-    ProgressReporter *m_reporter;
-
-    void addBlock(const SampleBlock &frames);
-    
-    class DecodeThread : public Thread
-    {
-    public:
-        DecodeThread(ResamplingWavFileReader *reader) : m_reader(reader) { }
-        virtual void run();
-
-    protected:
-        ResamplingWavFileReader *m_reader;
-    };
-
-    DecodeThread *m_decodeThread;
-};
-
-#endif
-
--- a/data/fileio/WavFileReader.cpp	Fri Jul 12 13:10:28 2013 +0100
+++ b/data/fileio/WavFileReader.cpp	Wed Jul 17 15:41:20 2013 +0100
@@ -24,6 +24,7 @@
     m_file(0),
     m_source(source),
     m_path(source.getLocalFilename()),
+    m_seekable(false),
     m_buffer(0),
     m_bufsiz(0),
     m_lastStart(0),
@@ -54,12 +55,26 @@
     }
 
     if (m_fileInfo.channels > 0) {
+
         m_frameCount = m_fileInfo.frames;
         m_channelCount = m_fileInfo.channels;
         m_sampleRate = m_fileInfo.samplerate;
+
+        m_seekable = (m_fileInfo.seekable != 0);
+
+        // Our m_seekable reports whether a file is rapidly seekable,
+        // so things like Ogg don't qualify. We cautiously report
+        // every file type of "at least" the historical period of Ogg
+        // or FLAC as non-seekable.
+        int type = m_fileInfo.format & SF_FORMAT_TYPEMASK;
+//        std::cerr << "WavFileReader: format type is " << type << " (flac, ogg are " << SF_FORMAT_FLAC << ", " << SF_FORMAT_OGG << ")" << std::endl;
+        if (type >= SF_FORMAT_FLAC || type >= SF_FORMAT_OGG) {
+//            std::cerr << "WavFileReader: Recording as non-seekable" << std::endl;
+            m_seekable = false;
+        }
     }
 
-//    std::cerr << "WavFileReader: Frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << std::endl;
+//    std::cerr << "WavFileReader: Frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << ", seekable " << m_seekable << std::endl;
 
 }
 
--- a/data/fileio/WavFileReader.h	Fri Jul 12 13:10:28 2013 +0100
+++ b/data/fileio/WavFileReader.h	Wed Jul 17 15:41:20 2013 +0100
@@ -23,6 +23,16 @@
 
 #include <set>
 
+/**
+ * Reader for audio files using libsndfile.
+ *
+ * This is typically intended for seekable file types that can be read
+ * directly (e.g. WAV, AIFF etc).
+ *
+ * Compressed files supported by libsndfile (e.g. Ogg, FLAC) should
+ * normally be read using DecodingWavFileReader instead (which decodes
+ * to an intermediate cached file).
+ */
 class WavFileReader : public AudioFileReader
 {
 public:
@@ -32,6 +42,8 @@
     virtual QString getLocation() const { return m_source.getLocation(); }
     virtual QString getError() const { return m_error; }
 
+    virtual bool isQuicklySeekable() const { return m_seekable; }
+    
     /** 
      * Must be safe to call from multiple threads with different
      * arguments on the same object at the same time.
@@ -59,6 +71,8 @@
     QString m_path;
     QString m_error;
 
+    bool m_seekable;
+
     mutable QMutex m_mutex;
     mutable float *m_buffer;
     mutable size_t m_bufsiz;