svcore
1.9
|
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