# HG changeset patch # User Chris Cannam # Date 1434375337 -3600 # Node ID 329ddaf7415d9469c3ff957d45defd2f200c82e3 # Parent abc309f507aedc15723819c6d1ab44e3c86e228a Store temporary audio files in memory if we have plenty of it diff -r abc309f507ae -r 329ddaf7415d base/StorageAdviser.cpp --- a/base/StorageAdviser.cpp Mon Jun 15 12:38:50 2015 +0100 +++ b/base/StorageAdviser.cpp Mon Jun 15 14:35:37 2015 +0100 @@ -22,7 +22,7 @@ #include -//#define DEBUG_STORAGE_ADVISER 1 +#define DEBUG_STORAGE_ADVISER 1 size_t StorageAdviser::m_discPlanned = 0; size_t StorageAdviser::m_memoryPlanned = 0; @@ -36,9 +36,9 @@ size_t maximumSize) { #ifdef DEBUG_STORAGE_ADVISER - SVDEBUG << "StorageAdviser::recommend: Criteria " << criteria - << ", minimumSize " << minimumSize - << ", maximumSize " << maximumSize << endl; + cerr << "StorageAdviser::recommend: Criteria " << criteria + << ", minimumSize " << minimumSize + << ", maximumSize " << maximumSize << endl; #endif if (m_baseRecommendation != NoRecommendation) { @@ -181,6 +181,10 @@ } } +#ifdef DEBUG_STORAGE_ADVISER + cerr << "StorageAdviser: returning recommendation " << recommendation << endl; +#endif + return Recommendation(recommendation); } diff -r abc309f507ae -r 329ddaf7415d data/fileio/AudioFileReaderFactory.cpp --- a/data/fileio/AudioFileReaderFactory.cpp Mon Jun 15 12:38:50 2015 +0100 +++ b/data/fileio/AudioFileReaderFactory.cpp Mon Jun 15 14:35:37 2015 +0100 @@ -21,6 +21,9 @@ #include "MP3FileReader.h" #include "QuickTimeFileReader.h" #include "CoreAudioFileReader.h" +#include "AudioFileSizeEstimator.h" + +#include "base/StorageAdviser.h" #include #include @@ -98,9 +101,22 @@ AudioFileReader *reader = 0; + sv_frame_t estimatedSamples = + AudioFileSizeEstimator::estimate(source, targetRate); + CodedAudioFileReader::CacheMode cacheMode = CodedAudioFileReader::CacheInTemporaryFile; + if (estimatedSamples > 0) { + size_t kb = (estimatedSamples * sizeof(float)) / 1024; + StorageAdviser::Recommendation rec = + StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb); + if (rec == StorageAdviser::UseMemory || + rec == StorageAdviser::PreferMemory) { + cacheMode = CodedAudioFileReader::CacheInMemory; + } + } + CodedAudioFileReader::DecodeMode decodeMode = (threading ? CodedAudioFileReader::DecodeThreaded : diff -r abc309f507ae -r 329ddaf7415d data/fileio/AudioFileReaderFactory.h --- a/data/fileio/AudioFileReaderFactory.h Mon Jun 15 12:38:50 2015 +0100 +++ b/data/fileio/AudioFileReaderFactory.h Mon Jun 15 14:35:37 2015 +0100 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _AUDIO_FILE_READER_FACTORY_H_ -#define _AUDIO_FILE_READER_FACTORY_H_ +#ifndef AUDIO_FILE_READER_FACTORY_H +#define AUDIO_FILE_READER_FACTORY_H #include diff -r abc309f507ae -r 329ddaf7415d data/fileio/AudioFileSizeEstimator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/AudioFileSizeEstimator.cpp Mon Jun 15 14:35:37 2015 +0100 @@ -0,0 +1,101 @@ +/* -*- 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 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 "AudioFileSizeEstimator.h" + +#include "WavFileReader.h" + +#include + +sv_frame_t +AudioFileSizeEstimator::estimate(FileSource source, + sv_samplerate_t targetRate) +{ + sv_frame_t estimate = 0; + + // Most of our file readers don't know the sample count until + // after they've finished decoding. This is an exception: + + WavFileReader *reader = new WavFileReader(source); + if (reader->isOK() && + reader->getChannelCount() > 0 && + reader->getFrameCount() > 0) { + sv_frame_t samples = + reader->getFrameCount() * reader->getChannelCount(); + sv_samplerate_t rate = reader->getSampleRate(); + if (targetRate != 0.0 && targetRate != rate) { + samples = sv_frame_t(double(samples) * targetRate / rate); + } + delete reader; + estimate = samples; + } + + if (estimate == 0) { + + // The remainder just makes an estimate based on the file size + // and extension. We don't even know its sample rate at this + // point, so the following is a wild guess. + + double rateRatio = 1.0; + if (targetRate != 0.0) { + rateRatio = targetRate / 44100.0; + } + + QString extension = source.getExtension(); + + source.waitForData(); + if (!source.isOK()) return 0; + + sv_frame_t sz = 0; + { + QFile f(source.getLocalFilename()); + if (f.open(QFile::ReadOnly)) { + cerr << "opened file, size is " << f.size() << endl; + sz = f.size(); + f.close(); + } + } + + if (extension == "ogg" || extension == "oga" || + extension == "m4a" || extension == "mp3" || + extension == "wma") { + + // Usually a lossy file. Compression ratios can vary + // dramatically, but don't usually exceed about 20x compared + // to 16-bit PCM (e.g. a 128kbps mp3 has 11x ratio over WAV at + // 44.1kHz). We can estimate the number of samples to be file + // size x 20, divided by 2 as we're comparing with 16-bit PCM. + + estimate = sv_frame_t(double(sz) * 10 * rateRatio); + } + + if (extension == "flac") { + + // FLAC usually takes up a bit more than half the space of + // 16-bit PCM. So the number of 16-bit samples is roughly the + // same as the file size in bytes. As above, let's be + // conservative. + + estimate = sv_frame_t(double(sz) * 1.2 * rateRatio); + } + + cerr << "AudioFileSizeEstimator: for extension " << extension << ", estimate = " << estimate << endl; + + } + + cerr << "estimate = " << estimate << endl; + + return estimate; +} + diff -r abc309f507ae -r 329ddaf7415d data/fileio/AudioFileSizeEstimator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fileio/AudioFileSizeEstimator.h Mon Jun 15 14:35:37 2015 +0100 @@ -0,0 +1,49 @@ +/* -*- 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 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 AUDIO_FILE_SIZE_ESTIMATOR_H +#define AUDIO_FILE_SIZE_ESTIMATOR_H + +#include "base/BaseTypes.h" +#include "data/fileio/FileSource.h" + +/** + * Estimate the number of samples in an audio file. For many + * compressed files this returns only a very approximate estimate, + * based on a rough estimate of compression ratio. Initially we're + * only aiming for a conservative estimate for purposes like "will + * this file fit in memory?" (and if unsure, say no). + */ +class AudioFileSizeEstimator +{ +public: + /** + * Return an estimate of the number of samples (across all + * channels) in the given audio file, once it has been decoded and + * (if applicable) resampled to the given rate. + * + * This function is intended to be reasonably fast -- it may open + * the file, but it should not do any decoding. (However, if the + * file source is remote, it will probably be downloaded in its + * entirety before anything can be estimated.) + * + * The returned value is an estimate, and is deliberately usually + * on the high side. If the estimator has no idea at all, this + * will return 0. + */ + static sv_frame_t estimate(FileSource source, + sv_samplerate_t targetRate = 0); +}; + +#endif diff -r abc309f507ae -r 329ddaf7415d data/fileio/CodedAudioFileReader.cpp --- a/data/fileio/CodedAudioFileReader.cpp Mon Jun 15 12:38:50 2015 +0100 +++ b/data/fileio/CodedAudioFileReader.cpp Mon Jun 15 14:35:37 2015 +0100 @@ -21,6 +21,7 @@ #include "base/Profiler.h" #include "base/Serialiser.h" #include "base/Resampler.h" +#include "base/StorageAdviser.h" #include #include @@ -59,7 +60,7 @@ QMutexLocker locker(&m_cacheMutex); endSerialised(); - + if (m_cacheFileWritePtr) sf_close(m_cacheFileWritePtr); SVDEBUG << "CodedAudioFileReader::~CodedAudioFileReader: deleting cache file reader" << endl; @@ -75,6 +76,12 @@ delete m_resampler; delete[] m_resampleBuffer; + + if (!m_data.empty()) { + StorageAdviser::notifyDoneAllocation + (StorageAdviser::MemoryAllocation, + (m_data.size() * sizeof(float)) / 1024); + } } void @@ -294,9 +301,16 @@ m_resampler = 0; if (m_cacheMode == CacheInTemporaryFile) { + sf_close(m_cacheFileWritePtr); m_cacheFileWritePtr = 0; if (m_cacheFileReader) m_cacheFileReader->updateFrameCount(); + + } else { + // I know, I know, we already allocated it... + StorageAdviser::notifyPlannedAllocation + (StorageAdviser::MemoryAllocation, + (m_data.size() * sizeof(float)) / 1024); } } diff -r abc309f507ae -r 329ddaf7415d data/fileio/FileSource.h --- a/data/fileio/FileSource.h Mon Jun 15 12:38:50 2015 +0100 +++ b/data/fileio/FileSource.h Mon Jun 15 14:35:37 2015 +0100 @@ -167,7 +167,8 @@ QString getContentType() const; /** - * Return the file extension for this file, if any. + * Return the file extension for this file, if any. The returned + * extension is always lower-case. */ QString getExtension() const; diff -r abc309f507ae -r 329ddaf7415d svcore.pro --- a/svcore.pro Mon Jun 15 12:38:50 2015 +0100 +++ b/svcore.pro Mon Jun 15 14:35:37 2015 +0100 @@ -121,6 +121,7 @@ HEADERS += data/fft/FFTapi.h \ data/fileio/AudioFileReader.h \ data/fileio/AudioFileReaderFactory.h \ + data/fileio/AudioFileSizeEstimator.h \ data/fileio/BZipFileDevice.h \ data/fileio/CachedFile.h \ data/fileio/CodedAudioFileReader.h \ @@ -179,6 +180,7 @@ SOURCES += data/fft/FFTapi.cpp \ data/fileio/AudioFileReader.cpp \ data/fileio/AudioFileReaderFactory.cpp \ + data/fileio/AudioFileSizeEstimator.cpp \ data/fileio/BZipFileDevice.cpp \ data/fileio/CachedFile.cpp \ data/fileio/CodedAudioFileReader.cpp \