annotate data/model/WritableWaveFileModel.cpp @ 1517:925d205c39b4 import-audio-data

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