annotate data/model/WritableWaveFileModel.cpp @ 316:3a6725f285d6

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 70a232b1f12a
children c324d410b096
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@314 25 #include <QTextStream>
Chris@175 26
Chris@175 27 #include <cassert>
Chris@175 28 #include <iostream>
Chris@175 29
Chris@258 30 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
Chris@187 31
Chris@175 32 WritableWaveFileModel::WritableWaveFileModel(size_t sampleRate,
Chris@175 33 size_t channels,
Chris@175 34 QString path) :
Chris@175 35 m_model(0),
Chris@175 36 m_writer(0),
Chris@175 37 m_reader(0),
Chris@175 38 m_sampleRate(sampleRate),
Chris@175 39 m_channels(channels),
Chris@188 40 m_frameCount(0),
Chris@300 41 m_startFrame(0),
Chris@188 42 m_completion(0)
Chris@175 43 {
Chris@175 44 if (path.isEmpty()) {
Chris@175 45 try {
Chris@175 46 QDir dir(TempDirectory::getInstance()->getPath());
Chris@175 47 path = dir.filePath(QString("written_%1.wav")
Chris@175 48 .arg((intptr_t)this));
Chris@175 49 } catch (DirectoryCreationFailed f) {
Chris@175 50 std::cerr << "WritableWaveFileModel: Failed to create temporary directory" << std::endl;
Chris@175 51 return;
Chris@175 52 }
Chris@175 53 }
Chris@175 54
Chris@175 55 m_writer = new WavFileWriter(path, sampleRate, channels);
Chris@175 56 if (!m_writer->isOK()) {
Chris@175 57 std::cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError().toStdString() << std::endl;
Chris@175 58 delete m_writer;
Chris@175 59 m_writer = 0;
Chris@175 60 return;
Chris@175 61 }
Chris@187 62
Chris@316 63 RemoteFile source(m_writer->getPath());
Chris@316 64
Chris@316 65 m_reader = new WavFileReader(source, true);
Chris@290 66 if (!m_reader->getError().isEmpty()) {
Chris@187 67 std::cerr << "WritableWaveFileModel: Error in creating wave file reader" << std::endl;
Chris@187 68 delete m_reader;
Chris@187 69 m_reader = 0;
Chris@187 70 return;
Chris@187 71 }
Chris@187 72
Chris@316 73 m_model = new WaveFileModel(source, m_reader);
Chris@187 74 if (!m_model->isOK()) {
Chris@187 75 std::cerr << "WritableWaveFileModel: Error in creating wave file model" << std::endl;
Chris@187 76 delete m_model;
Chris@187 77 m_model = 0;
Chris@187 78 delete m_reader;
Chris@187 79 m_reader = 0;
Chris@187 80 return;
Chris@187 81 }
Chris@300 82 m_model->setStartFrame(m_startFrame);
Chris@187 83
Chris@258 84 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@258 85 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@187 86 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@175 87 }
Chris@175 88
Chris@175 89 WritableWaveFileModel::~WritableWaveFileModel()
Chris@175 90 {
Chris@175 91 delete m_model;
Chris@175 92 delete m_writer;
Chris@175 93 delete m_reader;
Chris@175 94 }
Chris@175 95
Chris@300 96 void
Chris@300 97 WritableWaveFileModel::setStartFrame(size_t startFrame)
Chris@300 98 {
Chris@300 99 m_startFrame = startFrame;
Chris@300 100 if (m_model) m_model->setStartFrame(startFrame);
Chris@300 101 }
Chris@300 102
Chris@175 103 bool
Chris@175 104 WritableWaveFileModel::addSamples(float **samples, size_t count)
Chris@175 105 {
Chris@175 106 if (!m_writer) return false;
Chris@175 107
Chris@258 108 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 109 // std::cerr << "WritableWaveFileModel::addSamples(" << count << ")" << std::endl;
Chris@258 110 #endif
Chris@258 111
Chris@175 112 if (!m_writer->writeSamples(samples, count)) {
Chris@175 113 std::cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError().toStdString() << std::endl;
Chris@175 114 return false;
Chris@175 115 }
Chris@175 116
Chris@175 117 m_frameCount += count;
Chris@175 118
Chris@187 119 static int updateCounter = 0;
Chris@175 120
Chris@187 121 if (m_reader && m_reader->getChannelCount() == 0) {
Chris@258 122 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 123 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << std::endl;
Chris@258 124 #endif
Chris@187 125 m_reader->updateFrameCount();
Chris@187 126 } else if (++updateCounter == 100) {
Chris@258 127 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@258 128 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << std::endl;
Chris@258 129 #endif
Chris@175 130 if (m_reader) m_reader->updateFrameCount();
Chris@175 131 updateCounter = 0;
Chris@175 132 }
Chris@175 133
Chris@175 134 return true;
Chris@175 135 }
Chris@175 136
Chris@175 137 bool
Chris@175 138 WritableWaveFileModel::isOK() const
Chris@175 139 {
Chris@187 140 bool ok = (m_writer && m_writer->isOK());
Chris@188 141 // std::cerr << "WritableWaveFileModel::isOK(): ok = " << ok << std::endl;
Chris@175 142 return ok;
Chris@175 143 }
Chris@175 144
Chris@175 145 bool
Chris@175 146 WritableWaveFileModel::isReady(int *completion) const
Chris@175 147 {
Chris@188 148 if (completion) *completion = m_completion;
Chris@188 149 return (m_completion == 100);
Chris@188 150 }
Chris@188 151
Chris@188 152 void
Chris@188 153 WritableWaveFileModel::setCompletion(int completion)
Chris@188 154 {
Chris@188 155 m_completion = completion;
Chris@188 156 if (completion == 100) {
Chris@188 157 if (m_reader) m_reader->updateDone();
Chris@188 158 }
Chris@175 159 }
Chris@175 160
Chris@175 161 size_t
Chris@175 162 WritableWaveFileModel::getFrameCount() const
Chris@175 163 {
Chris@188 164 // std::cerr << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << std::endl;
Chris@175 165 return m_frameCount;
Chris@175 166 }
Chris@175 167
Chris@175 168 Model *
Chris@175 169 WritableWaveFileModel::clone() const
Chris@175 170 {
Chris@175 171 assert(0); //!!!
Chris@188 172 return 0;
Chris@175 173 }
Chris@175 174
Chris@175 175 size_t
Chris@300 176 WritableWaveFileModel::getData(int channel, size_t start, size_t count,
Chris@300 177 float *buffer) const
Chris@175 178 {
Chris@187 179 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@300 180 return m_model->getData(channel, start, count, buffer);
Chris@175 181 }
Chris@175 182
Chris@175 183 size_t
Chris@300 184 WritableWaveFileModel::getData(int channel, size_t start, size_t count,
Chris@300 185 double *buffer) const
Chris@175 186 {
Chris@187 187 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@175 188 // std::cerr << "WritableWaveFileModel::getValues(" << channel << ", "
Chris@175 189 // << start << ", " << end << "): calling model" << std::endl;
Chris@300 190 return m_model->getData(channel, start, count, buffer);
Chris@175 191 }
Chris@175 192
Chris@225 193 void
Chris@300 194 WritableWaveFileModel::getSummaries(size_t channel, size_t start, size_t count,
Chris@300 195 RangeBlock &ranges,
Chris@300 196 size_t &blockSize) const
Chris@175 197 {
Chris@225 198 ranges.clear();
Chris@225 199 if (!m_model || m_model->getChannelCount() == 0) return;
Chris@300 200 m_model->getSummaries(channel, start, count, ranges, blockSize);
Chris@175 201 }
Chris@175 202
Chris@175 203 WritableWaveFileModel::Range
Chris@300 204 WritableWaveFileModel::getSummary(size_t channel, size_t start, size_t count) const
Chris@175 205 {
Chris@187 206 if (!m_model || m_model->getChannelCount() == 0) return Range();
Chris@300 207 return m_model->getSummary(channel, start, count);
Chris@175 208 }
Chris@175 209
Chris@175 210 void
Chris@175 211 WritableWaveFileModel::toXml(QTextStream &out,
Chris@175 212 QString indent,
Chris@175 213 QString extraAttributes) const
Chris@175 214 {
Chris@188 215 // We don't actually write the data to XML. We just write a brief
Chris@188 216 // description of the model. Any code that uses this class is
Chris@188 217 // going to need to be aware that it will have to make separate
Chris@188 218 // arrangements for the audio file itself.
Chris@187 219
Chris@188 220 Model::toXml
Chris@188 221 (out, 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