changeset 327:1d656dcda8ef

* some tweaks to improve usability of these classes in a console application
author Chris Cannam
date Fri, 02 Nov 2007 16:50:31 +0000
parents bb6e4c46e202
children 21bd032ae791
files base/TempDirectory.cpp data/fileio/AudioFileReader.cpp data/fileio/AudioFileReader.h data/fileio/AudioFileReaderFactory.cpp data/fileio/AudioFileReaderFactory.h data/fileio/CodedAudioFileReader.cpp data/fileio/FileSource.cpp data/fileio/FileSource.h data/fileio/MP3FileReader.cpp data/fileio/OggVorbisFileReader.cpp data/fileio/QuickTimeFileReader.cpp data/fileio/ResamplingWavFileReader.cpp data/model/WaveFileModel.cpp
diffstat 13 files changed, 220 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/base/TempDirectory.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/base/TempDirectory.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -241,7 +241,7 @@
 
             if (GetProcessStatus(pid) == ProcessNotRunning) {
                 std::cerr << "INFO: Found abandoned temporary directory from "
-                          << "an old Sonic Visualiser process\n(pid=" << pid
+                          << "a previous, defunct process\n(pid=" << pid
                           << ", directory=\""
                           << dir.filePath(dir[i]).toStdString()
                           << "\").  Removing it..." << std::endl;
--- a/data/fileio/AudioFileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/AudioFileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -15,3 +15,26 @@
 
 #include "AudioFileReader.h"
 
+void
+AudioFileReader::getDeInterleavedFrames(size_t start, size_t count,
+                                        std::vector<SampleBlock> &frames) const
+{
+    SampleBlock interleaved;
+    getInterleavedFrames(start, count, interleaved);
+    
+    size_t channels = getChannelCount();
+    size_t rc = interleaved.size() / channels;
+
+    frames.clear();
+
+    for (size_t c = 0; c < channels; ++c) {
+        frames.push_back(SampleBlock());
+    }
+
+    for (size_t i = 0; i < rc; ++i) {
+        for (size_t c = 0; c < channels; ++c) {
+            frames[c].push_back(interleaved[i * channels + c]);
+        }
+    }
+}
+
--- a/data/fileio/AudioFileReader.h	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/AudioFileReader.h	Fri Nov 02 16:50:31 2007 +0000
@@ -17,10 +17,13 @@
 #define _AUDIO_FILE_READER_H_
 
 #include <QString>
-#include "model/Model.h" // for SampleBlock
 
 #include "FileSource.h"
 
+#include <vector>
+
+typedef std::vector<float> SampleBlock;
+
 class AudioFileReader : public QObject
 {
     Q_OBJECT
@@ -45,6 +48,10 @@
     virtual QString getTitle() const { return ""; }
 
     /** 
+     * Return interleaved samples for count frames from index start.
+     * The resulting sample block will contain count *
+     * getChannelCount() samples (or fewer if end of file is reached).
+     *
      * The subclass implementations of this function must be
      * thread-safe -- that is, safe to call from multiple threads with
      * different arguments on the same object at the same time.
@@ -52,6 +59,16 @@
     virtual void getInterleavedFrames(size_t start, size_t count,
 				      SampleBlock &frames) const = 0;
 
+    /**
+     * Return de-interleaved samples for count frames from index
+     * start.  Implemented in this class (it calls
+     * getInterleavedFrames and de-interleaves).  The resulting vector
+     * will contain getChannelCount() sample blocks of count samples
+     * each (or fewer if end of file is reached).
+     */
+    virtual void getDeInterleavedFrames(size_t start, size_t count,
+                                        std::vector<SampleBlock> &frames) const;
+
     // 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; } // %
--- a/data/fileio/AudioFileReaderFactory.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/AudioFileReaderFactory.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -56,9 +56,21 @@
 AudioFileReader *
 AudioFileReaderFactory::createReader(FileSource source, size_t targetRate)
 {
+    return create(source, targetRate, false);
+}
+
+AudioFileReader *
+AudioFileReaderFactory::createThreadingReader(FileSource source, size_t targetRate)
+{
+    return create(source, targetRate, true);
+}
+
+AudioFileReader *
+AudioFileReaderFactory::create(FileSource source, size_t targetRate, bool threading)
+{
     QString err;
 
-    std::cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation().toStdString() << "\"): Requested rate: " << targetRate << std::endl;
+//    std::cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation().toStdString() << "\"): Requested rate: " << targetRate << std::endl;
 
     if (!source.isOK() || !source.isAvailable()) {
         std::cerr << "AudioFileReaderFactory::createReader(\"" << source.getLocation().toStdString() << "\": Source unavailable" << std::endl;
@@ -83,7 +95,9 @@
             delete reader;
             reader = new ResamplingWavFileReader
                 (source,
-                 ResamplingWavFileReader::ResampleThreaded,
+                 threading ?
+                 ResamplingWavFileReader::ResampleThreaded :
+                 ResamplingWavFileReader::ResampleAtOnce,
                  ResamplingWavFileReader::CacheInTemporaryFile,
                  targetRate);
         }
@@ -95,7 +109,9 @@
         if (OggVorbisFileReader::supports(source)) {
             reader = new OggVorbisFileReader
                 (source,
-                 OggVorbisFileReader::DecodeThreaded,
+                 threading ?
+                 OggVorbisFileReader::DecodeThreaded :
+                 OggVorbisFileReader::DecodeAtOnce,
                  OggVorbisFileReader::CacheInTemporaryFile,
                  targetRate);
         }
@@ -108,7 +124,9 @@
         if (MP3FileReader::supports(source)) {
             reader = new MP3FileReader
                 (source,
-                 MP3FileReader::DecodeThreaded,
+                 threading ?
+                 MP3FileReader::DecodeThreaded :
+                 MP3FileReader::DecodeAtOnce,
                  MP3FileReader::CacheInTemporaryFile,
                  targetRate);
         }
@@ -120,7 +138,9 @@
         if (QuickTimeFileReader::supports(source)) {
             reader = new QuickTimeFileReader
                 (source,
-                 QuickTimeFileReader::DecodeThreaded,
+                 threading ?
+                 QuickTimeFileReader::DecodeThreaded : 
+                 QuickTimeFileReader::DecodeAtOnce,
                  QuickTimeFileReader::CacheInTemporaryFile,
                  targetRate);
         }
@@ -129,7 +149,7 @@
 
     if (reader) {
         if (reader->isOK()) {
-            std::cerr << "AudioFileReaderFactory: Reader is OK" << std::endl;
+//            std::cerr << "AudioFileReaderFactory: Reader is OK" << std::endl;
             return reader;
         }
         std::cerr << "AudioFileReaderFactory: Preferred reader for "
--- a/data/fileio/AudioFileReaderFactory.h	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/AudioFileReaderFactory.h	Fri Nov 02 16:50:31 2007 +0000
@@ -44,7 +44,30 @@
      *
      * Caller owns the returned object and must delete it after use.
      */
-    static AudioFileReader *createReader(FileSource source, size_t targetRate = 0);
+    static AudioFileReader *createReader(FileSource source,
+                                         size_t targetRate = 0);
+
+    /**
+     * Return an audio file reader initialised to the file at the
+     * given path, or NULL if no suitable reader for this path is
+     * available or the file cannot be opened.  If the reader supports
+     * threaded decoding, it will be used and the file decoded in a
+     * background thread.
+     *
+     * If targetRate is non-zero, the file will be resampled to that
+     * rate (transparently).  You can query reader->getNativeRate()
+     * if you want to find out whether the file is being resampled
+     * or not.
+     *
+     * Caller owns the returned object and must delete it after use.
+     */
+    static AudioFileReader *createThreadingReader(FileSource source,
+                                                  size_t targetRate = 0);
+
+protected:
+    static AudioFileReader *create(FileSource source,
+                                   size_t targetRate,
+                                   bool threading);
 };
 
 #endif
--- a/data/fileio/CodedAudioFileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/CodedAudioFileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -40,7 +40,7 @@
     m_resampler(0),
     m_resampleBuffer(0)
 {
-    std::cerr << "CodedAudioFileReader::CodedAudioFileReader: rate " << targetRate << std::endl;
+//    std::cerr << "CodedAudioFileReader::CodedAudioFileReader: rate " << targetRate << std::endl;
 
     m_frameCount = 0;
     m_sampleRate = targetRate;
--- a/data/fileio/FileSource.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/FileSource.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -27,6 +27,8 @@
 
 #include <iostream>
 
+//#define DEBUG_FILE_SOURCE 1
+
 int
 FileSource::m_count = 0;
 
@@ -56,7 +58,9 @@
     m_progressShowTimer(this),
     m_refCounted(false)
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::FileSource(" << fileOrUrl.toStdString() << ")" << std::endl;
+#endif
 
     if (!canHandleScheme(m_url)) {
         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
@@ -106,7 +110,9 @@
     m_progressShowTimer(this),
     m_refCounted(false)
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::FileSource(" << url.toString().toStdString() << ") [as url]" << std::endl;
+#endif
 
     if (!canHandleScheme(m_url)) {
         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
@@ -132,7 +138,9 @@
     m_progressShowTimer(0),
     m_refCounted(false)
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::FileSource(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl;
+#endif
 
     if (!canHandleScheme(m_url)) {
         std::cerr << "FileSource::FileSource: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl;
@@ -144,11 +152,15 @@
         m_localFilename = rf.m_localFilename;
     } else {
         QMutexLocker locker(&m_mapMutex);
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::FileSource(copy ctor): ref count is "
                   << m_refCountMap[m_url] << std::endl;
+#endif
         if (m_refCountMap[m_url] > 0) {
             m_refCountMap[m_url]++;
+#ifdef DEBUG_FILE_SOURCE
             std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
+#endif
             m_localFilename = m_remoteLocalMap[m_url];
             m_refCounted = true;
         } else {
@@ -162,7 +174,9 @@
 
 FileSource::~FileSource()
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource(" << m_url.toString().toStdString() << ")::~FileSource" << std::endl;
+#endif
 
     cleanup();
 
@@ -185,7 +199,9 @@
     }
 
     if (createCacheFile()) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::init: Already have this one" << std::endl;
+#endif
         m_ok = true;
         if (!QFileInfo(m_localFilename).exists()) {
             m_lastStatus = 404;
@@ -202,8 +218,10 @@
 
     QString scheme = m_url.scheme().toLower();
 
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::init: Don't have local copy of \""
               << m_url.toString().toStdString() << "\", retrieving" << std::endl;
+#endif
 
     if (scheme == "http") {
         initHttp();
@@ -223,7 +241,9 @@
             // but has got there first
             cleanup();
             m_refCountMap[m_url]++;
+#ifdef DEBUG_FILE_SOURCE
             std::cerr << "FileSource::init: Another FileSource has got there first, abandoning our download and using theirs" << std::endl;
+#endif
             m_localFilename = m_remoteLocalMap[m_url];
             m_refCounted = true;
             m_ok = true;
@@ -305,8 +325,10 @@
         
     QString path = "/" + QString(m_url.toEncoded()).section('/', 3);
 
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource: path is \""
               << path.toStdString() << "\"" << std::endl;
+#endif
         
     m_http->get(path, m_localFile);
 }
@@ -387,8 +409,10 @@
     bool available = true;
     if (!m_ok) available = false;
     else available = (m_lastStatus / 100 == 2);
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::isAvailable: " << (available ? "yes" : "no")
               << std::endl;
+#endif
     return available;
 }
 
@@ -480,11 +504,15 @@
     if (m_lastStatus / 100 >= 4) {
         m_errorString = QString("%1 %2")
             .arg(resp.statusCode()).arg(resp.reasonPhrase());
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::responseHeaderReceived: "
                   << m_errorString.toStdString() << std::endl;
+#endif
     } else {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::responseHeaderReceived: "
                   << m_lastStatus << std::endl;
+#endif
         if (resp.hasContentType()) m_contentType = resp.contentType();
     }
     emit statusAvailable();
@@ -493,15 +521,19 @@
 void
 FileSource::ftpCommandFinished(int id, bool error)
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::ftpCommandFinished(" << id << ", " << error << ")" << std::endl;
+#endif
 
     if (!m_ftp) return;
 
     QFtp::Command command = m_ftp->currentCommand();
 
     if (!error) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::ftpCommandFinished: success for command "
                   << command << std::endl;
+#endif
         return;
     }
 
@@ -521,11 +553,11 @@
 void
 FileSource::dataTransferProgress(qint64 done, qint64 total)
 {
-    if (!m_progressDialog) return;
-
     int percent = int((double(done) / double(total)) * 100.0 - 0.1);
     emit progress(percent);
 
+    if (!m_progressDialog) return;
+
     if (percent > 0) {
         m_progressDialog->setValue(percent);
         m_progressDialog->show();
@@ -545,12 +577,14 @@
 void
 FileSource::done(bool error)
 {
+    emit progress(100);
+
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::done(" << error << ")" << std::endl;
+#endif
 
     if (m_done) return;
 
-    emit progress(100);
-
     if (error) {
         if (m_http) {
             m_errorString = m_http->errorString();
@@ -577,7 +611,9 @@
     }
 
     if (error) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::done: error is " << error << ", deleting cache file" << std::endl;
+#endif
         deleteCacheFile();
     }
 
@@ -589,7 +625,9 @@
 void
 FileSource::deleteCacheFile()
 {
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl;
+#endif
 
     cleanup();
 
@@ -598,7 +636,9 @@
     }
 
     if (!isRemote()) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "not a cache file" << std::endl;
+#endif
         return;
     }
 
@@ -609,7 +649,9 @@
 
         if (m_refCountMap[m_url] > 0) {
             m_refCountMap[m_url]--;
+#ifdef DEBUG_FILE_SOURCE
             std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl;
+#endif
             if (m_refCountMap[m_url] > 0) {
                 m_done = true;
                 return;
@@ -620,9 +662,13 @@
     m_fileCreationMutex.lock();
 
     if (!QFile(m_localFilename).remove()) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl;
+#endif
     } else {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl;
+#endif
         m_localFilename = "";
     }
 
@@ -643,12 +689,16 @@
     {
         QMutexLocker locker(&m_mapMutex);
 
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl;
+#endif
 
         if (m_refCountMap[m_url] > 0) {
             m_refCountMap[m_url]++;
             m_localFilename = m_remoteLocalMap[m_url];
+#ifdef DEBUG_FILE_SOURCE
             std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl;
+#endif
             m_refCounted = true;
             return true;
         }
@@ -658,7 +708,9 @@
     try {
         dir = TempDirectory::getInstance()->getSubDirectoryPath("download");
     } catch (DirectoryCreationFailed f) {
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl;
+#endif
         return "";
     }
 
@@ -682,7 +734,9 @@
 
     QString filepath(dir.filePath(filename));
 
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::createCacheFile: URL is \"" << m_url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl;
+#endif
 
     QMutexLocker fcLocker(&m_fileCreationMutex);
 
@@ -691,10 +745,11 @@
     if (QFileInfo(filepath).exists() ||
         !QFile(filepath).open(QFile::WriteOnly)) {
 
+#ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::createCacheFile: Failed to create local file \""
                   << filepath.toStdString() << "\" for URL \""
                   << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl;
-
+#endif
 
         if (extension == "") {
             filename = QString("%1_%2").arg(base).arg(m_count);
@@ -706,19 +761,45 @@
         if (QFileInfo(filepath).exists() ||
             !QFile(filepath).open(QFile::WriteOnly)) {
 
+#ifdef DEBUG_FILE_SOURCE
             std::cerr << "FileSource::createCacheFile: ERROR: Failed to create local file \""
                       << filepath.toStdString() << "\" for URL \""
                       << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl;
+#endif
 
             return "";
         }
     }
 
+#ifdef DEBUG_FILE_SOURCE
     std::cerr << "FileSource::createCacheFile: url "
               << m_url.toString().toStdString() << " -> local filename "
               << filepath.toStdString() << std::endl;
+#endif
     
     m_localFilename = filepath;
 
     return false;
 }
+
+FileSourceProgressPrinter::FileSourceProgressPrinter() :
+    m_lastProgress(0)
+{
+}
+
+FileSourceProgressPrinter::~FileSourceProgressPrinter()
+{
+    if (m_lastProgress > 0 && m_lastProgress != 100) {
+        std::cerr << "\r\n";
+    }
+}
+
+void
+FileSourceProgressPrinter::progress(int progress)
+{
+    if (progress == m_lastProgress) return;
+    if (progress == 100) std::cerr << "\r\n";
+    else std::cerr << "\r" << progress << "%";
+    m_lastProgress = progress;
+}
+
--- a/data/fileio/FileSource.h	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/FileSource.h	Fri Nov 02 16:50:31 2007 +0000
@@ -237,4 +237,19 @@
     static int m_count;
 };
 
+class FileSourceProgressPrinter : public QObject
+{
+    Q_OBJECT
+
+public:
+    FileSourceProgressPrinter();
+    virtual ~FileSourceProgressPrinter();
+    
+public slots:
+    void progress(int);
+
+protected:
+    int m_lastProgress;
+};
+
 #endif
--- a/data/fileio/MP3FileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/MP3FileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -106,10 +106,12 @@
 
     if (decodeMode == DecodeAtOnce) {
 
-	m_progress = new QProgressDialog
-	    (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
-	     QObject::tr("Stop"), 0, 100);
-	m_progress->hide();
+        if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
+            m_progress = new QProgressDialog
+                (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
+                 QObject::tr("Stop"), 0, 100);
+            m_progress->hide();
+        }
 
         if (!decode(m_filebuffer, m_fileSize)) {
             m_error = QString("Failed to decode file %1.").arg(m_path);
--- a/data/fileio/OggVorbisFileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/OggVorbisFileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -70,10 +70,12 @@
 
     if (decodeMode == DecodeAtOnce) {
 
-	m_progress = new QProgressDialog
-	    (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
-	     QObject::tr("Stop"), 0, 100);
-	m_progress->hide();
+        if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
+            m_progress = new QProgressDialog
+                (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
+                 QObject::tr("Stop"), 0, 100);
+            m_progress->hide();
+        }
 
         while (oggz_read(m_oggz, 1024) > 0);
         
--- a/data/fileio/QuickTimeFileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/QuickTimeFileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -216,10 +216,12 @@
 
     if (decodeMode == DecodeAtOnce) {
 
-	m_progress = new QProgressDialog
-	    (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
-	     QObject::tr("Stop"), 0, 100);
-	m_progress->hide();
+        if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
+            m_progress = new QProgressDialog
+                (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
+                 QObject::tr("Stop"), 0, 100);
+            m_progress->hide();
+        }
 
         while (1) {
             
--- a/data/fileio/ResamplingWavFileReader.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/fileio/ResamplingWavFileReader.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -57,10 +57,12 @@
 
     if (resampleMode == ResampleAtOnce) {
 
-	m_progress = new QProgressDialog
-	    (QObject::tr("Resampling %1...").arg(QFileInfo(m_path).fileName()),
-	     QObject::tr("Stop"), 0, 100);
-	m_progress->hide();
+        if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
+            m_progress = new QProgressDialog
+                (QObject::tr("Resampling %1...").arg(QFileInfo(m_path).fileName()),
+                 QObject::tr("Stop"), 0, 100);
+            m_progress->hide();
+        }
 
         size_t blockSize = 16384;
         size_t total = m_original->getFrameCount();
--- a/data/model/WaveFileModel.cpp	Thu Nov 01 16:02:01 2007 +0000
+++ b/data/model/WaveFileModel.cpp	Fri Nov 02 16:50:31 2007 +0000
@@ -51,7 +51,8 @@
 {
     m_source.waitForData();
     if (m_source.isOK()) {
-        m_reader = AudioFileReaderFactory::createReader(m_source, targetRate);
+        m_reader = AudioFileReaderFactory::createThreadingReader
+            (m_source, targetRate);
         if (m_reader) {
             std::cerr << "WaveFileModel::WaveFileModel: reader rate: "
                       << m_reader->getSampleRate() << std::endl;