annotate data/fileio/CodedAudioFileReader.cpp @ 264:260032c26c4f

* don't store fft values scaled by fftsize/2; that's a special requirement for the spectrogram, and other applications will not expect it -- make the spectrogram do that scaling itself * add a higher-resolution memory cache (still polar, though) as an alternative to the 16-bit compact cache * don't use the memory cache if we want rectangular coords (unless the disc cache is totally infeasible) as conversion slows it down anyway * avoid redundant rectangular -> polar -> rectangular conversion when storing values in a rectangular-mode disc cache
author Chris Cannam
date Fri, 01 Jun 2007 13:56:35 +0000
parents 71dfc6ab3b54
children e08f486e8d8c
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@148 7 This file copyright 2006 Chris Cannam.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #include "CodedAudioFileReader.h"
Chris@148 17
Chris@148 18 #include "WavFileReader.h"
Chris@148 19 #include "base/TempDirectory.h"
Chris@148 20 #include "base/Exceptions.h"
Chris@192 21 #include "base/Profiler.h"
Chris@148 22
Chris@148 23 #include <iostream>
Chris@148 24 #include <QDir>
Chris@263 25 #include <QMutexLocker>
Chris@148 26
Chris@148 27 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode) :
Chris@148 28 m_cacheMode(cacheMode),
Chris@148 29 m_initialised(false),
Chris@148 30 m_cacheFileWritePtr(0),
Chris@148 31 m_cacheFileReader(0),
Chris@148 32 m_cacheWriteBuffer(0),
Chris@148 33 m_cacheWriteBufferIndex(0),
Chris@148 34 m_cacheWriteBufferSize(16384)
Chris@148 35 {
Chris@148 36 }
Chris@148 37
Chris@148 38 CodedAudioFileReader::~CodedAudioFileReader()
Chris@148 39 {
Chris@263 40 QMutexLocker locker(&m_cacheMutex);
Chris@263 41
Chris@148 42 if (m_cacheFileWritePtr) sf_close(m_cacheFileWritePtr);
Chris@148 43 if (m_cacheFileReader) delete m_cacheFileReader;
Chris@148 44 if (m_cacheWriteBuffer) delete[] m_cacheWriteBuffer;
Chris@148 45
Chris@148 46 if (m_cacheFileName != "") {
Chris@148 47 if (!QFile(m_cacheFileName).remove()) {
Chris@148 48 std::cerr << "WARNING: CodedAudioFileReader::~CodedAudioFileReader: Failed to delete cache file \"" << m_cacheFileName.toStdString() << "\"" << std::endl;
Chris@148 49 }
Chris@148 50 }
Chris@148 51 }
Chris@148 52
Chris@148 53 void
Chris@148 54 CodedAudioFileReader::initialiseDecodeCache()
Chris@148 55 {
Chris@263 56 QMutexLocker locker(&m_cacheMutex);
Chris@263 57
Chris@148 58 if (m_cacheMode == CacheInTemporaryFile) {
Chris@148 59
Chris@148 60 m_cacheWriteBuffer = new float[m_cacheWriteBufferSize * m_channelCount];
Chris@148 61 m_cacheWriteBufferIndex = 0;
Chris@148 62
Chris@148 63 try {
Chris@148 64 QDir dir(TempDirectory::getInstance()->getPath());
Chris@148 65 m_cacheFileName = dir.filePath(QString("decoded_%1.wav")
Chris@148 66 .arg((intptr_t)this));
Chris@148 67
Chris@148 68 SF_INFO fileInfo;
Chris@148 69 fileInfo.samplerate = m_sampleRate;
Chris@148 70 fileInfo.channels = m_channelCount;
Chris@148 71 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
Chris@148 72
Chris@148 73 m_cacheFileWritePtr = sf_open(m_cacheFileName.toLocal8Bit(),
Chris@148 74 SFM_WRITE, &fileInfo);
Chris@148 75
Chris@148 76 if (!m_cacheFileWritePtr) {
Chris@148 77 std::cerr << "CodedAudioFileReader::initialiseDecodeCache: failed to open cache file \"" << m_cacheFileName.toStdString() << "\" (" << m_channelCount << " channels, sample rate " << m_sampleRate << " for writing, falling back to in-memory cache" << std::endl;
Chris@148 78 m_cacheMode = CacheInMemory;
Chris@148 79 }
Chris@148 80 } catch (DirectoryCreationFailed f) {
Chris@148 81 std::cerr << "CodedAudioFileReader::initialiseDecodeCache: failed to create temporary directory! Falling back to in-memory cache" << std::endl;
Chris@148 82 m_cacheMode = CacheInMemory;
Chris@148 83 }
Chris@148 84 }
Chris@148 85
Chris@148 86 if (m_cacheMode == CacheInMemory) {
Chris@148 87 m_data.clear();
Chris@148 88 }
Chris@148 89
Chris@148 90 m_initialised = true;
Chris@148 91 }
Chris@148 92
Chris@148 93 void
Chris@148 94 CodedAudioFileReader::addSampleToDecodeCache(float sample)
Chris@148 95 {
Chris@263 96 QMutexLocker locker(&m_cacheMutex);
Chris@263 97
Chris@148 98 if (!m_initialised) return;
Chris@148 99
Chris@148 100 switch (m_cacheMode) {
Chris@148 101
Chris@148 102 case CacheInTemporaryFile:
Chris@148 103
Chris@148 104 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample;
Chris@148 105
Chris@148 106 if (m_cacheWriteBufferIndex ==
Chris@148 107 m_cacheWriteBufferSize * m_channelCount) {
Chris@148 108
Chris@148 109 //!!! check for return value! out of disk space, etc!
Chris@148 110 sf_writef_float(m_cacheFileWritePtr,
Chris@148 111 m_cacheWriteBuffer,
Chris@148 112 m_cacheWriteBufferSize);
Chris@148 113
Chris@148 114 m_cacheWriteBufferIndex = 0;
Chris@148 115 }
Chris@148 116 break;
Chris@148 117
Chris@148 118 case CacheInMemory:
Chris@148 119 m_data.push_back(sample);
Chris@148 120 break;
Chris@148 121 }
Chris@148 122 }
Chris@148 123
Chris@148 124 void
Chris@148 125 CodedAudioFileReader::finishDecodeCache()
Chris@148 126 {
Chris@263 127 QMutexLocker locker(&m_cacheMutex);
Chris@263 128
Chris@192 129 Profiler profiler("CodedAudioFileReader::finishDecodeCache", true);
Chris@192 130
Chris@148 131 if (!m_initialised) {
Chris@148 132 std::cerr << "WARNING: CodedAudioFileReader::finishDecodeCache: Cache was never initialised!" << std::endl;
Chris@148 133 return;
Chris@148 134 }
Chris@148 135
Chris@148 136 switch (m_cacheMode) {
Chris@148 137
Chris@148 138 case CacheInTemporaryFile:
Chris@148 139
Chris@148 140 if (m_cacheWriteBufferIndex > 0) {
Chris@148 141 //!!! check for return value! out of disk space, etc!
Chris@148 142 sf_writef_float(m_cacheFileWritePtr,
Chris@148 143 m_cacheWriteBuffer,
Chris@148 144 m_cacheWriteBufferIndex / m_channelCount);
Chris@148 145 }
Chris@148 146
Chris@148 147 if (m_cacheWriteBuffer) {
Chris@148 148 delete[] m_cacheWriteBuffer;
Chris@148 149 m_cacheWriteBuffer = 0;
Chris@148 150 }
Chris@148 151
Chris@148 152 m_cacheWriteBufferIndex = 0;
Chris@148 153
Chris@148 154 sf_close(m_cacheFileWritePtr);
Chris@148 155 m_cacheFileWritePtr = 0;
Chris@148 156
Chris@148 157 m_cacheFileReader = new WavFileReader(m_cacheFileName);
Chris@148 158
Chris@148 159 if (!m_cacheFileReader->isOK()) {
Chris@148 160 std::cerr << "ERROR: CodedAudioFileReader::finishDecodeCache: Failed to construct WAV file reader for temporary file: " << m_cacheFileReader->getError().toStdString() << std::endl;
Chris@148 161 delete m_cacheFileReader;
Chris@148 162 m_cacheFileReader = 0;
Chris@148 163 }
Chris@148 164 break;
Chris@148 165
Chris@148 166 case CacheInMemory:
Chris@148 167 // nothing to do
Chris@148 168 break;
Chris@148 169 }
Chris@148 170 }
Chris@148 171
Chris@148 172 void
Chris@148 173 CodedAudioFileReader::getInterleavedFrames(size_t start, size_t count,
Chris@148 174 SampleBlock &frames) const
Chris@148 175 {
Chris@263 176 //!!! we want to ensure this doesn't require a lock -- at the
Chris@263 177 // moment it does need one, but it doesn't have one...
Chris@263 178
Chris@148 179 if (!m_initialised) return;
Chris@148 180
Chris@148 181 switch (m_cacheMode) {
Chris@148 182
Chris@148 183 case CacheInTemporaryFile:
Chris@148 184 if (m_cacheFileReader) {
Chris@148 185 m_cacheFileReader->getInterleavedFrames(start, count, frames);
Chris@148 186 }
Chris@148 187 break;
Chris@148 188
Chris@148 189 case CacheInMemory:
Chris@148 190 {
Chris@148 191 frames.clear();
Chris@148 192 if (!isOK()) return;
Chris@148 193 if (count == 0) return;
Chris@148 194
Chris@148 195 // slownessabounds
Chris@148 196
Chris@148 197 for (size_t i = start; i < start + count; ++i) {
Chris@148 198 for (size_t ch = 0; ch < m_channelCount; ++ch) {
Chris@148 199 size_t index = i * m_channelCount + ch;
Chris@148 200 if (index >= m_data.size()) return;
Chris@148 201 frames.push_back(m_data[index]);
Chris@148 202 }
Chris@148 203 }
Chris@148 204 }
Chris@148 205 }
Chris@148 206 }
Chris@148 207