svcore  1.9
WritableWaveFileModel.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 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 "WritableWaveFileModel.h"
00017 
00018 #include "base/TempDirectory.h"
00019 #include "base/Exceptions.h"
00020 
00021 #include "fileio/WavFileWriter.h"
00022 #include "fileio/WavFileReader.h"
00023 
00024 #include <QDir>
00025 #include <QTextStream>
00026 
00027 #include <cassert>
00028 #include <iostream>
00029 #include <stdint.h>
00030 
00031 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
00032 
00033 WritableWaveFileModel::WritableWaveFileModel(int sampleRate,
00034                                              int channels,
00035                                              QString path) :
00036     m_model(0),
00037     m_writer(0),
00038     m_reader(0),
00039     m_sampleRate(sampleRate),
00040     m_channels(channels),
00041     m_frameCount(0),
00042     m_startFrame(0),
00043     m_completion(0)
00044 {
00045     if (path.isEmpty()) {
00046         try {
00047             QDir dir(TempDirectory::getInstance()->getPath());
00048             path = dir.filePath(QString("written_%1.wav")
00049                                 .arg((intptr_t)this));
00050         } catch (DirectoryCreationFailed f) {
00051             cerr << "WritableWaveFileModel: Failed to create temporary directory" << endl;
00052             return;
00053         }
00054     }
00055 
00056     // Write directly to the target file, so that we can do
00057     // incremental writes and concurrent reads
00058     m_writer = new WavFileWriter(path, sampleRate, channels,
00059                                  WavFileWriter::WriteToTarget);
00060     if (!m_writer->isOK()) {
00061         cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError() << endl;
00062         delete m_writer; 
00063         m_writer = 0;
00064         return;
00065     }
00066 
00067     FileSource source(m_writer->getPath());
00068 
00069     m_reader = new WavFileReader(source, true);
00070     if (!m_reader->getError().isEmpty()) {
00071         cerr << "WritableWaveFileModel: Error in creating wave file reader" << endl;
00072         delete m_reader;
00073         m_reader = 0;
00074         return;
00075     }
00076     
00077     m_model = new WaveFileModel(source, m_reader);
00078     if (!m_model->isOK()) {
00079         cerr << "WritableWaveFileModel: Error in creating wave file model" << endl;
00080         delete m_model;
00081         m_model = 0;
00082         delete m_reader;
00083         m_reader = 0;
00084         return;
00085     }
00086     m_model->setStartFrame(m_startFrame);
00087 
00088     connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
00089     connect(m_model, SIGNAL(modelChangedWithin(int, int)),
00090             this, SIGNAL(modelChangedWithin(int, int)));
00091 }
00092 
00093 WritableWaveFileModel::~WritableWaveFileModel()
00094 {
00095     delete m_model;
00096     delete m_writer;
00097     delete m_reader;
00098 }
00099 
00100 void
00101 WritableWaveFileModel::setStartFrame(int startFrame)
00102 {
00103     m_startFrame = startFrame;
00104     if (m_model) m_model->setStartFrame(startFrame);
00105 }
00106 
00107 bool
00108 WritableWaveFileModel::addSamples(float **samples, int count)
00109 {
00110     if (!m_writer) return false;
00111 
00112 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
00113 //    SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl;
00114 #endif
00115 
00116     if (!m_writer->writeSamples(samples, count)) {
00117         cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError() << endl;
00118         return false;
00119     }
00120 
00121     m_frameCount += count;
00122 
00123     static int updateCounter = 0;
00124 
00125     if (m_reader && m_reader->getChannelCount() == 0) {
00126 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
00127         SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << endl;
00128 #endif
00129         m_reader->updateFrameCount();
00130     } else if (++updateCounter == 100) {
00131 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
00132         SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << endl;
00133 #endif
00134         if (m_reader) m_reader->updateFrameCount();
00135         updateCounter = 0;
00136     }
00137 
00138     return true;
00139 }
00140 
00141 bool
00142 WritableWaveFileModel::isOK() const
00143 {
00144     bool ok = (m_writer && m_writer->isOK());
00145 //    SVDEBUG << "WritableWaveFileModel::isOK(): ok = " << ok << endl;
00146     return ok;
00147 }
00148 
00149 bool
00150 WritableWaveFileModel::isReady(int *completion) const
00151 {
00152     if (completion) *completion = m_completion;
00153     return (m_completion == 100);
00154 }
00155 
00156 void
00157 WritableWaveFileModel::setCompletion(int completion)
00158 {
00159     m_completion = completion;
00160     if (completion == 100) {
00161         if (m_reader) m_reader->updateDone();
00162     }
00163 }
00164 
00165 int
00166 WritableWaveFileModel::getFrameCount() const
00167 {
00168 //    SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl;
00169     return m_frameCount;
00170 }
00171 
00172 Model *
00173 WritableWaveFileModel::clone() const
00174 {
00175     assert(0); 
00176     return 0;
00177 }
00178 
00179 int
00180 WritableWaveFileModel::getData(int channel, int start, int count,
00181                                float *buffer) const
00182 {
00183     if (!m_model || m_model->getChannelCount() == 0) return 0;
00184     return m_model->getData(channel, start, count, buffer);
00185 }
00186 
00187 int
00188 WritableWaveFileModel::getData(int channel, int start, int count,
00189                                double *buffer) const
00190 {
00191     if (!m_model || m_model->getChannelCount() == 0) return 0;
00192     return m_model->getData(channel, start, count, buffer);
00193 }
00194 
00195 int
00196 WritableWaveFileModel::getData(int fromchannel, int tochannel,
00197                                int start, int count,
00198                                float **buffers) const
00199 {
00200     if (!m_model || m_model->getChannelCount() == 0) return 0;
00201     return m_model->getData(fromchannel, tochannel, start, count, buffers);
00202 }    
00203 
00204 int
00205 WritableWaveFileModel::getSummaryBlockSize(int desired) const
00206 {
00207     if (!m_model) return desired;
00208     return m_model->getSummaryBlockSize(desired);
00209 }
00210 
00211 void
00212 WritableWaveFileModel::getSummaries(int channel, int start, int count,
00213                                     RangeBlock &ranges,
00214                                     int &blockSize) const
00215 {
00216     ranges.clear();
00217     if (!m_model || m_model->getChannelCount() == 0) return;
00218     m_model->getSummaries(channel, start, count, ranges, blockSize);
00219 }
00220 
00221 WritableWaveFileModel::Range
00222 WritableWaveFileModel::getSummary(int channel, int start, int count) const
00223 {
00224     if (!m_model || m_model->getChannelCount() == 0) return Range();
00225     return m_model->getSummary(channel, start, count);
00226 }
00227 
00228 void
00229 WritableWaveFileModel::toXml(QTextStream &out,
00230                              QString indent,
00231                              QString extraAttributes) const
00232 {
00233     // We don't actually write the data to XML.  We just write a brief
00234     // description of the model.  Any code that uses this class is
00235     // going to need to be aware that it will have to make separate
00236     // arrangements for the audio file itself.
00237 
00238     Model::toXml
00239         (out, indent,
00240          QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
00241          .arg(encodeEntities(m_writer->getPath()))
00242          .arg(m_model->getChannelCount()).arg(extraAttributes));
00243 }
00244