annotate data/model/WritableWaveFileModel.cpp @ 1122:b9faee02afa5 recording

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