annotate data/model/WritableWaveFileModel.cpp @ 1455:ec9e65fcf749

The use of the begin/end pairs here just seems to cause too many rows to be deleted (from the visual representation, not the underlying model). Things apparently work better if we just modify the underlying model and let the change signals percolate back up again. To that end, update the change handlers so as to cover their proper ranges with dataChanged signals.
author Chris Cannam
date Mon, 23 Apr 2018 16:03:35 +0100
parents 48e9f538e6e9
children cee1be4fb8c1
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@1096 33 using namespace std;
Chris@1096 34
Chris@1133 35 const int WritableWaveFileModel::PROPORTION_UNKNOWN = -1;
Chris@1133 36
Chris@258 37 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
Chris@187 38
Chris@1040 39 WritableWaveFileModel::WritableWaveFileModel(sv_samplerate_t sampleRate,
Chris@1429 40 int channels,
Chris@1429 41 QString path) :
Chris@175 42 m_model(0),
Chris@175 43 m_writer(0),
Chris@175 44 m_reader(0),
Chris@175 45 m_sampleRate(sampleRate),
Chris@175 46 m_channels(channels),
Chris@188 47 m_frameCount(0),
Chris@300 48 m_startFrame(0),
Chris@1133 49 m_proportion(PROPORTION_UNKNOWN)
Chris@175 50 {
Chris@175 51 if (path.isEmpty()) {
Chris@175 52 try {
Chris@175 53 QDir dir(TempDirectory::getInstance()->getPath());
Chris@175 54 path = dir.filePath(QString("written_%1.wav")
Chris@175 55 .arg((intptr_t)this));
Chris@175 56 } catch (DirectoryCreationFailed f) {
Chris@1428 57 SVCERR << "WritableWaveFileModel: Failed to create temporary directory" << endl;
Chris@175 58 return;
Chris@175 59 }
Chris@175 60 }
Chris@175 61
Chris@684 62 // Write directly to the target file, so that we can do
Chris@684 63 // incremental writes and concurrent reads
Chris@684 64 m_writer = new WavFileWriter(path, sampleRate, channels,
Chris@684 65 WavFileWriter::WriteToTarget);
Chris@175 66 if (!m_writer->isOK()) {
Chris@1428 67 SVCERR << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError() << endl;
Chris@175 68 delete m_writer;
Chris@175 69 m_writer = 0;
Chris@175 70 return;
Chris@175 71 }
Chris@187 72
Chris@317 73 FileSource source(m_writer->getPath());
Chris@316 74
Chris@316 75 m_reader = new WavFileReader(source, true);
Chris@290 76 if (!m_reader->getError().isEmpty()) {
Chris@1428 77 SVCERR << "WritableWaveFileModel: Error in creating wave file reader" << endl;
Chris@187 78 delete m_reader;
Chris@187 79 m_reader = 0;
Chris@187 80 return;
Chris@187 81 }
Chris@187 82
Chris@1122 83 m_model = new ReadOnlyWaveFileModel(source, m_reader);
Chris@187 84 if (!m_model->isOK()) {
Chris@1428 85 SVCERR << "WritableWaveFileModel: Error in creating wave file model" << endl;
Chris@187 86 delete m_model;
Chris@187 87 m_model = 0;
Chris@187 88 delete m_reader;
Chris@187 89 m_reader = 0;
Chris@187 90 return;
Chris@187 91 }
Chris@300 92 m_model->setStartFrame(m_startFrame);
Chris@187 93
Chris@258 94 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@1038 95 connect(m_model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@1038 96 this, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@175 97 }
Chris@175 98
Chris@175 99 WritableWaveFileModel::~WritableWaveFileModel()
Chris@175 100 {
Chris@175 101 delete m_model;
Chris@175 102 delete m_writer;
Chris@175 103 delete m_reader;
Chris@175 104 }
Chris@175 105
Chris@300 106 void
Chris@1038 107 WritableWaveFileModel::setStartFrame(sv_frame_t startFrame)
Chris@300 108 {
Chris@300 109 m_startFrame = startFrame;
Chris@300 110 if (m_model) m_model->setStartFrame(startFrame);
Chris@300 111 }
Chris@300 112
Chris@175 113 bool
Chris@1325 114 WritableWaveFileModel::addSamples(const float *const *samples, sv_frame_t count)
Chris@175 115 {
Chris@175 116 if (!m_writer) return false;
Chris@175 117
Chris@258 118 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
Chris@690 119 // SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl;
Chris@258 120 #endif
Chris@258 121
Chris@175 122 if (!m_writer->writeSamples(samples, count)) {
Chris@1337 123 SVCERR << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError() << endl;
Chris@175 124 return false;
Chris@175 125 }
Chris@175 126
Chris@175 127 m_frameCount += count;
Chris@175 128
Chris@187 129 if (m_reader && m_reader->getChannelCount() == 0) {
Chris@187 130 m_reader->updateFrameCount();
Chris@175 131 }
Chris@175 132
Chris@175 133 return true;
Chris@175 134 }
Chris@175 135
Chris@1337 136 void
Chris@1337 137 WritableWaveFileModel::updateModel()
Chris@1337 138 {
Chris@1337 139 if (m_reader) {
Chris@1337 140 m_reader->updateFrameCount();
Chris@1337 141 }
Chris@1337 142 }
Chris@1337 143
Chris@175 144 bool
Chris@175 145 WritableWaveFileModel::isOK() const
Chris@175 146 {
Chris@187 147 bool ok = (m_writer && m_writer->isOK());
Chris@690 148 // SVDEBUG << "WritableWaveFileModel::isOK(): ok = " << ok << endl;
Chris@175 149 return ok;
Chris@175 150 }
Chris@175 151
Chris@175 152 bool
Chris@175 153 WritableWaveFileModel::isReady(int *completion) const
Chris@175 154 {
Chris@1133 155 int c = getCompletion();
Chris@1133 156 if (completion) *completion = c;
Chris@1133 157 if (!isOK()) return false;
Chris@1133 158 return (c == 100);
Chris@188 159 }
Chris@188 160
Chris@188 161 void
Chris@1133 162 WritableWaveFileModel::setWriteProportion(int proportion)
Chris@188 163 {
Chris@1133 164 m_proportion = proportion;
Chris@1133 165 }
Chris@1133 166
Chris@1133 167 int
Chris@1133 168 WritableWaveFileModel::getWriteProportion() const
Chris@1133 169 {
Chris@1133 170 return m_proportion;
Chris@1133 171 }
Chris@1133 172
Chris@1133 173 void
Chris@1133 174 WritableWaveFileModel::writeComplete()
Chris@1133 175 {
Chris@1336 176 m_writer->close();
Chris@1133 177 if (m_reader) m_reader->updateDone();
Chris@1133 178 m_proportion = 100;
Chris@1133 179 emit modelChanged();
Chris@175 180 }
Chris@175 181
Chris@1038 182 sv_frame_t
Chris@175 183 WritableWaveFileModel::getFrameCount() const
Chris@175 184 {
Chris@690 185 // SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl;
Chris@175 186 return m_frameCount;
Chris@175 187 }
Chris@175 188
Chris@1326 189 floatvec_t
Chris@1096 190 WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
Chris@175 191 {
Chris@1096 192 if (!m_model || m_model->getChannelCount() == 0) return {};
Chris@1096 193 return m_model->getData(channel, start, count);
Chris@175 194 }
Chris@175 195
Chris@1326 196 vector<floatvec_t>
Chris@1086 197 WritableWaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
Chris@1096 198 sv_frame_t start, sv_frame_t count) const
Chris@175 199 {
Chris@1096 200 if (!m_model || m_model->getChannelCount() == 0) return {};
Chris@1096 201 return m_model->getMultiChannelData(fromchannel, tochannel, start, count);
Chris@363 202 }
Chris@363 203
Chris@929 204 int
Chris@929 205 WritableWaveFileModel::getSummaryBlockSize(int desired) const
Chris@377 206 {
Chris@377 207 if (!m_model) return desired;
Chris@377 208 return m_model->getSummaryBlockSize(desired);
Chris@377 209 }
Chris@377 210
Chris@225 211 void
Chris@1038 212 WritableWaveFileModel::getSummaries(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 213 RangeBlock &ranges,
Chris@929 214 int &blockSize) const
Chris@175 215 {
Chris@225 216 ranges.clear();
Chris@225 217 if (!m_model || m_model->getChannelCount() == 0) return;
Chris@300 218 m_model->getSummaries(channel, start, count, ranges, blockSize);
Chris@175 219 }
Chris@175 220
Chris@175 221 WritableWaveFileModel::Range
Chris@1038 222 WritableWaveFileModel::getSummary(int channel, sv_frame_t start, sv_frame_t count) const
Chris@175 223 {
Chris@187 224 if (!m_model || m_model->getChannelCount() == 0) return Range();
Chris@300 225 return m_model->getSummary(channel, start, count);
Chris@175 226 }
Chris@175 227
Chris@175 228 void
Chris@175 229 WritableWaveFileModel::toXml(QTextStream &out,
Chris@175 230 QString indent,
Chris@175 231 QString extraAttributes) const
Chris@175 232 {
Chris@1123 233 // The assumption here is that the underlying wave file has
Chris@1123 234 // already been saved somewhere (its location is available through
Chris@1123 235 // getLocation()) and that the code that uses this class is
Chris@1123 236 // dealing with the problem of making sure it remains available.
Chris@1123 237 // We just write this out as if it were a normal wave file.
Chris@187 238
Chris@188 239 Model::toXml
Chris@188 240 (out, indent,
Chris@1123 241 QString("type=\"wavefile\" file=\"%1\" subtype=\"writable\" %2")
Chris@603 242 .arg(encodeEntities(m_writer->getPath()))
Chris@1123 243 .arg(extraAttributes));
Chris@175 244 }
Chris@175 245