annotate data/model/WritableWaveFileModel.cpp @ 273:f1f47660483d

* Fix up and simplify the LayerTreeModel, removing a horrible memory leak * Move phase-unwrapped frequency estimation from SpectrogramLayer to FFTDataServer * Make the spectrum show peak phase-unwrapped frequencies as well (still needs work) * Start adding piano keyboard horizontal scale to spectrum * Debug output for id3 tags
author Chris Cannam
date Tue, 03 Jul 2007 12:46:18 +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