annotate data/model/WritableWaveFileModel.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 96a6dd889c68
children 20028c634494
rev   line source
Chris@175 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@175 2
Chris@175 3 /*
Chris@175 4 Sonic Visualiser
Chris@175 5 An audio file viewer and annotation editor.
Chris@175 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 QMUL.
Chris@175 8
Chris@175 9 This program is free software; you can redistribute it and/or
Chris@175 10 modify it under the terms of the GNU General Public License as
Chris@175 11 published by the Free Software Foundation; either version 2 of the
Chris@175 12 License, or (at your option) any later version. See the file
Chris@175 13 COPYING included with this distribution for more information.
Chris@175 14 */
Chris@175 15
Chris@175 16 #include "WritableWaveFileModel.h"
Chris@175 17
Chris@175 18 #include "base/TempDirectory.h"
Chris@175 19 #include "base/Exceptions.h"
Chris@175 20
Chris@175 21 #include "fileio/WavFileWriter.h"
Chris@175 22 #include "fileio/WavFileReader.h"
Chris@175 23
Chris@175 24 #include <QDir>
Chris@175 25
Chris@175 26 #include <cassert>
Chris@175 27 #include <iostream>
Chris@175 28
Chris@258 29 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
Chris@187 30
Chris@175 31 WritableWaveFileModel::WritableWaveFileModel(size_t sampleRate,
Chris@175 32 size_t channels,
Chris@175 33 QString path) :
Chris@175 34 m_model(0),
Chris@175 35 m_writer(0),
Chris@175 36 m_reader(0),
Chris@175 37 m_sampleRate(sampleRate),
Chris@175 38 m_channels(channels),
Chris@188 39 m_frameCount(0),
Chris@188 40 m_completion(0)
Chris@175 41 {
Chris@175 42 if (path.isEmpty()) {
Chris@175 43 try {
Chris@175 44 QDir dir(TempDirectory::getInstance()->getPath());
Chris@175 45 path = dir.filePath(QString("written_%1.wav")
Chris@175 46 .arg((intptr_t)this));
Chris@175 47 } catch (DirectoryCreationFailed f) {
Chris@175 48 std::cerr << "WritableWaveFileModel: Failed to create temporary directory" << std::endl;
Chris@175 49 return;
Chris@175 50 }
Chris@175 51 }
Chris@175 52
Chris@175 53 m_writer = new WavFileWriter(path, sampleRate, channels);
Chris@175 54 if (!m_writer->isOK()) {
Chris@175 55 std::cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError().toStdString() << std::endl;
Chris@175 56 delete m_writer;
Chris@175 57 m_writer = 0;
Chris@175 58 return;
Chris@175 59 }
Chris@187 60
Chris@187 61 m_reader = new WavFileReader(m_writer->getPath(), true);
Chris@187 62 if (!m_reader->getError().isEmpty()) {
Chris@187 63 std::cerr << "WritableWaveFileModel: Error in creating wave file reader" << std::endl;
Chris@187 64 delete m_reader;
Chris@187 65 m_reader = 0;
Chris@187 66 return;
Chris@187 67 }
Chris@187 68
Chris@187 69 m_model = new WaveFileModel(m_writer->getPath(), m_reader);
Chris@187 70 if (!m_model->isOK()) {
Chris@187 71 std::cerr << "WritableWaveFileModel: Error in creating wave file model" << std::endl;
Chris@187 72 delete m_model;
Chris@187 73 m_model = 0;
Chris@187 74 delete m_reader;
Chris@187 75 m_reader = 0;
Chris@187 76 return;
Chris@187 77 }
Chris@187 78
Chris@258 79 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@258 80 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@187 81 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@175 82 }
Chris@175 83
Chris@175 84 WritableWaveFileModel::~WritableWaveFileModel()
Chris@175 85 {
Chris@175 86 delete m_model;
Chris@175 87 delete m_writer;
Chris@175 88 delete m_reader;
Chris@175 89 }
Chris@175 90
Chris@175 91 bool
Chris@175 92 WritableWaveFileModel::addSamples(float **samples, size_t count)
Chris@175 93 {
Chris@175 94 if (!m_writer) return false;
Chris@175 95
Chris@258 96 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 97 // std::cerr << "WritableWaveFileModel::addSamples(" << count << ")" << std::endl;
Chris@258 98 #endif
Chris@258 99
Chris@175 100 if (!m_writer->writeSamples(samples, count)) {
Chris@175 101 std::cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError().toStdString() << std::endl;
Chris@175 102 return false;
Chris@175 103 }
Chris@175 104
Chris@175 105 m_frameCount += count;
Chris@175 106
Chris@187 107 static int updateCounter = 0;
Chris@175 108
Chris@187 109 if (m_reader && m_reader->getChannelCount() == 0) {
Chris@258 110 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 111 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << std::endl;
Chris@258 112 #endif
Chris@187 113 m_reader->updateFrameCount();
Chris@187 114 } else if (++updateCounter == 100) {
Chris@258 115 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 116 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << std::endl;
Chris@258 117 #endif
Chris@175 118 if (m_reader) m_reader->updateFrameCount();
Chris@175 119 updateCounter = 0;
Chris@175 120 }
Chris@175 121
Chris@175 122 return true;
Chris@175 123 }
Chris@175 124
Chris@175 125 bool
Chris@175 126 WritableWaveFileModel::isOK() const
Chris@175 127 {
Chris@187 128 bool ok = (m_writer && m_writer->isOK());
Chris@188 129 // std::cerr << "WritableWaveFileModel::isOK(): ok = " << ok << std::endl;
Chris@175 130 return ok;
Chris@175 131 }
Chris@175 132
Chris@175 133 bool
Chris@175 134 WritableWaveFileModel::isReady(int *completion) const
Chris@175 135 {
Chris@188 136 if (completion) *completion = m_completion;
Chris@188 137 return (m_completion == 100);
Chris@188 138 }
Chris@188 139
Chris@188 140 void
Chris@188 141 WritableWaveFileModel::setCompletion(int completion)
Chris@188 142 {
Chris@188 143 m_completion = completion;
Chris@188 144 if (completion == 100) {
Chris@188 145 if (m_reader) m_reader->updateDone();
Chris@188 146 }
Chris@175 147 }
Chris@175 148
Chris@175 149 size_t
Chris@175 150 WritableWaveFileModel::getFrameCount() const
Chris@175 151 {
Chris@188 152 // std::cerr << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << std::endl;
Chris@175 153 return m_frameCount;
Chris@175 154 }
Chris@175 155
Chris@175 156 Model *
Chris@175 157 WritableWaveFileModel::clone() const
Chris@175 158 {
Chris@175 159 assert(0); //!!!
Chris@188 160 return 0;
Chris@175 161 }
Chris@175 162
Chris@175 163 size_t
Chris@175 164 WritableWaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@175 165 float *buffer) const
Chris@175 166 {
Chris@187 167 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@175 168 return m_model->getValues(channel, start, end, buffer);
Chris@175 169 }
Chris@175 170
Chris@175 171 size_t
Chris@175 172 WritableWaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@175 173 double *buffer) const
Chris@175 174 {
Chris@187 175 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@175 176 // std::cerr << "WritableWaveFileModel::getValues(" << channel << ", "
Chris@175 177 // << start << ", " << end << "): calling model" << std::endl;
Chris@175 178 return m_model->getValues(channel, start, end, buffer);
Chris@175 179 }
Chris@175 180
Chris@225 181 void
Chris@175 182 WritableWaveFileModel::getRanges(size_t channel, size_t start, size_t end,
Chris@225 183 RangeBlock &ranges,
Chris@175 184 size_t &blockSize) const
Chris@175 185 {
Chris@225 186 ranges.clear();
Chris@225 187 if (!m_model || m_model->getChannelCount() == 0) return;
Chris@225 188 m_model->getRanges(channel, start, end, ranges, blockSize);
Chris@175 189 }
Chris@175 190
Chris@175 191 WritableWaveFileModel::Range
Chris@175 192 WritableWaveFileModel::getRange(size_t channel, size_t start, size_t end) const
Chris@175 193 {
Chris@187 194 if (!m_model || m_model->getChannelCount() == 0) return Range();
Chris@175 195 return m_model->getRange(channel, start, end);
Chris@175 196 }
Chris@175 197
Chris@175 198 void
Chris@175 199 WritableWaveFileModel::toXml(QTextStream &out,
Chris@175 200 QString indent,
Chris@175 201 QString extraAttributes) const
Chris@175 202 {
Chris@188 203 // We don't actually write the data to XML. We just write a brief
Chris@188 204 // description of the model. Any code that uses this class is
Chris@188 205 // going to need to be aware that it will have to make separate
Chris@188 206 // arrangements for the audio file itself.
Chris@187 207
Chris@188 208 Model::toXml
Chris@188 209 (out, indent,
Chris@188 210 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
Chris@188 211 .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes));
Chris@175 212 }
Chris@175 213
Chris@175 214 QString
Chris@175 215 WritableWaveFileModel::toXmlString(QString indent,
Chris@175 216 QString extraAttributes) const
Chris@175 217 {
Chris@188 218 // As above.
Chris@188 219
Chris@188 220 return Model::toXmlString
Chris@188 221 (indent,
Chris@188 222 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
Chris@188 223 .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes));
Chris@175 224 }
Chris@175 225