[Sv1-commits] SF.net SVN: sv1: [788] sonic-visualiser/trunk
Brought to you by:
cannam
From: <ca...@us...> - 2007-10-18 15:31:22
|
Revision: 788 http://sv1.svn.sourceforge.net/sv1/?rev=788&view=rev Author: cannam Date: 2007-10-18 08:31:20 -0700 (Thu, 18 Oct 2007) Log Message: ----------- * Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc Modified Paths: -------------- sonic-visualiser/trunk/data/fileio/AudioFileReader.h sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.cpp sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.h sonic-visualiser/trunk/data/fileio/FileFinder.cpp sonic-visualiser/trunk/data/fileio/MP3FileReader.cpp sonic-visualiser/trunk/data/fileio/MP3FileReader.h sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.cpp sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.h sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.cpp sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.h sonic-visualiser/trunk/data/fileio/RemoteFile.cpp sonic-visualiser/trunk/data/fileio/RemoteFile.h sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.cpp sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.h sonic-visualiser/trunk/data/fileio/WavFileReader.cpp sonic-visualiser/trunk/data/fileio/WavFileReader.h sonic-visualiser/trunk/data/model/WaveFileModel.cpp sonic-visualiser/trunk/data/model/WaveFileModel.h sonic-visualiser/trunk/data/model/WritableWaveFileModel.cpp sonic-visualiser/trunk/layer/ImageLayer.cpp sonic-visualiser/trunk/sv/document/SVFileReader.cpp sonic-visualiser/trunk/sv/main/MainWindow.cpp sonic-visualiser/trunk/sv/main/MainWindow.h sonic-visualiser/trunk/sv/main/main.cpp sonic-visualiser/trunk/widgets/ImageDialog.cpp Modified: sonic-visualiser/trunk/data/fileio/AudioFileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/AudioFileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/AudioFileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -19,6 +19,8 @@ #include <QString> #include "model/Model.h" // for SampleBlock +#include "RemoteFile.h" + class AudioFileReader : public QObject { Q_OBJECT Modified: sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -54,24 +54,25 @@ } AudioFileReader * -AudioFileReaderFactory::createReader(QString path, size_t targetRate) +AudioFileReaderFactory::createReader(RemoteFile source, size_t targetRate) { QString err; - std::cerr << "AudioFileReaderFactory::createReader(\"" << path.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; + return 0; + } + AudioFileReader *reader = 0; - // First try to construct a preferred reader based on the - // extension. If we can't identify one or it fails to load the - // file, fall back to trying all readers in no particular order. + // Try to construct a preferred reader based on the extension or + // MIME type. - QString ext = QFileInfo(path).suffix().toLower(); - std::set<QString> extensions; + if (WavFileReader::supports(source)) { - WavFileReader::getSupportedExtensions(extensions); - if (extensions.find(ext) != extensions.end()) { - reader = new WavFileReader(path); + reader = new WavFileReader(source); if (targetRate != 0 && reader->isOK() && @@ -81,7 +82,7 @@ delete reader; reader = new ResamplingWavFileReader - (path, + (source, ResamplingWavFileReader::ResampleThreaded, ResamplingWavFileReader::CacheInTemporaryFile, targetRate); @@ -91,11 +92,9 @@ #ifdef HAVE_OGGZ #ifdef HAVE_FISHSOUND if (!reader) { - extensions.clear(); - OggVorbisFileReader::getSupportedExtensions(extensions); - if (extensions.find(ext) != extensions.end()) { + if (OggVorbisFileReader::supports(source)) { reader = new OggVorbisFileReader - (path, + (source, OggVorbisFileReader::DecodeThreaded, OggVorbisFileReader::CacheInTemporaryFile, targetRate); @@ -106,11 +105,9 @@ #ifdef HAVE_MAD if (!reader) { - extensions.clear(); - MP3FileReader::getSupportedExtensions(extensions); - if (extensions.find(ext) != extensions.end()) { + if (MP3FileReader::supports(source)) { reader = new MP3FileReader - (path, + (source, MP3FileReader::DecodeThreaded, MP3FileReader::CacheInTemporaryFile, targetRate); @@ -120,11 +117,9 @@ #ifdef HAVE_QUICKTIME if (!reader) { - extensions.clear(); - QuickTimeFileReader::getSupportedExtensions(extensions); - if (extensions.find(ext) != extensions.end()) { + if (QuickTimeFileReader::supports(source)) { reader = new QuickTimeFileReader - (path, + (source, QuickTimeFileReader::DecodeThreaded, QuickTimeFileReader::CacheInTemporaryFile, targetRate); @@ -133,20 +128,24 @@ #endif if (reader) { - if (reader->isOK()) return reader; + if (reader->isOK()) { + std::cerr << "AudioFileReaderFactory: Reader is OK" << std::endl; + return reader; + } + std::cerr << "AudioFileReaderFactory: Preferred reader for " + << "url \"" << source.getLocation().toStdString() + << "\" (content type \"" + << source.getContentType().toStdString() << "\") failed"; + if (reader->getError() != "") { - std::cerr << "AudioFileReaderFactory: Preferred reader for " - << "extension \"" << ext.toStdString() << "\" failed: \"" - << reader->getError().toStdString() << "\"" << std::endl; - } else { - std::cerr << "AudioFileReaderFactory: Preferred reader for " - << "extension \"" << ext.toStdString() << "\" failed" - << std::endl; - } + std::cerr << ": \"" << reader->getError().toStdString() << "\""; + } + std::cerr << std::endl; delete reader; reader = 0; } + std::cerr << "AudioFileReaderFactory: No reader" << std::endl; return reader; } Modified: sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.h =================================================================== --- sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/AudioFileReaderFactory.h 2007-10-18 15:31:20 UTC (rev 788) @@ -18,6 +18,8 @@ #include <QString> +#include "RemoteFile.h" + class AudioFileReader; class AudioFileReaderFactory @@ -42,7 +44,7 @@ * * Caller owns the returned object and must delete it after use. */ - static AudioFileReader *createReader(QString path, size_t targetRate = 0); + static AudioFileReader *createReader(RemoteFile source, size_t targetRate = 0); }; #endif Modified: sonic-visualiser/trunk/data/fileio/FileFinder.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/FileFinder.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/FileFinder.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -380,11 +380,11 @@ { if (QFileInfo(location).exists()) return location; - if (RemoteFile::canHandleScheme(QUrl(location))) { - RemoteFile rf(location); - bool available = rf.isAvailable(); - rf.deleteLocalFile(); - if (available) return location; + if (RemoteFile::isRemote(location)) { + if (RemoteFile(location).isAvailable()) { + std::cerr << "FileFinder::find: ok, it's available... returning" << std::endl; + return location; + } } QString foundAt = ""; @@ -411,19 +411,17 @@ QString fileName; QString resolved; - if (RemoteFile::canHandleScheme(QUrl(location))) { + if (RemoteFile::isRemote(location)) { fileName = QUrl(location).path().section('/', -1, -1, QString::SectionSkipEmpty); } else { fileName = QFileInfo(location).fileName(); } - if (RemoteFile::canHandleScheme(QUrl(relativeTo))) { + if (RemoteFile::isRemote(relativeTo)) { resolved = QUrl(relativeTo).resolved(fileName).toString(); - RemoteFile rf(resolved); - if (!rf.isAvailable()) resolved = ""; + if (!RemoteFile(resolved).isAvailable()) resolved = ""; std::cerr << "resolved: " << resolved.toStdString() << std::endl; - rf.deleteLocalFile(); } else { resolved = QFileInfo(relativeTo).dir().filePath(fileName); if (!QFileInfo(resolved).exists() || @@ -481,8 +479,7 @@ QLineEdit::Normal, "", &ok); if (ok && path != "") { - RemoteFile rf(path); - if (rf.isAvailable()) { + if (RemoteFile(path).isAvailable()) { done = true; } else { QMessageBox::critical @@ -490,7 +487,6 @@ tr("URL \"%1\" could not be opened").arg(path)); path = ""; } - rf.deleteLocalFile(); } break; } Modified: sonic-visualiser/trunk/data/fileio/MP3FileReader.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/MP3FileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/MP3FileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -34,10 +34,11 @@ #include <QFileInfo> #include <QProgressDialog> -MP3FileReader::MP3FileReader(QString path, DecodeMode decodeMode, +MP3FileReader::MP3FileReader(RemoteFile source, DecodeMode decodeMode, CacheMode mode, size_t targetRate) : CodedAudioFileReader(mode, targetRate), - m_path(path), + m_source(source), + m_path(source.getLocalFilename()), m_decodeThread(0) { m_channelCount = 0; @@ -51,20 +52,20 @@ m_progress = 0; struct stat stat; - if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { - m_error = QString("File %1 does not exist.").arg(path); + if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { + m_error = QString("File %1 does not exist.").arg(m_path); return; } m_fileSize = stat.st_size; int fd = -1; - if ((fd = ::open(path.toLocal8Bit().data(), O_RDONLY + if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY #ifdef _WIN32 | O_BINARY #endif , 0)) < 0) { - m_error = QString("Failed to open file %1 for reading.").arg(path); + m_error = QString("Failed to open file %1 for reading.").arg(m_path); return; } @@ -86,7 +87,7 @@ sz = ::read(fd, m_filebuffer + offset, m_fileSize - offset); if (sz < 0) { m_error = QString("Read error for file %1 (after %2 bytes)") - .arg(path).arg(offset); + .arg(m_path).arg(offset); delete[] m_filebuffer; ::close(fd); return; @@ -106,12 +107,12 @@ if (decodeMode == DecodeAtOnce) { m_progress = new QProgressDialog - (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), + (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(path); + m_error = QString("Failed to decode file %1.").arg(m_path); } delete[] m_filebuffer; @@ -394,4 +395,26 @@ extensions.insert("mp3"); } +bool +MP3FileReader::supportsExtension(QString extension) +{ + std::set<QString> extensions; + getSupportedExtensions(extensions); + return (extensions.find(extension.toLower()) != extensions.end()); +} + +bool +MP3FileReader::supportsContentType(QString type) +{ + return (type == "audio/mpeg"); +} + +bool +MP3FileReader::supports(RemoteFile &source) +{ + return (supportsExtension(source.getExtension()) || + supportsContentType(source.getContentType())); +} + + #endif Modified: sonic-visualiser/trunk/data/fileio/MP3FileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/MP3FileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/MP3FileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -35,7 +35,7 @@ DecodeThreaded // decode in a background thread after construction }; - MP3FileReader(QString path, + MP3FileReader(RemoteFile source, DecodeMode decodeMode, CacheMode cacheMode, size_t targetRate = 0); @@ -46,7 +46,10 @@ virtual QString getTitle() const { return m_title; } static void getSupportedExtensions(std::set<QString> &extensions); - + static bool supportsExtension(QString ext); + static bool supportsContentType(QString type); + static bool supports(RemoteFile &source); + virtual int getDecodeCompletion() const { return m_completion; } virtual bool isUpdating() const { @@ -54,6 +57,7 @@ } protected: + RemoteFile m_source; QString m_path; QString m_error; QString m_title; Modified: sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -32,12 +32,13 @@ static int instances = 0; -OggVorbisFileReader::OggVorbisFileReader(QString path, +OggVorbisFileReader::OggVorbisFileReader(RemoteFile source, DecodeMode decodeMode, CacheMode mode, size_t targetRate) : CodedAudioFileReader(mode, targetRate), - m_path(path), + m_source(source), + m_path(source.getLocalFilename()), m_progress(0), m_fileSize(0), m_bytesRead(0), @@ -49,15 +50,15 @@ m_channelCount = 0; m_fileRate = 0; - std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl; + std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl; Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true); - QFileInfo info(path); + QFileInfo info(m_path); m_fileSize = info.size(); - if (!(m_oggz = oggz_open(path.toLocal8Bit().data(), OGGZ_READ))) { - m_error = QString("File %1 is not an OGG file.").arg(path); + if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) { + m_error = QString("File %1 is not an OGG file.").arg(m_path); return; } @@ -70,7 +71,7 @@ if (decodeMode == DecodeAtOnce) { m_progress = new QProgressDialog - (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), + (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()), QObject::tr("Stop"), 0, 100); m_progress->hide(); @@ -201,5 +202,26 @@ extensions.insert("ogg"); } +bool +OggVorbisFileReader::supportsExtension(QString extension) +{ + std::set<QString> extensions; + getSupportedExtensions(extensions); + return (extensions.find(extension.toLower()) != extensions.end()); +} + +bool +OggVorbisFileReader::supportsContentType(QString type) +{ + return (type == "application/ogg"); +} + +bool +OggVorbisFileReader::supports(RemoteFile &source) +{ + return (supportsExtension(source.getExtension()) || + supportsContentType(source.getContentType())); +} + #endif #endif Modified: sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/OggVorbisFileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -37,7 +37,7 @@ DecodeThreaded // decode in a background thread after construction }; - OggVorbisFileReader(QString path, + OggVorbisFileReader(RemoteFile source, DecodeMode decodeMode, CacheMode cacheMode, size_t targetRate = 0); @@ -48,6 +48,9 @@ virtual QString getTitle() const { return m_title; } static void getSupportedExtensions(std::set<QString> &extensions); + static bool supportsExtension(QString ext); + static bool supportsContentType(QString type); + static bool supports(RemoteFile &source); virtual int getDecodeCompletion() const { return m_completion; } @@ -56,6 +59,7 @@ } protected: + RemoteFile m_source; QString m_path; QString m_error; QString m_title; Modified: sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -48,12 +48,13 @@ }; -QuickTimeFileReader::QuickTimeFileReader(QString path, +QuickTimeFileReader::QuickTimeFileReader(RemoteFile source, DecodeMode decodeMode, CacheMode mode, size_t targetRate) : CodedAudioFileReader(mode, targetRate), - m_path(path), + m_source(source), + m_path(source.getLocalFilename()), m_d(new D), m_progress(0), m_cancelled(false), @@ -65,7 +66,7 @@ Profiler profiler("QuickTimeFileReader::QuickTimeFileReader", true); -std::cerr << "QuickTimeFileReader: path is \"" << path.toStdString() << "\"" << std::endl; +std::cerr << "QuickTimeFileReader: path is \"" << m_path.toStdString() << "\"" << std::endl; long QTversion; @@ -90,8 +91,8 @@ CFURLRef url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, - (const UInt8 *)path.toLocal8Bit().data(), - (CFIndex)path.length(), + (const UInt8 *)m_path.toLocal8Bit().data(), + (CFIndex)m_path.length(), false); @@ -216,7 +217,7 @@ if (decodeMode == DecodeAtOnce) { m_progress = new QProgressDialog - (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), + (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()), QObject::tr("Stop"), 0, 100); m_progress->hide(); @@ -335,5 +336,32 @@ extensions.insert("wav"); } +bool +QuickTimeFileReader::supportsExtension(QString extension) +{ + std::set<QString> extensions; + getSupportedExtensions(extensions); + return (extensions.find(extension.toLower()) != extensions.end()); +} + +bool +QuickTimeFileReader::supportsContentType(QString type) +{ + return (type == "audio/x-aiff" || + type == "audio/x-wav" || + type == "audio/mpeg" || + type == "audio/basic" || + type == "audio/x-aac" || + type == "video/mp4" || + type == "video/quicktime"); +} + +bool +QuickTimeFileReader::supports(RemoteFile &source) +{ + return (supportsExtension(source.getExtension()) || + supportsContentType(source.getContentType())); +} + #endif Modified: sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/QuickTimeFileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -37,7 +37,7 @@ DecodeThreaded // decode in a background thread after construction }; - QuickTimeFileReader(QString path, + QuickTimeFileReader(RemoteFile source, DecodeMode decodeMode, CacheMode cacheMode, size_t targetRate = 0); @@ -47,6 +47,9 @@ virtual QString getTitle() const { return m_title; } static void getSupportedExtensions(std::set<QString> &extensions); + static bool supportsExtension(QString ext); + static bool supportsContentType(QString type); + static bool supports(RemoteFile &source); virtual int getDecodeCompletion() const { return m_completion; } @@ -55,6 +58,7 @@ } protected: + RemoteFile m_source; QString m_path; QString m_error; QString m_title; Modified: sonic-visualiser/trunk/data/fileio/RemoteFile.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/RemoteFile.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/RemoteFile.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -42,156 +42,303 @@ QMutex RemoteFile::m_mapMutex; -RemoteFile::RemoteFile(QUrl url) : - m_url(url), +RemoteFile::RemoteFile(QString fileOrUrl, bool showProgress) : + m_url(fileOrUrl), m_ftp(0), m_http(0), m_localFile(0), m_ok(false), m_lastStatus(0), + m_remote(isRemote(fileOrUrl)), m_done(false), + m_leaveLocalFile(false), m_progressDialog(0), m_progressShowTimer(this), - m_referenced(false) + m_refCounted(false) { - if (!canHandleScheme(url)) { - std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << url.toString().toStdString() << "\"" << std::endl; + std::cerr << "RemoteFile::RemoteFile(" << fileOrUrl.toStdString() << ")" << std::endl; + + if (!canHandleScheme(m_url)) { + std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; + m_errorString = tr("Unsupported scheme in URL"); return; } - QMutexLocker locker(&m_mapMutex); + init(showProgress); - std::cerr << "RemoteFile::RemoteFile: refcount is " << m_refCountMap[m_url] << std::endl; + if (isRemote() && + (fileOrUrl.contains('%') || + fileOrUrl.contains("--"))) { // for IDNA - if (m_refCountMap[m_url] > 0) { - m_refCountMap[m_url]++; - m_localFilename = m_remoteLocalMap[m_url]; - std::cerr << "raising it" << std::endl; - m_ok = true; - m_done = true; - m_referenced = true; - return; + waitForStatus(); + + if (!isAvailable()) { + // The URL was created on the assumption that the string + // was human-readable. Let's try again, this time + // assuming it was already encoded. + std::cerr << "RemoteFile::RemoteFile: Failed to retrieve URL \"" + << fileOrUrl.toStdString() + << "\" as human-readable URL; " + << "trying again treating it as encoded URL" + << std::endl; + m_url.setEncodedUrl(fileOrUrl.toAscii()); + init(showProgress); + } } +} - m_localFilename = createLocalFile(url); - if (m_localFilename == "") return; - m_localFile = new QFile(m_localFilename); - m_localFile->open(QFile::WriteOnly); +RemoteFile::RemoteFile(QUrl url, bool showProgress) : + m_url(url), + m_ftp(0), + m_http(0), + m_localFile(0), + m_ok(false), + m_lastStatus(0), + m_remote(isRemote(url.toString())), + m_done(false), + m_leaveLocalFile(false), + m_progressDialog(0), + m_progressShowTimer(this), + m_refCounted(false) +{ + std::cerr << "RemoteFile::RemoteFile(" << url.toString().toStdString() << ") [as url]" << std::endl; - QString scheme = url.scheme().toLower(); + if (!canHandleScheme(m_url)) { + std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; + m_errorString = tr("Unsupported scheme in URL"); + return; + } - if (scheme == "http") { + init(showProgress); +} - m_ok = true; - m_http = new QHttp(url.host(), url.port(80)); - connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); - connect(m_http, SIGNAL(dataReadProgress(int, int)), - this, SLOT(dataReadProgress(int, int))); - connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), - this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); +RemoteFile::RemoteFile(const RemoteFile &rf) : + QObject(), + m_url(rf.m_url), + m_ftp(0), + m_http(0), + m_localFile(0), + m_ok(rf.m_ok), + m_lastStatus(rf.m_lastStatus), + m_remote(rf.m_remote), + m_done(false), + m_leaveLocalFile(false), + m_progressDialog(0), + m_progressShowTimer(0), + m_refCounted(false) +{ + std::cerr << "RemoteFile::RemoteFile(" << m_url.toString().toStdString() << ") [copy ctor]" << std::endl; - // I don't quite understand this. url.path() returns a path - // without percent encoding; for example, spaces appear as - // literal spaces. This generally won't work if sent to the - // server directly. You can retrieve a correctly encoded URL - // from QUrl using url.toEncoded(), but that gives you the - // whole URL; there doesn't seem to be any way to retrieve - // only an encoded path. Furthermore there doesn't seem to be - // any way to convert a retrieved path into an encoded path - // without explicitly specifying that you don't want the path - // separators ("/") to be encoded. (Besides being painful to - // manage, I don't see how this can work correctly in any case - // where a percent-encoded "/" is supposed to appear within a - // path element?) There also seems to be no way to retrieve - // the path plus query string, i.e. everything that I need to - // send to the HTTP server. And no way for QHttp to take a - // QUrl argument. I'm obviously missing something. + if (!canHandleScheme(m_url)) { + std::cerr << "RemoteFile::RemoteFile: ERROR: Unsupported scheme in URL \"" << m_url.toString().toStdString() << "\"" << std::endl; + m_errorString = tr("Unsupported scheme in URL"); + return; + } - // So, two ways to do this: query the bits from the URL, - // encode them individually, and glue them back together - // again... - /* - QString path = QUrl::toPercentEncoding(url.path(), "/"); - QList<QPair<QString, QString> > query = url.queryItems(); - if (!query.empty()) { - QStringList q2; - for (QList<QPair<QString, QString> >::iterator i = query.begin(); - i != query.end(); ++i) { - q2.push_back(QString("%1=%3") - .arg(QString(QUrl::toPercentEncoding(i->first))) - .arg(QString(QUrl::toPercentEncoding(i->second)))); - } - path = QString("%1%2%3") - .arg(path).arg("?") - .arg(q2.join("&")); + if (!isRemote()) { + m_localFilename = rf.m_localFilename; + } else { + QMutexLocker locker(&m_mapMutex); + std::cerr << "RemoteFile::RemoteFile(copy ctor): ref count is " + << m_refCountMap[m_url] << std::endl; + if (m_refCountMap[m_url] > 0) { + m_refCountMap[m_url]++; + std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl; + m_localFilename = m_remoteLocalMap[m_url]; + m_refCounted = true; + } else { + m_ok = false; + m_lastStatus = 404; } - */ + } - // ...or, much simpler but relying on knowledge about the - // scheme://host/path/path/query etc format of the URL, we can - // get the whole URL ready-encoded and then split it on "/" as - // appropriate... - - QString path = "/" + QString(url.toEncoded()).section('/', 3); + m_done = true; +} - std::cerr << "RemoteFile: path is \"" - << path.toStdString() << "\"" << std::endl; +RemoteFile::~RemoteFile() +{ + std::cerr << "RemoteFile(" << m_url.toString().toStdString() << ")::~RemoteFile" << std::endl; - m_http->get(path, m_localFile); + cleanup(); - } else if (scheme == "ftp") { + if (isRemote() && !m_leaveLocalFile) deleteCacheFile(); +} +void +RemoteFile::init(bool showProgress) +{ + if (!isRemote()) { + m_localFilename = m_url.toLocalFile(); m_ok = true; - m_ftp = new QFtp; - connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); - connect(m_ftp, SIGNAL(commandFinished(int, bool)), - this, SLOT(ftpCommandFinished(int, bool))); - connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), - this, SLOT(dataTransferProgress(qint64, qint64))); - m_ftp->connectToHost(url.host(), url.port(21)); - - QString username = url.userName(); - if (username == "") { - username = "anonymous"; + if (!QFileInfo(m_localFilename).exists()) { + m_lastStatus = 404; + } else { + m_lastStatus = 200; } + m_done = true; + return; + } - QString password = url.password(); - if (password == "") { - password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); + if (createCacheFile()) { + std::cerr << "RemoteFile::init: Already have this one" << std::endl; + m_ok = true; + if (!QFileInfo(m_localFilename).exists()) { + m_lastStatus = 404; + } else { + m_lastStatus = 200; } + m_done = true; + return; + } - m_ftp->login(username, password); + if (m_localFilename == "") return; + m_localFile = new QFile(m_localFilename); + m_localFile->open(QFile::WriteOnly); - QString dirpath = url.path().section('/', 0, -2); - QString filename = url.path().section('/', -1); + QString scheme = m_url.scheme().toLower(); - if (dirpath == "") dirpath = "/"; - m_ftp->cd(dirpath); - m_ftp->get(filename, m_localFile); + std::cerr << "RemoteFile::init: Don't have local copy of \"" + << m_url.toString().toStdString() << "\", retrieving" << std::endl; + + if (scheme == "http") { + initHttp(); + } else if (scheme == "ftp") { + initFtp(); + } else { + m_remote = false; + m_ok = false; } if (m_ok) { + + QMutexLocker locker(&m_mapMutex); + if (m_refCountMap[m_url] > 0) { + // someone else has been doing the same thing at the same time, + // but has got there first + cleanup(); + m_refCountMap[m_url]++; + std::cerr << "RemoteFile::init: Another RemoteFile has got there first, abandoning our download and using theirs" << std::endl; + m_localFilename = m_remoteLocalMap[m_url]; + m_refCounted = true; + m_ok = true; + if (!QFileInfo(m_localFilename).exists()) { + m_lastStatus = 404; + } + m_done = true; + return; + } + m_remoteLocalMap[m_url] = m_localFilename; m_refCountMap[m_url]++; - m_referenced = true; + m_refCounted = true; - m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(url.toString()), tr("Cancel"), 0, 100); - m_progressDialog->hide(); - connect(&m_progressShowTimer, SIGNAL(timeout()), - this, SLOT(showProgressDialog())); - connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); - m_progressShowTimer.setSingleShot(true); - m_progressShowTimer.start(2000); + if (showProgress) { + m_progressDialog = new QProgressDialog(tr("Downloading %1...").arg(m_url.toString()), tr("Cancel"), 0, 100); + m_progressDialog->hide(); + connect(&m_progressShowTimer, SIGNAL(timeout()), + this, SLOT(showProgressDialog())); + connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelled())); + m_progressShowTimer.setSingleShot(true); + m_progressShowTimer.start(2000); + } } } -RemoteFile::~RemoteFile() +void +RemoteFile::initHttp() { - cleanup(); + m_ok = true; + m_http = new QHttp(m_url.host(), m_url.port(80)); + connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool))); + connect(m_http, SIGNAL(dataReadProgress(int, int)), + this, SLOT(dataReadProgress(int, int))); + connect(m_http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), + this, SLOT(httpResponseHeaderReceived(const QHttpResponseHeader &))); + + // I don't quite understand this. url.path() returns a path + // without percent encoding; for example, spaces appear as + // literal spaces. This generally won't work if sent to the + // server directly. You can retrieve a correctly encoded URL + // from QUrl using url.toEncoded(), but that gives you the + // whole URL; there doesn't seem to be any way to retrieve + // only an encoded path. Furthermore there doesn't seem to be + // any way to convert a retrieved path into an encoded path + // without explicitly specifying that you don't want the path + // separators ("/") to be encoded. (Besides being painful to + // manage, I don't see how this can work correctly in any case + // where a percent-encoded "/" is supposed to appear within a + // path element?) There also seems to be no way to retrieve + // the path plus query string, i.e. everything that I need to + // send to the HTTP server. And no way for QHttp to take a + // QUrl argument. I'm obviously missing something. + + // So, two ways to do this: query the bits from the URL, + // encode them individually, and glue them back together + // again... +/* + QString path = QUrl::toPercentEncoding(m_url.path(), "/"); + QList<QPair<QString, QString> > query = m_url.queryItems(); + if (!query.empty()) { + QStringList q2; + for (QList<QPair<QString, QString> >::iterator i = query.begin(); + i != query.end(); ++i) { + q2.push_back(QString("%1=%3") + .arg(QString(QUrl::toPercentEncoding(i->first))) + .arg(QString(QUrl::toPercentEncoding(i->second)))); + } + path = QString("%1%2%3") + .arg(path).arg("?") + .arg(q2.join("&")); + } +*/ + + // ...or, much simpler but relying on knowledge about the + // scheme://host/path/path/query etc format of the URL, we can + // get the whole URL ready-encoded and then split it on "/" as + // appropriate... + + QString path = "/" + QString(m_url.toEncoded()).section('/', 3); + + std::cerr << "RemoteFile: path is \"" + << path.toStdString() << "\"" << std::endl; + + m_http->get(path, m_localFile); } void +RemoteFile::initFtp() +{ + m_ok = true; + m_ftp = new QFtp; + connect(m_ftp, SIGNAL(done(bool)), this, SLOT(done(bool))); + connect(m_ftp, SIGNAL(commandFinished(int, bool)), + this, SLOT(ftpCommandFinished(int, bool))); + connect(m_ftp, SIGNAL(dataTransferProgress(qint64, qint64)), + this, SLOT(dataTransferProgress(qint64, qint64))); + m_ftp->connectToHost(m_url.host(), m_url.port(21)); + + QString username = m_url.userName(); + if (username == "") { + username = "anonymous"; + } + + QString password = m_url.password(); + if (password == "") { + password = QString("%1@%2").arg(getenv("USER")).arg(getenv("HOST")); + } + + m_ftp->login(username, password); + + QString dirpath = m_url.path().section('/', 0, -2); + QString filename = m_url.path().section('/', -1); + + if (dirpath == "") dirpath = "/"; + m_ftp->cd(dirpath); + m_ftp->get(filename, m_localFile); +} + +void RemoteFile::cleanup() { m_done = true; @@ -216,22 +363,22 @@ bool RemoteFile::isRemote(QString fileOrUrl) { - return (fileOrUrl.startsWith("http:") || fileOrUrl.startsWith("ftp:")); + QString scheme = QUrl(fileOrUrl).scheme().toLower(); + return (scheme == "http" || scheme == "ftp"); } bool RemoteFile::canHandleScheme(QUrl url) { QString scheme = url.scheme().toLower(); - return (scheme == "http" || scheme == "ftp"); + return (scheme == "http" || scheme == "ftp" || + scheme == "file" || scheme == ""); } bool RemoteFile::isAvailable() { - while (m_ok && (!m_done && m_lastStatus == 0)) { - QApplication::processEvents(); - } + waitForStatus(); bool available = true; if (!m_ok) available = false; else available = (m_lastStatus / 100 == 2); @@ -241,13 +388,28 @@ } void -RemoteFile::wait() +RemoteFile::waitForStatus() { + while (m_ok && (!m_done && m_lastStatus == 0)) { +// std::cerr << "waitForStatus: processing (last status " << m_lastStatus << ")" << std::endl; + QApplication::processEvents(); + } +} + +void +RemoteFile::waitForData() +{ while (m_ok && !m_done) { QApplication::processEvents(); } } +void +RemoteFile::setLeaveLocalFile(bool leave) +{ + m_leaveLocalFile = leave; +} + bool RemoteFile::isOK() const { @@ -260,13 +422,41 @@ return m_done; } +bool +RemoteFile::isRemote() const +{ + return m_remote; +} + QString +RemoteFile::getLocation() const +{ + return m_url.toString(); +} + +QString RemoteFile::getLocalFilename() const { return m_localFilename; } QString +RemoteFile::getContentType() const +{ + return m_contentType; +} + +QString +RemoteFile::getExtension() const +{ + if (m_localFilename != "") { + return QFileInfo(m_localFilename).suffix().toLower(); + } else { + return QFileInfo(m_url.toLocalFile()).suffix().toLower(); + } +} + +QString RemoteFile::getErrorString() const { return m_errorString; @@ -339,8 +529,9 @@ void RemoteFile::cancelled() { - deleteLocalFile(); m_done = true; + cleanup(); + m_ok = false; m_errorString = tr("Download cancelled"); } @@ -380,7 +571,8 @@ } if (error) { - deleteLocalFile(); + std::cerr << "RemoteFile::done: error is " << error << ", deleting cache file" << std::endl; + deleteCacheFile(); } m_ok = !error; @@ -389,21 +581,29 @@ } void -RemoteFile::deleteLocalFile() +RemoteFile::deleteCacheFile() { -// std::cerr << "RemoteFile::deleteLocalFile" << std::endl; + std::cerr << "RemoteFile::deleteCacheFile(\"" << m_localFilename.toStdString() << "\")" << std::endl; cleanup(); - if (m_localFilename == "") return; + if (m_localFilename == "") { + return; + } - if (m_referenced) { + if (!isRemote()) { + std::cerr << "not a cache file" << std::endl; + return; + } + if (m_refCounted) { + QMutexLocker locker(&m_mapMutex); - m_referenced = false; + m_refCounted = false; if (m_refCountMap[m_url] > 0) { m_refCountMap[m_url]--; + std::cerr << "reduced ref count to " << m_refCountMap[m_url] << std::endl; if (m_refCountMap[m_url] > 0) { m_done = true; return; @@ -414,8 +614,9 @@ m_fileCreationMutex.lock(); if (!QFile(m_localFilename).remove()) { - std::cerr << "RemoteFile::deleteLocalFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; + std::cerr << "RemoteFile::deleteCacheFile: ERROR: Failed to delete file \"" << m_localFilename.toStdString() << "\"" << std::endl; } else { + std::cerr << "RemoteFile::deleteCacheFile: Deleted cache file \"" << m_localFilename.toStdString() << "\"" << std::endl; m_localFilename = ""; } @@ -430,19 +631,33 @@ if (m_progressDialog) m_progressDialog->show(); } -QString -RemoteFile::createLocalFile(QUrl url) +bool +RemoteFile::createCacheFile() { + { + QMutexLocker locker(&m_mapMutex); + + std::cerr << "RemoteFile::createCacheFile: refcount is " << m_refCountMap[m_url] << std::endl; + + if (m_refCountMap[m_url] > 0) { + m_refCountMap[m_url]++; + m_localFilename = m_remoteLocalMap[m_url]; + std::cerr << "raised it to " << m_refCountMap[m_url] << std::endl; + m_refCounted = true; + return true; + } + } + QDir dir; try { dir = TempDirectory::getInstance()->getSubDirectoryPath("download"); } catch (DirectoryCreationFailed f) { - std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; + std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create temporary directory: " << f.what() << std::endl; return ""; } - QString filepart = url.path().section('/', -1, -1, - QString::SectionSkipEmpty); + QString filepart = m_url.path().section('/', -1, -1, + QString::SectionSkipEmpty); QString extension = filepart.section('.', -1); QString base = filepart; @@ -461,17 +676,18 @@ QString filepath(dir.filePath(filename)); - std::cerr << "RemoteFile::createLocalFile: URL is \"" << url.toString().toStdString() << "\", dir is \"" << dir.path().toStdString() << "\", base \"" << base.toStdString() << "\", extension \"" << extension.toStdString() << "\", filebase \"" << filename.toStdString() << "\", filename \"" << filepath.toStdString() << "\"" << std::endl; + std::cerr << "RemoteFile::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; - m_fileCreationMutex.lock(); + QMutexLocker fcLocker(&m_fileCreationMutex); + ++m_count; if (QFileInfo(filepath).exists() || !QFile(filepath).open(QFile::WriteOnly)) { - std::cerr << "RemoteFile::createLocalFile: Failed to create local file \"" + std::cerr << "RemoteFile::createCacheFile: Failed to create local file \"" << filepath.toStdString() << "\" for URL \"" - << url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; + << m_url.toString().toStdString() << "\" (or file already exists): appending suffix instead" << std::endl; if (extension == "") { @@ -484,20 +700,19 @@ if (QFileInfo(filepath).exists() || !QFile(filepath).open(QFile::WriteOnly)) { - std::cerr << "RemoteFile::createLocalFile: ERROR: Failed to create local file \"" + std::cerr << "RemoteFile::createCacheFile: ERROR: Failed to create local file \"" << filepath.toStdString() << "\" for URL \"" - << url.toString().toStdString() << "\" (or file already exists)" << std::endl; + << m_url.toString().toStdString() << "\" (or file already exists)" << std::endl; - m_fileCreationMutex.unlock(); return ""; } } - m_fileCreationMutex.unlock(); - - std::cerr << "RemoteFile::createLocalFile: url " - << url.toString().toStdString() << " -> local filename " + std::cerr << "RemoteFile::createCacheFile: url " + << m_url.toString().toStdString() << " -> local filename " << filepath.toStdString() << std::endl; + + m_localFilename = filepath; - return filepath; + return false; } Modified: sonic-visualiser/trunk/data/fileio/RemoteFile.h =================================================================== --- sonic-visualiser/trunk/data/fileio/RemoteFile.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/RemoteFile.h 2007-10-18 15:31:20 UTC (rev 788) @@ -34,23 +34,30 @@ Q_OBJECT public: - RemoteFile(QUrl url); + RemoteFile(QString fileOrUrl, bool showProgress = true); + RemoteFile(QUrl url, bool showProgress = true); + RemoteFile(const RemoteFile &); + virtual ~RemoteFile(); bool isAvailable(); - void wait(); + void waitForStatus(); + void waitForData(); + void setLeaveLocalFile(bool leave); + bool isOK() const; bool isDone() const; + bool isRemote() const; + QString getLocation() const; + QString getLocalFilename() const; QString getContentType() const; + QString getExtension() const; - QString getLocalFilename() const; QString getErrorString() const; - void deleteLocalFile(); - static bool isRemote(QString fileOrUrl); static bool canHandleScheme(QUrl url); @@ -68,6 +75,8 @@ void cancelled(); protected: + RemoteFile &operator=(const RemoteFile &); // not provided + QUrl m_url; QFtp *m_ftp; QHttp *m_http; @@ -77,7 +86,9 @@ QString m_contentType; bool m_ok; int m_lastStatus; + bool m_remote; bool m_done; + bool m_leaveLocalFile; QProgressDialog *m_progressDialog; QTimer m_progressShowTimer; @@ -86,11 +97,18 @@ static RemoteRefCountMap m_refCountMap; static RemoteLocalMap m_remoteLocalMap; static QMutex m_mapMutex; - bool m_referenced; + bool m_refCounted; + void init(bool showProgress); + void initHttp(); + void initFtp(); + void cleanup(); - QString createLocalFile(QUrl url); + // Create a local file for m_url. If it already existed, return true. + // The local filename is stored in m_localFilename. + bool createCacheFile(); + void deleteCacheFile(); static QMutex m_fileCreationMutex; static int m_count; Modified: sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -22,12 +22,13 @@ #include <QFileInfo> #include <QApplication> -ResamplingWavFileReader::ResamplingWavFileReader(QString path, +ResamplingWavFileReader::ResamplingWavFileReader(RemoteFile source, ResampleMode resampleMode, CacheMode mode, size_t targetRate) : CodedAudioFileReader(mode, targetRate), - m_path(path), + m_source(source), + m_path(source.getLocalFilename()), m_cancelled(false), m_processed(0), m_completion(0), @@ -39,11 +40,11 @@ m_fileRate = 0; std::cerr << "ResamplingWavFileReader::ResamplingWavFileReader(\"" - << path.toStdString() << "\"): rate " << targetRate << std::endl; + << m_path.toStdString() << "\"): rate " << targetRate << std::endl; Profiler profiler("ResamplingWavFileReader::ResamplingWavFileReader", true); - m_original = new WavFileReader(path); + m_original = new WavFileReader(m_path); if (!m_original->isOK()) { m_error = m_original->getError(); return; @@ -57,7 +58,7 @@ if (resampleMode == ResampleAtOnce) { m_progress = new QProgressDialog - (QObject::tr("Resampling %1...").arg(QFileInfo(path).fileName()), + (QObject::tr("Resampling %1...").arg(QFileInfo(m_path).fileName()), QObject::tr("Stop"), 0, 100); m_progress->hide(); @@ -167,4 +168,22 @@ WavFileReader::getSupportedExtensions(extensions); } +bool +ResamplingWavFileReader::supportsExtension(QString extension) +{ + return WavFileReader::supportsExtension(extension); +} +bool +ResamplingWavFileReader::supportsContentType(QString type) +{ + return WavFileReader::supportsContentType(type); +} + +bool +ResamplingWavFileReader::supports(RemoteFile &source) +{ + return WavFileReader::supports(source); +} + + Modified: sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/ResamplingWavFileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -33,15 +33,17 @@ ResampleThreaded // resample in a background thread after construction }; - ResamplingWavFileReader(QString path, + ResamplingWavFileReader(RemoteFile source, ResampleMode resampleMode, CacheMode cacheMode, size_t targetRate = 0); virtual ~ResamplingWavFileReader(); virtual QString getError() const { return m_error; } - static void getSupportedExtensions(std::set<QString> &extensions); + static bool supportsExtension(QString ext); + static bool supportsContentType(QString type); + static bool supports(RemoteFile &source); virtual int getDecodeCompletion() const { return m_completion; } @@ -50,6 +52,7 @@ } protected: + RemoteFile m_source; QString m_path; QString m_error; bool m_cancelled; Modified: sonic-visualiser/trunk/data/fileio/WavFileReader.cpp =================================================================== --- sonic-visualiser/trunk/data/fileio/WavFileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/WavFileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -18,10 +18,12 @@ #include <iostream> #include <QMutexLocker> +#include <QFileInfo> -WavFileReader::WavFileReader(QString path, bool fileUpdating) : +WavFileReader::WavFileReader(RemoteFile source, bool fileUpdating) : m_file(0), - m_path(path), + m_source(source), + m_path(source.getLocalFilename()), m_buffer(0), m_bufsiz(0), m_lastStart(0), @@ -171,6 +173,7 @@ if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) { extensions.insert("wav"); extensions.insert("aiff"); + extensions.insert("aifc"); extensions.insert("aif"); return; } @@ -179,7 +182,32 @@ for (int i = 0; i < count; ++i) { info.format = i; if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) { - extensions.insert(info.extension); + extensions.insert(QString(info.extension).toLower()); } } } + +bool +WavFileReader::supportsExtension(QString extension) +{ + std::set<QString> extensions; + getSupportedExtensions(extensions); + return (extensions.find(extension.toLower()) != extensions.end()); +} + +bool +WavFileReader::supportsContentType(QString type) +{ + return (type == "audio/x-wav" || + type == "audio/x-aiff" || + type == "audio/basic"); +} + +bool +WavFileReader::supports(RemoteFile &source) +{ + return (supportsExtension(source.getExtension()) || + supportsContentType(source.getContentType())); +} + + Modified: sonic-visualiser/trunk/data/fileio/WavFileReader.h =================================================================== --- sonic-visualiser/trunk/data/fileio/WavFileReader.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/fileio/WavFileReader.h 2007-10-18 15:31:20 UTC (rev 788) @@ -26,7 +26,7 @@ class WavFileReader : public AudioFileReader { public: - WavFileReader(QString path, bool fileUpdating = false); + WavFileReader(RemoteFile source, bool fileUpdating = false); virtual ~WavFileReader(); virtual QString getError() const { return m_error; } @@ -39,6 +39,9 @@ SampleBlock &frames) const; static void getSupportedExtensions(std::set<QString> &extensions); + static bool supportsExtension(QString ext); + static bool supportsContentType(QString type); + static bool supports(RemoteFile &source); virtual int getDecodeCompletion() const { return 100; } @@ -51,6 +54,7 @@ SF_INFO m_fileInfo; SNDFILE *m_file; + RemoteFile m_source; QString m_path; QString m_error; Modified: sonic-visualiser/trunk/data/model/WaveFileModel.cpp =================================================================== --- sonic-visualiser/trunk/data/model/WaveFileModel.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/model/WaveFileModel.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -39,8 +39,9 @@ PowerOfSqrtTwoZoomConstraint WaveFileModel::m_zoomConstraint; -WaveFileModel::WaveFileModel(QString path, size_t targetRate) : - m_path(path), +WaveFileModel::WaveFileModel(RemoteFile source, size_t targetRate) : + m_source(source), + m_path(source.getLocation()), m_myReader(true), m_startFrame(0), m_fillThread(0), @@ -48,31 +49,22 @@ m_lastFillExtent(0), m_exiting(false) { - m_reader = AudioFileReaderFactory::createReader(path, targetRate); - if (m_reader) std::cerr << "WaveFileModel::WaveFileModel: reader rate: " << m_reader->getSampleRate() << std::endl; + m_source.waitForData(); + if (m_source.isOK()) { + m_reader = AudioFileReaderFactory::createReader(m_source, targetRate); + if (m_reader) { + std::cerr << "WaveFileModel::WaveFileModel: reader rate: " + << m_reader->getSampleRate() << std::endl; + } + } if (m_reader) setObjectName(m_reader->getTitle()); - if (objectName() == "") setObjectName(QFileInfo(path).fileName()); + if (objectName() == "") setObjectName(QFileInfo(m_path).fileName()); if (isOK()) fillCache(); } -WaveFileModel::WaveFileModel(QString path, QString originalLocation, size_t targetRate) : - m_path(originalLocation), - m_myReader(true), - m_startFrame(0), - m_fillThread(0), - m_updateTimer(0), - m_lastFillExtent(0), - m_exiting(false) -{ - m_reader = AudioFileReaderFactory::createReader(path, targetRate); - if (m_reader) std::cerr << "WaveFileModel::WaveFileModel: reader rate: " << m_reader->getSampleRate() << std::endl; - if (m_reader) setObjectName(m_reader->getTitle()); - if (objectName() == "") setObjectName(QFileInfo(originalLocation).fileName()); - if (isOK()) fillCache(); -} - -WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) : - m_path(path), +WaveFileModel::WaveFileModel(RemoteFile source, AudioFileReader *reader) : + m_source(source), + m_path(source.getLocation()), m_myReader(false), m_startFrame(0), m_fillThread(0), @@ -82,7 +74,7 @@ { m_reader = reader; if (m_reader) setObjectName(m_reader->getTitle()); - if (objectName() == "") setObjectName(QFileInfo(path).fileName()); + if (objectName() == "") setObjectName(QFileInfo(m_path).fileName()); fillCache(); } @@ -131,7 +123,7 @@ Model * WaveFileModel::clone() const { - WaveFileModel *model = new WaveFileModel(m_path); + WaveFileModel *model = new WaveFileModel(m_source); return model; } Modified: sonic-visualiser/trunk/data/model/WaveFileModel.h =================================================================== --- sonic-visualiser/trunk/data/model/WaveFileModel.h 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/model/WaveFileModel.h 2007-10-18 15:31:20 UTC (rev 788) @@ -20,6 +20,8 @@ #include <QMutex> #include <QTimer> +#include "data/fileio/RemoteFile.h" + #include "RangeSummarisableTimeValueModel.h" #include "PowerOfSqrtTwoZoomConstraint.h" @@ -32,9 +34,8 @@ Q_OBJECT public: - WaveFileModel(QString path, size_t targetRate = 0); - WaveFileModel(QString path, QString originalLocation, size_t targetRate = 0); - WaveFileModel(QString originalLocation, AudioFileReader *reader); + WaveFileModel(RemoteFile source, size_t targetRate = 0); + WaveFileModel(RemoteFile source, AudioFileReader *reader); ~WaveFileModel(); bool isOK() const; @@ -102,7 +103,8 @@ }; void fillCache(); - + + RemoteFile m_source; QString m_path; AudioFileReader *m_reader; bool m_myReader; Modified: sonic-visualiser/trunk/data/model/WritableWaveFileModel.cpp =================================================================== --- sonic-visualiser/trunk/data/model/WritableWaveFileModel.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/data/model/WritableWaveFileModel.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -60,7 +60,9 @@ return; } - m_reader = new WavFileReader(m_writer->getPath(), true); + RemoteFile source(m_writer->getPath()); + + m_reader = new WavFileReader(source, true); if (!m_reader->getError().isEmpty()) { std::cerr << "WritableWaveFileModel: Error in creating wave file reader" << std::endl; delete m_reader; @@ -68,7 +70,7 @@ return; } - m_model = new WaveFileModel(m_writer->getPath(), m_reader); + m_model = new WaveFileModel(source, m_reader); if (!m_model->isOK()) { std::cerr << "WritableWaveFileModel: Error in creating wave file model" << std::endl; delete m_model; Modified: sonic-visualiser/trunk/layer/ImageLayer.cpp =================================================================== --- sonic-visualiser/trunk/layer/ImageLayer.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/layer/ImageLayer.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -892,16 +892,13 @@ return; } - QUrl url(img); - if (RemoteFile::canHandleScheme(url)) { - RemoteFile *rf = new RemoteFile(url); - if (rf->isOK()) { - std::cerr << "ok, adding it (local filename = " << rf->getLocalFilename().toStdString() << ")" << std::endl; - m_remoteFiles[img] = rf; - connect(rf, SIGNAL(ready()), this, SLOT(remoteFileReady())); - } else { - delete rf; - } + RemoteFile *rf = new RemoteFile(img); + if (rf->isOK()) { + std::cerr << "ok, adding it (local filename = " << rf->getLocalFilename().toStdString() << ")" << std::endl; + m_remoteFiles[img] = rf; + connect(rf, SIGNAL(ready()), this, SLOT(remoteFileReady())); + } else { + delete rf; } } } Modified: sonic-visualiser/trunk/sv/document/SVFileReader.cpp =================================================================== --- sonic-visualiser/trunk/sv/document/SVFileReader.cpp 2007-10-18 10:24:26 UTC (rev 787) +++ sonic-visualiser/trunk/sv/document/SVFileReader.cpp 2007-10-18 15:31:20 UTC (rev 788) @@ -412,25 +412,18 @@ QString originalPath = attributes.value("file"); QString path = ff->find(FileFinder::AudioFile, ... [truncated message content] |