annotate data/fileio/CodedAudioFileReader.cpp @ 263:71dfc6ab3b54

* Threaded mp3/ogg file reading. Not activated yet, as it doesn't work in context (SV needs to know the duration of its main model at the outset)
author Chris Cannam
date Thu, 24 May 2007 16:20:22 +0000
parents 900ac6667eab
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