annotate data/model/WritableWaveFileModel.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 166c22eff678
children e43368ec5ff0
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@317 63 FileSource 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@300 188 return m_model->getData(channel, start, count, buffer);
Chris@175 189 }
Chris@175 190
Chris@363 191 size_t
Chris@363 192 WritableWaveFileModel::getData(size_t fromchannel, size_t tochannel,
Chris@363 193 size_t start, size_t count,
Chris@363 194 float **buffers) const
Chris@363 195 {
Chris@363 196 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@363 197 return m_model->getData(fromchannel, tochannel, start, count, buffers);
Chris@363 198 }
Chris@363 199
Chris@377 200 size_t
Chris@377 201 WritableWaveFileModel::getSummaryBlockSize(size_t desired) const
Chris@377 202 {
Chris@377 203 if (!m_model) return desired;
Chris@377 204 return m_model->getSummaryBlockSize(desired);
Chris@377 205 }
Chris@377 206
Chris@225 207 void
Chris@300 208 WritableWaveFileModel::getSummaries(size_t channel, size_t start, size_t count,
Chris@300 209 RangeBlock &ranges,
Chris@300 210 size_t &blockSize) const
Chris@175 211 {
Chris@225 212 ranges.clear();
Chris@225 213 if (!m_model || m_model->getChannelCount() == 0) return;
Chris@300 214 m_model->getSummaries(channel, start, count, ranges, blockSize);
Chris@175 215 }
Chris@175 216
Chris@175 217 WritableWaveFileModel::Range
Chris@300 218 WritableWaveFileModel::getSummary(size_t channel, size_t start, size_t count) const
Chris@175 219 {
Chris@187 220 if (!m_model || m_model->getChannelCount() == 0) return Range();
Chris@300 221 return m_model->getSummary(channel, start, count);
Chris@175 222 }
Chris@175 223
Chris@175 224 void
Chris@175 225 WritableWaveFileModel::toXml(QTextStream &out,
Chris@175 226 QString indent,
Chris@175 227 QString extraAttributes) const
Chris@175 228 {
Chris@188 229 // We don't actually write the data to XML. We just write a brief
Chris@188 230 // description of the model. Any code that uses this class is
Chris@188 231 // going to need to be aware that it will have to make separate
Chris@188 232 // arrangements for the audio file itself.
Chris@187 233
Chris@188 234 Model::toXml
Chris@188 235 (out, indent,
Chris@188 236 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
Chris@188 237 .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes));
Chris@175 238 }
Chris@175 239