svcore  1.9
WritableWaveFileModel.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "WritableWaveFileModel.h"
17 
18 #include "base/TempDirectory.h"
19 #include "base/Exceptions.h"
20 
21 #include "fileio/WavFileWriter.h"
22 #include "fileio/WavFileReader.h"
23 
24 #include <QDir>
25 #include <QTextStream>
26 
27 #include <cassert>
28 #include <iostream>
29 #include <stdint.h>
30 
31 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
32 
34  int channels,
35  QString path) :
36  m_model(0),
37  m_writer(0),
38  m_reader(0),
39  m_sampleRate(sampleRate),
40  m_channels(channels),
41  m_frameCount(0),
42  m_startFrame(0),
43  m_completion(0)
44 {
45  if (path.isEmpty()) {
46  try {
47  QDir dir(TempDirectory::getInstance()->getPath());
48  path = dir.filePath(QString("written_%1.wav")
49  .arg((intptr_t)this));
50  } catch (DirectoryCreationFailed f) {
51  cerr << "WritableWaveFileModel: Failed to create temporary directory" << endl;
52  return;
53  }
54  }
55 
56  // Write directly to the target file, so that we can do
57  // incremental writes and concurrent reads
58  m_writer = new WavFileWriter(path, sampleRate, channels,
60  if (!m_writer->isOK()) {
61  cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError() << endl;
62  delete m_writer;
63  m_writer = 0;
64  return;
65  }
66 
67  FileSource source(m_writer->getPath());
68 
69  m_reader = new WavFileReader(source, true);
70  if (!m_reader->getError().isEmpty()) {
71  cerr << "WritableWaveFileModel: Error in creating wave file reader" << endl;
72  delete m_reader;
73  m_reader = 0;
74  return;
75  }
76 
77  m_model = new WaveFileModel(source, m_reader);
78  if (!m_model->isOK()) {
79  cerr << "WritableWaveFileModel: Error in creating wave file model" << endl;
80  delete m_model;
81  m_model = 0;
82  delete m_reader;
83  m_reader = 0;
84  return;
85  }
87 
88  connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
89  connect(m_model, SIGNAL(modelChangedWithin(int, int)),
90  this, SIGNAL(modelChangedWithin(int, int)));
91 }
92 
94 {
95  delete m_model;
96  delete m_writer;
97  delete m_reader;
98 }
99 
100 void
102 {
103  m_startFrame = startFrame;
104  if (m_model) m_model->setStartFrame(startFrame);
105 }
106 
107 bool
108 WritableWaveFileModel::addSamples(float **samples, int count)
109 {
110  if (!m_writer) return false;
111 
112 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
113 // SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl;
114 #endif
115 
116  if (!m_writer->writeSamples(samples, count)) {
117  cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError() << endl;
118  return false;
119  }
120 
121  m_frameCount += count;
122 
123  static int updateCounter = 0;
124 
125  if (m_reader && m_reader->getChannelCount() == 0) {
126 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
127  SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << endl;
128 #endif
130  } else if (++updateCounter == 100) {
131 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
132  SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << endl;
133 #endif
135  updateCounter = 0;
136  }
137 
138  return true;
139 }
140 
141 bool
143 {
144  bool ok = (m_writer && m_writer->isOK());
145 // SVDEBUG << "WritableWaveFileModel::isOK(): ok = " << ok << endl;
146  return ok;
147 }
148 
149 bool
150 WritableWaveFileModel::isReady(int *completion) const
151 {
152  if (completion) *completion = m_completion;
153  return (m_completion == 100);
154 }
155 
156 void
158 {
159  m_completion = completion;
160  if (completion == 100) {
161  if (m_reader) m_reader->updateDone();
162  }
163 }
164 
165 int
167 {
168 // SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl;
169  return m_frameCount;
170 }
171 
172 Model *
174 {
175  assert(0);
176  return 0;
177 }
178 
179 int
180 WritableWaveFileModel::getData(int channel, int start, int count,
181  float *buffer) const
182 {
183  if (!m_model || m_model->getChannelCount() == 0) return 0;
184  return m_model->getData(channel, start, count, buffer);
185 }
186 
187 int
188 WritableWaveFileModel::getData(int channel, int start, int count,
189  double *buffer) const
190 {
191  if (!m_model || m_model->getChannelCount() == 0) return 0;
192  return m_model->getData(channel, start, count, buffer);
193 }
194 
195 int
196 WritableWaveFileModel::getData(int fromchannel, int tochannel,
197  int start, int count,
198  float **buffers) const
199 {
200  if (!m_model || m_model->getChannelCount() == 0) return 0;
201  return m_model->getData(fromchannel, tochannel, start, count, buffers);
202 }
203 
204 int
206 {
207  if (!m_model) return desired;
208  return m_model->getSummaryBlockSize(desired);
209 }
210 
211 void
212 WritableWaveFileModel::getSummaries(int channel, int start, int count,
213  RangeBlock &ranges,
214  int &blockSize) const
215 {
216  ranges.clear();
217  if (!m_model || m_model->getChannelCount() == 0) return;
218  m_model->getSummaries(channel, start, count, ranges, blockSize);
219 }
220 
221 WritableWaveFileModel::Range
222 WritableWaveFileModel::getSummary(int channel, int start, int count) const
223 {
224  if (!m_model || m_model->getChannelCount() == 0) return Range();
225  return m_model->getSummary(channel, start, count);
226 }
227 
228 void
230  QString indent,
231  QString extraAttributes) const
232 {
233  // We don't actually write the data to XML. We just write a brief
234  // description of the model. Any code that uses this class is
235  // going to need to be aware that it will have to make separate
236  // arrangements for the audio file itself.
237 
239  (out, indent,
240  QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
242  .arg(m_model->getChannelCount()).arg(extraAttributes));
243 }
244 
QString getPath() const
Definition: WavFileWriter.h:55
bool isOK() const
virtual void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const
Stream this exportable object out to XML on a text stream.
int getChannelCount() const
virtual Model * clone() const
Return a copy of this model.
Reader for audio files using libsndfile.
Definition: WavFileReader.h:36
virtual void getSummaries(int channel, int start, int count, RangeBlock &ranges, int &blockSize) const
Return ranges from the given start frame, corresponding to the given number of underlying sample fram...
bool isOK() const
Return true if the model was constructed successfully.
void modelChangedWithin(int startFrame, int endFrame)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
virtual void setCompletion(int completion)
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Stream this exportable object out to XML on a text stream.
Definition: Model.cpp:174
static QString encodeEntities(QString)
static TempDirectory * getInstance()
bool isReady(int *) const
Return true if the model has finished loading or calculating all its data, for a model that is capabl...
virtual int getData(int channel, int start, int count, float *buffer) const
Get the specified set of samples from the given channel of the model in single-precision floating-poi...
void setStartFrame(int startFrame)
WritableWaveFileModel(int sampleRate, int channels, QString path="")
void modelChanged()
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
Model is the base class for all data models that represent any sort of data on a time scale based on ...
Definition: Model.h:35
virtual void getSummaries(int channel, int start, int count, RangeBlock &ranges, int &blockSize) const
Return ranges from the given start frame, corresponding to the given number of underlying sample fram...
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
Definition: FileSource.h:59
virtual Range getSummary(int channel, int start, int count) const
Return the range from the given start frame, corresponding to the given number of underlying sample f...
virtual int getSummaryBlockSize(int desired) const
virtual QString getError() const
#define SVDEBUG
Definition: Debug.h:42
int getChannelCount() const
Return the number of distinct channels for this model.
void updateFrameCount()
virtual Range getSummary(int channel, int start, int count) const
Return the range from the given start frame, corresponding to the given number of underlying sample f...
bool writeSamples(float **samples, int count)
virtual QString getError() const
Definition: WavFileReader.h:43
void setStartFrame(int startFrame)
Definition: WaveFileModel.h:63
virtual int getData(int channel, int start, int count, float *buffer) const
Get the specified set of samples from the given channel of the model in single-precision floating-poi...
bool isOK() const
Return true if the model was constructed successfully.
virtual bool addSamples(float **samples, int count)
Call addSamples to append a block of samples to the end of the file.
virtual int getSummaryBlockSize(int desired) const