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