comparison data/model/WritableWaveFileModel.cpp @ 1527:710e6250a401 zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:14 +0100
parents 954d0cf29ca7
children 70e172e6cc59
comparison
equal deleted inserted replaced
1324:d4a28d1479a8 1527:710e6250a401
34 34
35 const int WritableWaveFileModel::PROPORTION_UNKNOWN = -1; 35 const int WritableWaveFileModel::PROPORTION_UNKNOWN = -1;
36 36
37 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1 37 //#define DEBUG_WRITABLE_WAVE_FILE_MODEL 1
38 38
39 WritableWaveFileModel::WritableWaveFileModel(sv_samplerate_t sampleRate, 39 WritableWaveFileModel::WritableWaveFileModel(QString path,
40 int channels, 40 sv_samplerate_t sampleRate,
41 QString path) : 41 int channels,
42 Normalisation norm) :
42 m_model(0), 43 m_model(0),
43 m_writer(0), 44 m_temporaryWriter(0),
45 m_targetWriter(0),
44 m_reader(0), 46 m_reader(0),
47 m_normalisation(norm),
45 m_sampleRate(sampleRate), 48 m_sampleRate(sampleRate),
46 m_channels(channels), 49 m_channels(channels),
47 m_frameCount(0), 50 m_frameCount(0),
48 m_startFrame(0), 51 m_startFrame(0),
49 m_proportion(PROPORTION_UNKNOWN) 52 m_proportion(PROPORTION_UNKNOWN)
50 { 53 {
54 init(path);
55 }
56
57 WritableWaveFileModel::WritableWaveFileModel(sv_samplerate_t sampleRate,
58 int channels,
59 Normalisation norm) :
60 m_model(0),
61 m_temporaryWriter(0),
62 m_targetWriter(0),
63 m_reader(0),
64 m_normalisation(norm),
65 m_sampleRate(sampleRate),
66 m_channels(channels),
67 m_frameCount(0),
68 m_startFrame(0),
69 m_proportion(PROPORTION_UNKNOWN)
70 {
71 init();
72 }
73
74 WritableWaveFileModel::WritableWaveFileModel(sv_samplerate_t sampleRate,
75 int channels) :
76 m_model(0),
77 m_temporaryWriter(0),
78 m_targetWriter(0),
79 m_reader(0),
80 m_normalisation(Normalisation::None),
81 m_sampleRate(sampleRate),
82 m_channels(channels),
83 m_frameCount(0),
84 m_startFrame(0),
85 m_proportion(PROPORTION_UNKNOWN)
86 {
87 init();
88 }
89
90 void
91 WritableWaveFileModel::init(QString path)
92 {
51 if (path.isEmpty()) { 93 if (path.isEmpty()) {
52 try { 94 try {
95 // Temp dir is exclusive to this run of the application,
96 // so the filename only needs to be unique within that -
97 // model ID should be ok
53 QDir dir(TempDirectory::getInstance()->getPath()); 98 QDir dir(TempDirectory::getInstance()->getPath());
54 path = dir.filePath(QString("written_%1.wav") 99 path = dir.filePath(QString("written_%1.wav").arg(getId()));
55 .arg((intptr_t)this)); 100 } catch (const DirectoryCreationFailed &f) {
56 } catch (DirectoryCreationFailed f) { 101 SVCERR << "WritableWaveFileModel: Failed to create temporary directory" << endl;
57 cerr << "WritableWaveFileModel: Failed to create temporary directory" << endl;
58 return; 102 return;
59 } 103 }
60 } 104 }
61 105
62 // Write directly to the target file, so that we can do 106 m_targetPath = path;
63 // incremental writes and concurrent reads 107 m_temporaryPath = "";
64 m_writer = new WavFileWriter(path, sampleRate, channels, 108
65 WavFileWriter::WriteToTarget); 109 // We don't delete or null-out writer/reader members after
66 if (!m_writer->isOK()) { 110 // failures here - they are all deleted in the dtor, and the
67 cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError() << endl; 111 // presence/existence of the model is what's used to determine
68 delete m_writer; 112 // whether to go ahead, not the writer/readers. If the model is
69 m_writer = 0; 113 // non-null, then the necessary writer/readers must be OK, as the
70 return; 114 // model is the last thing initialised
71 } 115
72 116 m_targetWriter = new WavFileWriter(m_targetPath, m_sampleRate, m_channels,
73 FileSource source(m_writer->getPath()); 117 WavFileWriter::WriteToTarget);
118
119 if (!m_targetWriter->isOK()) {
120 SVCERR << "WritableWaveFileModel: Error in creating WAV file writer: " << m_targetWriter->getError() << endl;
121 return;
122 }
123
124 if (m_normalisation != Normalisation::None) {
125
126 // Temp dir is exclusive to this run of the application, so
127 // the filename only needs to be unique within that
128 QDir dir(TempDirectory::getInstance()->getPath());
129 m_temporaryPath = dir.filePath(QString("prenorm_%1.wav").arg(getId()));
130
131 m_temporaryWriter = new WavFileWriter
132 (m_temporaryPath, m_sampleRate, m_channels,
133 WavFileWriter::WriteToTarget);
134
135 if (!m_temporaryWriter->isOK()) {
136 SVCERR << "WritableWaveFileModel: Error in creating temporary WAV file writer: " << m_temporaryWriter->getError() << endl;
137 return;
138 }
139 }
140
141 FileSource source(m_targetPath);
74 142
75 m_reader = new WavFileReader(source, true); 143 m_reader = new WavFileReader(source, true);
76 if (!m_reader->getError().isEmpty()) { 144 if (!m_reader->getError().isEmpty()) {
77 cerr << "WritableWaveFileModel: Error in creating wave file reader" << endl; 145 SVCERR << "WritableWaveFileModel: Error in creating wave file reader: " << m_reader->getError() << endl;
78 delete m_reader;
79 m_reader = 0;
80 return; 146 return;
81 } 147 }
82 148
83 m_model = new ReadOnlyWaveFileModel(source, m_reader); 149 m_model = new ReadOnlyWaveFileModel(source, m_reader);
84 if (!m_model->isOK()) { 150 if (!m_model->isOK()) {
85 cerr << "WritableWaveFileModel: Error in creating wave file model" << endl; 151 SVCERR << "WritableWaveFileModel: Error in creating wave file model" << endl;
86 delete m_model; 152 delete m_model;
87 m_model = 0; 153 m_model = 0;
88 delete m_reader;
89 m_reader = 0;
90 return; 154 return;
91 } 155 }
92 m_model->setStartFrame(m_startFrame); 156 m_model->setStartFrame(m_startFrame);
93 157
94 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); 158 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
97 } 161 }
98 162
99 WritableWaveFileModel::~WritableWaveFileModel() 163 WritableWaveFileModel::~WritableWaveFileModel()
100 { 164 {
101 delete m_model; 165 delete m_model;
102 delete m_writer; 166 delete m_targetWriter;
167 delete m_temporaryWriter;
103 delete m_reader; 168 delete m_reader;
104 } 169 }
105 170
106 void 171 void
107 WritableWaveFileModel::setStartFrame(sv_frame_t startFrame) 172 WritableWaveFileModel::setStartFrame(sv_frame_t startFrame)
108 { 173 {
109 m_startFrame = startFrame; 174 m_startFrame = startFrame;
110 if (m_model) m_model->setStartFrame(startFrame); 175 if (m_model) {
176 m_model->setStartFrame(startFrame);
177 }
111 } 178 }
112 179
113 bool 180 bool
114 WritableWaveFileModel::addSamples(float **samples, sv_frame_t count) 181 WritableWaveFileModel::addSamples(const float *const *samples, sv_frame_t count)
115 { 182 {
116 if (!m_writer) return false; 183 if (!m_model) return false;
117 184
118 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL 185 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
119 // SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl; 186 // SVDEBUG << "WritableWaveFileModel::addSamples(" << count << ")" << endl;
120 #endif 187 #endif
121 188
122 if (!m_writer->writeSamples(samples, count)) { 189 WavFileWriter *writer = m_targetWriter;
123 cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError() << endl; 190 if (m_normalisation != Normalisation::None) {
191 writer = m_temporaryWriter;
192 }
193
194 if (!writer->writeSamples(samples, count)) {
195 SVCERR << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << writer->getError() << endl;
124 return false; 196 return false;
125 } 197 }
126 198
127 m_frameCount += count; 199 m_frameCount += count;
128 200
129 static int updateCounter = 0; 201 if (m_normalisation == Normalisation::None) {
130 202 if (m_reader->getChannelCount() == 0) {
131 if (m_reader && m_reader->getChannelCount() == 0) { 203 m_reader->updateFrameCount();
132 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL 204 }
133 SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (initial)" << endl;
134 #endif
135 m_reader->updateFrameCount();
136 } else if (++updateCounter == 100) {
137 #ifdef DEBUG_WRITABLE_WAVE_FILE_MODEL
138 SVDEBUG << "WritableWaveFileModel::addSamples(" << count << "): calling updateFrameCount (periodic)" << endl;
139 #endif
140 if (m_reader) m_reader->updateFrameCount();
141 updateCounter = 0;
142 } 205 }
143 206
144 return true; 207 return true;
208 }
209
210 void
211 WritableWaveFileModel::updateModel()
212 {
213 if (!m_model) return;
214
215 m_reader->updateFrameCount();
145 } 216 }
146 217
147 bool 218 bool
148 WritableWaveFileModel::isOK() const 219 WritableWaveFileModel::isOK() const
149 { 220 {
150 bool ok = (m_writer && m_writer->isOK()); 221 return (m_model && m_model->isOK());
151 // SVDEBUG << "WritableWaveFileModel::isOK(): ok = " << ok << endl;
152 return ok;
153 } 222 }
154 223
155 bool 224 bool
156 WritableWaveFileModel::isReady(int *completion) const 225 WritableWaveFileModel::isReady(int *completion) const
157 { 226 {
174 } 243 }
175 244
176 void 245 void
177 WritableWaveFileModel::writeComplete() 246 WritableWaveFileModel::writeComplete()
178 { 247 {
179 if (m_reader) m_reader->updateDone(); 248 if (!m_model) return;
249
250 if (m_normalisation == Normalisation::None) {
251 m_targetWriter->close();
252 } else {
253 m_temporaryWriter->close();
254 normaliseToTarget();
255 }
256
257 m_reader->updateDone();
180 m_proportion = 100; 258 m_proportion = 100;
181 emit modelChanged(); 259 emit modelChanged();
182 } 260 }
183 261
262 void
263 WritableWaveFileModel::normaliseToTarget()
264 {
265 if (m_temporaryPath == "") {
266 SVCERR << "WritableWaveFileModel::normaliseToTarget: No temporary path available" << endl;
267 return;
268 }
269
270 WavFileReader normalisingReader(m_temporaryPath, false,
271 WavFileReader::Normalisation::Peak);
272
273 if (!normalisingReader.getError().isEmpty()) {
274 SVCERR << "WritableWaveFileModel: Error in creating normalising reader: " << normalisingReader.getError() << endl;
275 return;
276 }
277
278 sv_frame_t frame = 0;
279 sv_frame_t block = 65536;
280 sv_frame_t count = normalisingReader.getFrameCount();
281
282 while (frame < count) {
283 auto frames = normalisingReader.getInterleavedFrames(frame, block);
284 if (!m_targetWriter->putInterleavedFrames(frames)) {
285 SVCERR << "ERROR: WritableWaveFileModel::normaliseToTarget: writer failed: " << m_targetWriter->getError() << endl;
286 return;
287 }
288 frame += block;
289 }
290
291 m_targetWriter->close();
292
293 delete m_temporaryWriter;
294 m_temporaryWriter = 0;
295 QFile::remove(m_temporaryPath);
296 }
297
184 sv_frame_t 298 sv_frame_t
185 WritableWaveFileModel::getFrameCount() const 299 WritableWaveFileModel::getFrameCount() const
186 { 300 {
187 // SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl; 301 // SVDEBUG << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << endl;
188 return m_frameCount; 302 return m_frameCount;
189 } 303 }
190 304
191 vector<float> 305 floatvec_t
192 WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const 306 WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
193 { 307 {
194 if (!m_model || m_model->getChannelCount() == 0) return {}; 308 if (!m_model || m_model->getChannelCount() == 0) return {};
195 return m_model->getData(channel, start, count); 309 return m_model->getData(channel, start, count);
196 } 310 }
197 311
198 vector<vector<float>> 312 vector<floatvec_t>
199 WritableWaveFileModel::getMultiChannelData(int fromchannel, int tochannel, 313 WritableWaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
200 sv_frame_t start, sv_frame_t count) const 314 sv_frame_t start, sv_frame_t count) const
201 { 315 {
202 if (!m_model || m_model->getChannelCount() == 0) return {}; 316 if (!m_model || m_model->getChannelCount() == 0) return {};
203 return m_model->getMultiChannelData(fromchannel, tochannel, start, count); 317 return m_model->getMultiChannelData(fromchannel, tochannel, start, count);
239 // We just write this out as if it were a normal wave file. 353 // We just write this out as if it were a normal wave file.
240 354
241 Model::toXml 355 Model::toXml
242 (out, indent, 356 (out, indent,
243 QString("type=\"wavefile\" file=\"%1\" subtype=\"writable\" %2") 357 QString("type=\"wavefile\" file=\"%1\" subtype=\"writable\" %2")
244 .arg(encodeEntities(m_writer->getPath())) 358 .arg(encodeEntities(m_targetPath))
245 .arg(extraAttributes)); 359 .arg(extraAttributes));
246 } 360 }
247 361