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