lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7 This file copyright 2006 QMUL.
|
lbajardsilogic@0
|
8
|
lbajardsilogic@0
|
9 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
10 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
11 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
12 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
13 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
14 */
|
lbajardsilogic@0
|
15
|
lbajardsilogic@0
|
16 #include "WritableWaveFileModel.h"
|
lbajardsilogic@0
|
17
|
lbajardsilogic@0
|
18 #include "base/TempDirectory.h"
|
lbajardsilogic@0
|
19 #include "base/Exceptions.h"
|
lbajardsilogic@0
|
20
|
lbajardsilogic@0
|
21 #include "fileio/WavFileWriter.h"
|
lbajardsilogic@0
|
22 #include "fileio/WavFileReader.h"
|
lbajardsilogic@0
|
23
|
lbajardsilogic@0
|
24 #include <QDir>
|
lbajardsilogic@0
|
25
|
lbajardsilogic@0
|
26 #include <cassert>
|
lbajardsilogic@0
|
27 #include <iostream>
|
lbajardsilogic@0
|
28
|
lbajardsilogic@0
|
29 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
|
lbajardsilogic@0
|
30
|
lbajardsilogic@0
|
31 WritableWaveFileModel::WritableWaveFileModel(size_t sampleRate,
|
lbajardsilogic@0
|
32 size_t channels,
|
lbajardsilogic@0
|
33 QString path) :
|
lbajardsilogic@0
|
34 m_model(0),
|
lbajardsilogic@0
|
35 m_writer(0),
|
lbajardsilogic@0
|
36 m_reader(0),
|
lbajardsilogic@0
|
37 m_sampleRate(sampleRate),
|
lbajardsilogic@0
|
38 m_channels(channels),
|
lbajardsilogic@0
|
39 m_frameCount(0),
|
lbajardsilogic@0
|
40 m_completion(0)
|
lbajardsilogic@0
|
41 {
|
lbajardsilogic@0
|
42 if (path.isEmpty()) {
|
lbajardsilogic@0
|
43 try {
|
lbajardsilogic@0
|
44 QDir dir(TempDirectory::getInstance()->getPath());
|
lbajardsilogic@0
|
45 path = dir.filePath(QString("written_%1.wav")
|
lbajardsilogic@0
|
46 .arg((intptr_t)this));
|
lbajardsilogic@0
|
47 } catch (DirectoryCreationFailed f) {
|
lbajardsilogic@0
|
48 std::cerr << "WritableWaveFileModel: Failed to create temporary directory" << std::endl;
|
lbajardsilogic@0
|
49 return;
|
lbajardsilogic@0
|
50 }
|
lbajardsilogic@0
|
51 }
|
lbajardsilogic@0
|
52
|
lbajardsilogic@0
|
53 m_writer = new WavFileWriter(path, sampleRate, channels);
|
lbajardsilogic@0
|
54 if (!m_writer->isOK()) {
|
lbajardsilogic@0
|
55 std::cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError().toStdString() << std::endl;
|
lbajardsilogic@0
|
56 delete m_writer;
|
lbajardsilogic@0
|
57 m_writer = 0;
|
lbajardsilogic@0
|
58 return;
|
lbajardsilogic@0
|
59 }
|
lbajardsilogic@0
|
60
|
lbajardsilogic@0
|
61 m_reader = new WavFileReader(m_writer->getPath(), true);
|
lbajardsilogic@0
|
62 if (!m_reader->getError().isEmpty()) {
|
lbajardsilogic@0
|
63 std::cerr << "WritableWaveFileModel: Error in creating wave file reader" << std::endl;
|
lbajardsilogic@0
|
64 delete m_reader;
|
lbajardsilogic@0
|
65 m_reader = 0;
|
lbajardsilogic@0
|
66 return;
|
lbajardsilogic@0
|
67 }
|
lbajardsilogic@0
|
68
|
lbajardsilogic@0
|
69 m_model = new WaveFileModel(m_writer->getPath(), m_reader);
|
lbajardsilogic@0
|
70 if (!m_model->isOK()) {
|
lbajardsilogic@0
|
71 std::cerr << "WritableWaveFileModel: Error in creating wave file model" << std::endl;
|
lbajardsilogic@0
|
72 delete m_model;
|
lbajardsilogic@0
|
73 m_model = 0;
|
lbajardsilogic@0
|
74 delete m_reader;
|
lbajardsilogic@0
|
75 m_reader = 0;
|
lbajardsilogic@0
|
76 return;
|
lbajardsilogic@0
|
77 }
|
lbajardsilogic@0
|
78
|
lbajardsilogic@0
|
79 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
|
lbajardsilogic@0
|
80 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
|
lbajardsilogic@0
|
81 this, SIGNAL(modelChanged(size_t, size_t)));
|
lbajardsilogic@0
|
82 }
|
lbajardsilogic@0
|
83
|
lbajardsilogic@0
|
84 WritableWaveFileModel::~WritableWaveFileModel()
|
lbajardsilogic@0
|
85 {
|
lbajardsilogic@0
|
86 delete m_model;
|
lbajardsilogic@0
|
87 delete m_writer;
|
lbajardsilogic@0
|
88 delete m_reader;
|
lbajardsilogic@0
|
89 }
|
lbajardsilogic@0
|
90
|
lbajardsilogic@0
|
91 bool
|
lbajardsilogic@0
|
92 WritableWaveFileModel::addSamples(float **samples, size_t count)
|
lbajardsilogic@0
|
93 {
|
lbajardsilogic@0
|
94 if (!m_writer) return false;
|
lbajardsilogic@0
|
95
|
lbajardsilogic@0
|
96 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
|
lbajardsilogic@0
|
97 // std::cerr << "WritableWaveFileModel::addSamples(" << count << ")" << std::endl;
|
lbajardsilogic@0
|
98 #endif
|
lbajardsilogic@0
|
99
|
lbajardsilogic@0
|
100 if (!m_writer->writeSamples(samples, count)) {
|
lbajardsilogic@0
|
101 std::cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError().toStdString() << std::endl;
|
lbajardsilogic@0
|
102 return false;
|
lbajardsilogic@0
|
103 }
|
lbajardsilogic@0
|
104
|
lbajardsilogic@0
|
105 m_frameCount += count;
|
lbajardsilogic@0
|
106
|
lbajardsilogic@0
|
107 static int updateCounter = 0;
|
lbajardsilogic@0
|
108
|
lbajardsilogic@0
|
109 if (m_reader && m_reader->getChannelCount() == 0) {
|
lbajardsilogic@0
|
110 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
|
lbajardsilogic@0
|
111 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << std::endl;
|
lbajardsilogic@0
|
112 #endif
|
lbajardsilogic@0
|
113 m_reader->updateFrameCount();
|
lbajardsilogic@0
|
114 } else if (++updateCounter == 100) {
|
lbajardsilogic@0
|
115 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
|
lbajardsilogic@0
|
116 std::cerr << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << std::endl;
|
lbajardsilogic@0
|
117 #endif
|
lbajardsilogic@0
|
118 if (m_reader) m_reader->updateFrameCount();
|
lbajardsilogic@0
|
119 updateCounter = 0;
|
lbajardsilogic@0
|
120 }
|
lbajardsilogic@0
|
121
|
lbajardsilogic@0
|
122 return true;
|
lbajardsilogic@0
|
123 }
|
lbajardsilogic@0
|
124
|
lbajardsilogic@0
|
125 bool
|
lbajardsilogic@0
|
126 WritableWaveFileModel::isOK() const
|
lbajardsilogic@0
|
127 {
|
lbajardsilogic@0
|
128 bool ok = (m_writer && m_writer->isOK());
|
lbajardsilogic@0
|
129 // std::cerr << "WritableWaveFileModel::isOK(): ok = " << ok << std::endl;
|
lbajardsilogic@0
|
130 return ok;
|
lbajardsilogic@0
|
131 }
|
lbajardsilogic@0
|
132
|
lbajardsilogic@0
|
133 bool
|
lbajardsilogic@0
|
134 WritableWaveFileModel::isReady(int *completion) const
|
lbajardsilogic@0
|
135 {
|
lbajardsilogic@0
|
136 if (completion) *completion = m_completion;
|
lbajardsilogic@0
|
137 return (m_completion == 100);
|
lbajardsilogic@0
|
138 }
|
lbajardsilogic@0
|
139
|
lbajardsilogic@0
|
140 void
|
lbajardsilogic@0
|
141 WritableWaveFileModel::setCompletion(int completion)
|
lbajardsilogic@0
|
142 {
|
lbajardsilogic@0
|
143 m_completion = completion;
|
lbajardsilogic@0
|
144 if (completion == 100) {
|
lbajardsilogic@0
|
145 if (m_reader) m_reader->updateDone();
|
lbajardsilogic@0
|
146 }
|
lbajardsilogic@0
|
147 }
|
lbajardsilogic@0
|
148
|
lbajardsilogic@0
|
149 size_t
|
lbajardsilogic@0
|
150 WritableWaveFileModel::getFrameCount() const
|
lbajardsilogic@0
|
151 {
|
lbajardsilogic@0
|
152 // std::cerr << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << std::endl;
|
lbajardsilogic@0
|
153 return m_frameCount;
|
lbajardsilogic@0
|
154 }
|
lbajardsilogic@0
|
155
|
lbajardsilogic@0
|
156 Model *
|
lbajardsilogic@0
|
157 WritableWaveFileModel::clone() const
|
lbajardsilogic@0
|
158 {
|
lbajardsilogic@0
|
159 assert(0); //!!!
|
lbajardsilogic@0
|
160 return 0;
|
lbajardsilogic@0
|
161 }
|
lbajardsilogic@0
|
162
|
lbajardsilogic@0
|
163 size_t
|
lbajardsilogic@0
|
164 WritableWaveFileModel::getValues(int channel, size_t start, size_t end,
|
lbajardsilogic@0
|
165 float *buffer) const
|
lbajardsilogic@0
|
166 {
|
lbajardsilogic@0
|
167 if (!m_model || m_model->getChannelCount() == 0) return 0;
|
lbajardsilogic@0
|
168 return m_model->getValues(channel, start, end, buffer);
|
lbajardsilogic@0
|
169 }
|
lbajardsilogic@0
|
170
|
lbajardsilogic@0
|
171 size_t
|
lbajardsilogic@0
|
172 WritableWaveFileModel::getValues(int channel, size_t start, size_t end,
|
lbajardsilogic@0
|
173 double *buffer) const
|
lbajardsilogic@0
|
174 {
|
lbajardsilogic@0
|
175 if (!m_model || m_model->getChannelCount() == 0) return 0;
|
lbajardsilogic@0
|
176 // std::cerr << "WritableWaveFileModel::getValues(" << channel << ", "
|
lbajardsilogic@0
|
177 // << start << ", " << end << "): calling model" << std::endl;
|
lbajardsilogic@0
|
178 return m_model->getValues(channel, start, end, buffer);
|
lbajardsilogic@0
|
179 }
|
lbajardsilogic@0
|
180
|
lbajardsilogic@0
|
181 void
|
lbajardsilogic@0
|
182 WritableWaveFileModel::getRanges(size_t channel, size_t start, size_t end,
|
lbajardsilogic@0
|
183 RangeBlock &ranges,
|
lbajardsilogic@0
|
184 size_t &blockSize) const
|
lbajardsilogic@0
|
185 {
|
lbajardsilogic@0
|
186 ranges.clear();
|
lbajardsilogic@0
|
187 if (!m_model || m_model->getChannelCount() == 0) return;
|
lbajardsilogic@0
|
188 m_model->getRanges(channel, start, end, ranges, blockSize);
|
lbajardsilogic@0
|
189 }
|
lbajardsilogic@0
|
190
|
lbajardsilogic@0
|
191 WritableWaveFileModel::Range
|
lbajardsilogic@0
|
192 WritableWaveFileModel::getRange(size_t channel, size_t start, size_t end) const
|
lbajardsilogic@0
|
193 {
|
lbajardsilogic@0
|
194 if (!m_model || m_model->getChannelCount() == 0) return Range();
|
lbajardsilogic@0
|
195 return m_model->getRange(channel, start, end);
|
lbajardsilogic@0
|
196 }
|
lbajardsilogic@0
|
197
|
lbajardsilogic@0
|
198 void
|
lbajardsilogic@0
|
199 WritableWaveFileModel::toXml(QTextStream &out,
|
lbajardsilogic@0
|
200 QString indent,
|
lbajardsilogic@0
|
201 QString extraAttributes) const
|
lbajardsilogic@0
|
202 {
|
lbajardsilogic@0
|
203 // We don't actually write the data to XML. We just write a brief
|
lbajardsilogic@0
|
204 // description of the model. Any code that uses this class is
|
lbajardsilogic@0
|
205 // going to need to be aware that it will have to make separate
|
lbajardsilogic@0
|
206 // arrangements for the audio file itself.
|
lbajardsilogic@0
|
207
|
lbajardsilogic@0
|
208 Model::toXml
|
lbajardsilogic@0
|
209 (out, indent,
|
lbajardsilogic@0
|
210 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
|
lbajardsilogic@0
|
211 .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes));
|
lbajardsilogic@0
|
212 }
|
lbajardsilogic@0
|
213
|
lbajardsilogic@0
|
214 QString
|
lbajardsilogic@0
|
215 WritableWaveFileModel::toXmlString(QString indent,
|
lbajardsilogic@0
|
216 QString extraAttributes) const
|
lbajardsilogic@0
|
217 {
|
lbajardsilogic@0
|
218 // As above.
|
lbajardsilogic@0
|
219
|
lbajardsilogic@0
|
220 return Model::toXmlString
|
lbajardsilogic@0
|
221 (indent,
|
lbajardsilogic@0
|
222 QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3")
|
lbajardsilogic@0
|
223 .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes));
|
lbajardsilogic@0
|
224 }
|
lbajardsilogic@0
|
225
|