annotate data/model/WritableWaveFileModel.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents 0fd3661bcfff
children 9f4505ac9072
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@723 29 #include <stdint.h>
Chris@175 30
Chris@258 31 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
Chris@187 32
Chris@1040 33 WritableWaveFileModel::WritableWaveFileModel(sv_samplerate_t sampleRate,
Chris@929 34 int channels,
Chris@175 35 QString path) :
Chris@175 36 m_model(0),
Chris@175 37 m_writer(0),
Chris@175 38 m_reader(0),
Chris@175 39 m_sampleRate(sampleRate),
Chris@175 40 m_channels(channels),
Chris@188 41 m_frameCount(0),
Chris@300 42 m_startFrame(0),
Chris@188 43 m_completion(0)
Chris@175 44 {
Chris@175 45 if (path.isEmpty()) {
Chris@175 46 try {
Chris@175 47 QDir dir(TempDirectory::getInstance()->getPath());
Chris@175 48 path = dir.filePath(QString("written_%1.wav")
Chris@175 49 .arg((intptr_t)this));
Chris@175 50 } catch (DirectoryCreationFailed f) {
Chris@843 51 cerr << "WritableWaveFileModel: Failed to create temporary directory" << endl;
Chris@175 52 return;
Chris@175 53 }
Chris@175 54 }
Chris@175 55
Chris@684 56 // Write directly to the target file, so that we can do
Chris@684 57 // incremental writes and concurrent reads
Chris@684 58 m_writer = new WavFileWriter(path, sampleRate, channels,
Chris@684 59 WavFileWriter::WriteToTarget);
Chris@175 60 if (!m_writer->isOK()) {
Chris@843 61 cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError() << endl;
Chris@175 62 delete m_writer;
Chris@175 63 m_writer = 0;
Chris@175 64 return;
Chris@175 65 }
Chris@187 66
Chris@317 67 FileSource source(m_writer->getPath());
Chris@316 68
Chris@316 69 m_reader = new WavFileReader(source, true);
Chris@290 70 if (!m_reader->getError().isEmpty()) {
Chris@843 71 cerr << "WritableWaveFileModel: Error in creating wave file reader" << endl;
Chris@187 72 delete m_reader;
Chris@187 73 m_reader = 0;
Chris@187 74 return;
Chris@187 75 }
Chris@187 76
Chris@316 77 m_model = new WaveFileModel(source, m_reader);
Chris@187 78 if (!m_model->isOK()) {
Chris@843 79 cerr << "WritableWaveFileModel: Error in creating wave file model" << endl;
Chris@187 80 delete m_model;
Chris@187 81 m_model = 0;
Chris@187 82 delete m_reader;
Chris@187 83 m_reader = 0;
Chris@187 84 return;
Chris@187 85 }
Chris@300 86 m_model->setStartFrame(m_startFrame);
Chris@187 87
Chris@258 88 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@1038 89 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@1038 90 this, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@175 91 }
Chris@175 92
Chris@175 93 WritableWaveFileModel::~WritableWaveFileModel()
Chris@175 94 {
Chris@175 95 delete m_model;
Chris@175 96 delete m_writer;
Chris@175 97 delete m_reader;
Chris@175 98 }
Chris@175 99
Chris@300 100 void
Chris@1038 101 WritableWaveFileModel::setStartFrame(sv_frame_t startFrame)
Chris@300 102 {
Chris@300 103 m_startFrame = startFrame;
Chris@300 104 if (m_model) m_model->setStartFrame(startFrame);
Chris@300 105 }
Chris@300 106
Chris@175 107 bool
Chris@1038 108 WritableWaveFileModel::addSamples(float **samples, sv_frame_t count)
Chris@175 109 {
Chris@175 110 if (!m_writer) return false;
Chris@175 111
Chris@258 112 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@690 113 // SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl;
Chris@258 114 #endif
Chris@258 115
Chris@175 116 if (!m_writer->writeSamples(samples, count)) {
Chris@843 117 cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError() << endl;
Chris@175 118 return false;
Chris@175 119 }
Chris@175 120
Chris@175 121 m_frameCount += count;
Chris@175 122
Chris@187 123 static int updateCounter = 0;
Chris@175 124
Chris@187 125 if (m_reader && m_reader->getChannelCount() == 0) {
Chris@258 126 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@690 127 SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << endl;
Chris@258 128 #endif
Chris@187 129 m_reader->updateFrameCount();
Chris@187 130 } else if (++updateCounter == 100) {
Chris@258 131 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@690 132 SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << endl;
Chris@258 133 #endif
Chris@175 134 if (m_reader) m_reader->updateFrameCount();
Chris@175 135 updateCounter = 0;
Chris@175 136 }
Chris@175 137
Chris@175 138 return true;
Chris@175 139 }
Chris@175 140
Chris@175 141 bool
Chris@175 142 WritableWaveFileModel::isOK() const
Chris@175 143 {
Chris@187 144 bool ok = (m_writer && m_writer->isOK());
Chris@690 145 // SVDEBUG << "WritableWaveFileModel::isOK(): ok = " << ok << endl;
Chris@175 146 return ok;
Chris@175 147 }
Chris@175 148
Chris@175 149 bool
Chris@175 150 WritableWaveFileModel::isReady(int *completion) const
Chris@175 151 {
Chris@188 152 if (completion) *completion = m_completion;
Chris@188 153 return (m_completion == 100);
Chris@188 154 }
Chris@188 155
Chris@188 156 void
Chris@188 157 WritableWaveFileModel::setCompletion(int completion)
Chris@188 158 {
Chris@188 159 m_completion = completion;
Chris@188 160 if (completion == 100) {
Chris@188 161 if (m_reader) m_reader->updateDone();
Chris@188 162 }
Chris@175 163 }
Chris@175 164
Chris@1038 165 sv_frame_t
Chris@175 166 WritableWaveFileModel::getFrameCount() const
Chris@175 167 {
Chris@690 168 // SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl;
Chris@175 169 return m_frameCount;
Chris@175 170 }
Chris@175 171
Chris@1038 172 sv_frame_t
Chris@1038 173 WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 174 float *buffer) const
Chris@175 175 {
Chris@187 176 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@300 177 return m_model->getData(channel, start, count, buffer);
Chris@175 178 }
Chris@175 179
Chris@1038 180 sv_frame_t
Chris@1038 181 WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 182 double *buffer) const
Chris@175 183 {
Chris@187 184 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@300 185 return m_model->getData(channel, start, count, buffer);
Chris@175 186 }
Chris@175 187
Chris@1038 188 sv_frame_t
Chris@929 189 WritableWaveFileModel::getData(int fromchannel, int tochannel,
Chris@1038 190 sv_frame_t start, sv_frame_t count,
Chris@363 191 float **buffers) const
Chris@363 192 {
Chris@363 193 if (!m_model || m_model->getChannelCount() == 0) return 0;
Chris@363 194 return m_model->getData(fromchannel, tochannel, start, count, buffers);
Chris@363 195 }
Chris@363 196
Chris@929 197 int
Chris@929 198 WritableWaveFileModel::getSummaryBlockSize(int desired) const
Chris@377 199 {
Chris@377 200 if (!m_model) return desired;
Chris@377 201 return m_model->getSummaryBlockSize(desired);
Chris@377 202 }
Chris@377 203
Chris@225 204 void
Chris@1038 205 WritableWaveFileModel::getSummaries(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 206 RangeBlock &ranges,
Chris@929 207 int &blockSize) const
Chris@175 208 {
Chris@225 209 ranges.clear();
Chris@225 210 if (!m_model || m_model->getChannelCount() == 0) return;
Chris@300 211 m_model->getSummaries(channel, start, count, ranges, blockSize);
Chris@175 212 }
Chris@175 213
Chris@175 214 WritableWaveFileModel::Range
Chris@1038 215 WritableWaveFileModel::getSummary(int channel, sv_frame_t start, sv_frame_t count) const
Chris@175 216 {
Chris@187 217 if (!m_model || m_model->getChannelCount() == 0) return Range();
Chris@300 218 return m_model->getSummary(channel, start, count);
Chris@175 219 }
Chris@175 220
Chris@175 221 void
Chris@175 222 WritableWaveFileModel::toXml(QTextStream &out,
Chris@175 223 QString indent,
Chris@175 224 QString extraAttributes) const
Chris@175 225 {
Chris@188 226 // We don't actually write the data to XML. We just write a brief
Chris@188 227 // description of the model. Any code that uses this class is
Chris@188 228 // going to need to be aware that it will have to make separate
Chris@188 229 // arrangements for the audio file itself.
Chris@187 230
Chris@188 231 Model::toXml
Chris@188 232 (out, indent,
Chris@188 233 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
Chris@603 234 .arg(encodeEntities(m_writer->getPath()))
Chris@603 235 .arg(m_model->getChannelCount()).arg(extraAttributes));
Chris@175 236 }
Chris@175 237