CodedAudioFileReader.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006-2007 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
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 //    std::cerr << "CodedAudioFileReader::CodedAudioFileReader: rate " << targetRate << std::endl;
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 //    std::cerr << "CodedAudioFileReader::startSerialised(" << id.toStdString() << ")" << std::endl;
00074 
00075     delete m_serialiser;
00076     m_serialiser = new Serialiser(id);
00077 }
00078 
00079 void
00080 CodedAudioFileReader::endSerialised()
00081 {
00082 //    std::cerr << "CodedAudioFileReader::endSerialised" << std::endl;
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; // got to have something
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             // No point in writing 24-bit or float; generally this
00127             // class is used for decoding files that have come from a
00128             // 16 bit source or that decode to only 16 bits anyway.
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                 // Ideally we would do this now only if we were in a
00137                 // threaded mode -- creating the reader later if we're
00138                 // not threaded -- but we don't have access to that
00139                 // information here
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     // moment it does need one, but it doesn't have one...
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         // slownessabounds
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 

Generated on Wed Feb 20 15:45:25 2008 for SonicVisualiser by  doxygen 1.5.1