00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "CodedAudioFileReader.h"
00017
00018 #include "WavFileReader.h"
00019 #include "base/TempDirectory.h"
00020 #include "base/Exceptions.h"
00021 #include "base/Profiler.h"
00022 #include "base/Serialiser.h"
00023 #include "base/Resampler.h"
00024
00025 #include <iostream>
00026 #include <QDir>
00027 #include <QMutexLocker>
00028
00029 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode,
00030 size_t targetRate) :
00031 m_cacheMode(cacheMode),
00032 m_initialised(false),
00033 m_serialiser(0),
00034 m_fileRate(0),
00035 m_cacheFileWritePtr(0),
00036 m_cacheFileReader(0),
00037 m_cacheWriteBuffer(0),
00038 m_cacheWriteBufferIndex(0),
00039 m_cacheWriteBufferSize(16384),
00040 m_resampler(0),
00041 m_resampleBuffer(0)
00042 {
00043
00044
00045 m_frameCount = 0;
00046 m_sampleRate = targetRate;
00047 }
00048
00049 CodedAudioFileReader::~CodedAudioFileReader()
00050 {
00051 QMutexLocker locker(&m_cacheMutex);
00052
00053 endSerialised();
00054
00055 if (m_cacheFileWritePtr) sf_close(m_cacheFileWritePtr);
00056
00057 delete m_cacheFileReader;
00058 delete[] m_cacheWriteBuffer;
00059
00060 if (m_cacheFileName != "") {
00061 if (!QFile(m_cacheFileName).remove()) {
00062 std::cerr << "WARNING: CodedAudioFileReader::~CodedAudioFileReader: Failed to delete cache file \"" << m_cacheFileName.toStdString() << "\"" << std::endl;
00063 }
00064 }
00065
00066 delete m_resampler;
00067 delete[] m_resampleBuffer;
00068 }
00069
00070 void
00071 CodedAudioFileReader::startSerialised(QString id)
00072 {
00073
00074
00075 delete m_serialiser;
00076 m_serialiser = new Serialiser(id);
00077 }
00078
00079 void
00080 CodedAudioFileReader::endSerialised()
00081 {
00082
00083
00084 delete m_serialiser;
00085 m_serialiser = 0;
00086 }
00087
00088 void
00089 CodedAudioFileReader::initialiseDecodeCache()
00090 {
00091 QMutexLocker locker(&m_cacheMutex);
00092
00093 std::cerr << "CodedAudioFileReader::initialiseDecodeCache: file rate = " << m_fileRate << std::endl;
00094
00095 if (m_fileRate == 0) {
00096 std::cerr << "CodedAudioFileReader::initialiseDecodeCache: ERROR: File sample rate unknown (bug in subclass implementation?)" << std::endl;
00097 m_fileRate = 48000;
00098 }
00099 if (m_sampleRate == 0) {
00100 m_sampleRate = m_fileRate;
00101 }
00102 if (m_fileRate != m_sampleRate) {
00103 std::cerr << "CodedAudioFileReader: resampling " << m_fileRate << " -> " << m_sampleRate << std::endl;
00104 m_resampler = new Resampler(Resampler::FastestTolerable,
00105 m_channelCount,
00106 m_cacheWriteBufferSize);
00107 float ratio = float(m_sampleRate) / float(m_fileRate);
00108 m_resampleBuffer = new float
00109 [lrintf(ceilf(m_cacheWriteBufferSize * m_channelCount * ratio))];
00110 }
00111
00112 m_cacheWriteBuffer = new float[m_cacheWriteBufferSize * m_channelCount];
00113 m_cacheWriteBufferIndex = 0;
00114
00115 if (m_cacheMode == CacheInTemporaryFile) {
00116
00117 try {
00118 QDir dir(TempDirectory::getInstance()->getPath());
00119 m_cacheFileName = dir.filePath(QString("decoded_%1.wav")
00120 .arg((intptr_t)this));
00121
00122 SF_INFO fileInfo;
00123 fileInfo.samplerate = m_sampleRate;
00124 fileInfo.channels = m_channelCount;
00125
00126
00127
00128
00129 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
00130
00131 m_cacheFileWritePtr = sf_open(m_cacheFileName.toLocal8Bit(),
00132 SFM_WRITE, &fileInfo);
00133
00134 if (m_cacheFileWritePtr) {
00135
00136
00137
00138
00139
00140
00141 m_cacheFileReader = new WavFileReader(m_cacheFileName);
00142
00143 if (!m_cacheFileReader->isOK()) {
00144 std::cerr << "ERROR: CodedAudioFileReader::initialiseDecodeCache: Failed to construct WAV file reader for temporary file: " << m_cacheFileReader->getError().toStdString() << std::endl;
00145 delete m_cacheFileReader;
00146 m_cacheFileReader = 0;
00147 m_cacheMode = CacheInMemory;
00148 sf_close(m_cacheFileWritePtr);
00149 }
00150
00151 } else {
00152 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;
00153 m_cacheMode = CacheInMemory;
00154 }
00155
00156 } catch (DirectoryCreationFailed f) {
00157 std::cerr << "CodedAudioFileReader::initialiseDecodeCache: failed to create temporary directory! Falling back to in-memory cache" << std::endl;
00158 m_cacheMode = CacheInMemory;
00159 }
00160 }
00161
00162 if (m_cacheMode == CacheInMemory) {
00163 m_data.clear();
00164 }
00165
00166 m_initialised = true;
00167 }
00168
00169 void
00170 CodedAudioFileReader::addSamplesToDecodeCache(float **samples, size_t nframes)
00171 {
00172 QMutexLocker locker(&m_cacheMutex);
00173
00174 if (!m_initialised) return;
00175
00176 for (size_t i = 0; i < nframes; ++i) {
00177
00178 for (size_t c = 0; c < m_channelCount; ++c) {
00179
00180 float sample = samples[c][i];
00181
00182 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample;
00183
00184 if (m_cacheWriteBufferIndex ==
00185 m_cacheWriteBufferSize * m_channelCount) {
00186
00187 pushBuffer(m_cacheWriteBuffer, m_cacheWriteBufferSize, false);
00188 m_cacheWriteBufferIndex = 0;
00189 }
00190
00191 if (m_cacheWriteBufferIndex % 10240 == 0 &&
00192 m_cacheFileReader) {
00193 m_cacheFileReader->updateFrameCount();
00194 }
00195 }
00196 }
00197 }
00198
00199 void
00200 CodedAudioFileReader::addSamplesToDecodeCache(float *samples, size_t nframes)
00201 {
00202 QMutexLocker locker(&m_cacheMutex);
00203
00204 if (!m_initialised) return;
00205
00206 for (size_t i = 0; i < nframes; ++i) {
00207
00208 for (size_t c = 0; c < m_channelCount; ++c) {
00209
00210 float sample = samples[i * m_channelCount + c];
00211
00212 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample;
00213
00214 if (m_cacheWriteBufferIndex ==
00215 m_cacheWriteBufferSize * m_channelCount) {
00216
00217 pushBuffer(m_cacheWriteBuffer, m_cacheWriteBufferSize, false);
00218 m_cacheWriteBufferIndex = 0;
00219 }
00220
00221 if (m_cacheWriteBufferIndex % 10240 == 0 &&
00222 m_cacheFileReader) {
00223 m_cacheFileReader->updateFrameCount();
00224 }
00225 }
00226 }
00227 }
00228
00229 void
00230 CodedAudioFileReader::addSamplesToDecodeCache(const SampleBlock &samples)
00231 {
00232 QMutexLocker locker(&m_cacheMutex);
00233
00234 if (!m_initialised) return;
00235
00236 for (size_t i = 0; i < samples.size(); ++i) {
00237
00238 float sample = samples[i];
00239
00240 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample;
00241
00242 if (m_cacheWriteBufferIndex ==
00243 m_cacheWriteBufferSize * m_channelCount) {
00244
00245 pushBuffer(m_cacheWriteBuffer, m_cacheWriteBufferSize, false);
00246 m_cacheWriteBufferIndex = 0;
00247 }
00248
00249 if (m_cacheWriteBufferIndex % 10240 == 0 &&
00250 m_cacheFileReader) {
00251 m_cacheFileReader->updateFrameCount();
00252 }
00253 }
00254 }
00255
00256 void
00257 CodedAudioFileReader::finishDecodeCache()
00258 {
00259 QMutexLocker locker(&m_cacheMutex);
00260
00261 Profiler profiler("CodedAudioFileReader::finishDecodeCache", true);
00262
00263 if (!m_initialised) {
00264 std::cerr << "WARNING: CodedAudioFileReader::finishDecodeCache: Cache was never initialised!" << std::endl;
00265 return;
00266 }
00267
00268 if (m_cacheWriteBufferIndex > 0) {
00270 pushBuffer(m_cacheWriteBuffer,
00271 m_cacheWriteBufferIndex / m_channelCount,
00272 true);
00273 }
00274
00275 delete[] m_cacheWriteBuffer;
00276 m_cacheWriteBuffer = 0;
00277
00278 delete[] m_resampleBuffer;
00279 m_resampleBuffer = 0;
00280
00281 delete m_resampler;
00282 m_resampler = 0;
00283
00284 if (m_cacheMode == CacheInTemporaryFile) {
00285 sf_close(m_cacheFileWritePtr);
00286 m_cacheFileWritePtr = 0;
00287 if (m_cacheFileReader) m_cacheFileReader->updateFrameCount();
00288 }
00289 }
00290
00291 void
00292 CodedAudioFileReader::pushBuffer(float *buffer, size_t sz, bool final)
00293 {
00294 float max = 1.0;
00295 size_t count = sz * m_channelCount;
00296
00297 if (m_resampler && m_fileRate != 0) {
00298
00299 float ratio = float(m_sampleRate) / float(m_fileRate);
00300
00301 if (ratio != 1.f) {
00302
00303 size_t out = m_resampler->resampleInterleaved
00304 (buffer,
00305 m_resampleBuffer,
00306 sz,
00307 ratio,
00308 final);
00309
00310 buffer = m_resampleBuffer;
00311 sz = out;
00312 count = sz * m_channelCount;
00313 }
00314 }
00315
00316 for (size_t i = 0; i < count; ++i) {
00317 if (buffer[i] > max) buffer[i] = max;
00318 }
00319 for (size_t i = 0; i < count; ++i) {
00320 if (buffer[i] < -max) buffer[i] = -max;
00321 }
00322
00323 m_frameCount += sz;
00324
00325 switch (m_cacheMode) {
00326
00327 case CacheInTemporaryFile:
00329 sf_writef_float(m_cacheFileWritePtr, buffer, sz);
00330 break;
00331
00332 case CacheInMemory:
00333 for (size_t s = 0; s < count; ++s) {
00334 m_data.push_back(buffer[count]);
00335 }
00336 MUNLOCK_SAMPLEBLOCK(m_data);
00337 break;
00338 }
00339 }
00340
00341 void
00342 CodedAudioFileReader::getInterleavedFrames(size_t start, size_t count,
00343 SampleBlock &frames) const
00344 {
00346
00347
00348 if (!m_initialised) {
00349 std::cerr << "CodedAudioFileReader::getInterleavedFrames: not initialised" << std::endl;
00350 return;
00351 }
00352
00353 switch (m_cacheMode) {
00354
00355 case CacheInTemporaryFile:
00356 if (m_cacheFileReader) {
00357 m_cacheFileReader->getInterleavedFrames(start, count, frames);
00358 }
00359 break;
00360
00361 case CacheInMemory:
00362 {
00363 frames.clear();
00364 if (!isOK()) return;
00365 if (count == 0) return;
00366
00367
00368
00369 for (size_t i = start; i < start + count; ++i) {
00370 for (size_t ch = 0; ch < m_channelCount; ++ch) {
00371 size_t index = i * m_channelCount + ch;
00372 if (index >= m_data.size()) return;
00373 frames.push_back(m_data[index]);
00374 }
00375 }
00376 }
00377 }
00378 }
00379