Mercurial > hg > svcore
comparison data/fileio/CodedAudioFileReader.cpp @ 1069:32ab6c48efaa
Merge from branch tonioni
author | Chris Cannam |
---|---|
date | Mon, 20 Apr 2015 09:11:34 +0100 |
parents | e603b44510c3 |
children | 4d9816ba0ebe 1517d4c60e88 |
comparison
equal
deleted
inserted
replaced
1036:682d64f05e72 | 1069:32ab6c48efaa |
---|---|
26 #include <iostream> | 26 #include <iostream> |
27 #include <QDir> | 27 #include <QDir> |
28 #include <QMutexLocker> | 28 #include <QMutexLocker> |
29 | 29 |
30 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode, | 30 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode, |
31 int targetRate, | 31 sv_samplerate_t targetRate, |
32 bool normalised) : | 32 bool normalised) : |
33 m_cacheMode(cacheMode), | 33 m_cacheMode(cacheMode), |
34 m_initialised(false), | 34 m_initialised(false), |
35 m_serialiser(0), | 35 m_serialiser(0), |
36 m_fileRate(0), | 36 m_fileRate(0), |
111 if (m_fileRate != m_sampleRate) { | 111 if (m_fileRate != m_sampleRate) { |
112 SVDEBUG << "CodedAudioFileReader: resampling " << m_fileRate << " -> " << m_sampleRate << endl; | 112 SVDEBUG << "CodedAudioFileReader: resampling " << m_fileRate << " -> " << m_sampleRate << endl; |
113 m_resampler = new Resampler(Resampler::FastestTolerable, | 113 m_resampler = new Resampler(Resampler::FastestTolerable, |
114 m_channelCount, | 114 m_channelCount, |
115 m_cacheWriteBufferSize); | 115 m_cacheWriteBufferSize); |
116 float ratio = float(m_sampleRate) / float(m_fileRate); | 116 double ratio = m_sampleRate / m_fileRate; |
117 m_resampleBuffer = new float | 117 m_resampleBuffer = new float |
118 [lrintf(ceilf(m_cacheWriteBufferSize * m_channelCount * ratio + 1))]; | 118 [lrint(ceil(double(m_cacheWriteBufferSize) * m_channelCount * ratio + 1))]; |
119 } | 119 } |
120 | 120 |
121 m_cacheWriteBuffer = new float[m_cacheWriteBufferSize * m_channelCount]; | 121 m_cacheWriteBuffer = new float[m_cacheWriteBufferSize * m_channelCount]; |
122 m_cacheWriteBufferIndex = 0; | 122 m_cacheWriteBufferIndex = 0; |
123 | 123 |
127 QDir dir(TempDirectory::getInstance()->getPath()); | 127 QDir dir(TempDirectory::getInstance()->getPath()); |
128 m_cacheFileName = dir.filePath(QString("decoded_%1.wav") | 128 m_cacheFileName = dir.filePath(QString("decoded_%1.wav") |
129 .arg((intptr_t)this)); | 129 .arg((intptr_t)this)); |
130 | 130 |
131 SF_INFO fileInfo; | 131 SF_INFO fileInfo; |
132 fileInfo.samplerate = m_sampleRate; | 132 int fileRate = int(round(m_sampleRate)); |
133 if (m_sampleRate != sv_samplerate_t(fileRate)) { | |
134 cerr << "CodedAudioFileReader: WARNING: Non-integer sample rate " | |
135 << m_sampleRate << " presented for writing, rounding to " << fileRate | |
136 << endl; | |
137 } | |
138 fileInfo.samplerate = fileRate; | |
133 fileInfo.channels = m_channelCount; | 139 fileInfo.channels = m_channelCount; |
134 | 140 |
135 // No point in writing 24-bit or float; generally this | 141 // No point in writing 24-bit or float; generally this |
136 // class is used for decoding files that have come from a | 142 // class is used for decoding files that have come from a |
137 // 16 bit source or that decode to only 16 bits anyway. | 143 // 16 bit source or that decode to only 16 bits anyway. |
138 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; | 144 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; |
139 | 145 |
174 | 180 |
175 m_initialised = true; | 181 m_initialised = true; |
176 } | 182 } |
177 | 183 |
178 void | 184 void |
179 CodedAudioFileReader::addSamplesToDecodeCache(float **samples, int nframes) | 185 CodedAudioFileReader::addSamplesToDecodeCache(float **samples, sv_frame_t nframes) |
180 { | 186 { |
181 QMutexLocker locker(&m_cacheMutex); | 187 QMutexLocker locker(&m_cacheMutex); |
182 | 188 |
183 if (!m_initialised) return; | 189 if (!m_initialised) return; |
184 | 190 |
185 for (int i = 0; i < nframes; ++i) { | 191 for (sv_frame_t i = 0; i < nframes; ++i) { |
186 | 192 |
187 for (int c = 0; c < m_channelCount; ++c) { | 193 for (int c = 0; c < m_channelCount; ++c) { |
188 | 194 |
189 float sample = samples[c][i]; | 195 float sample = samples[c][i]; |
190 | 196 |
204 } | 210 } |
205 } | 211 } |
206 } | 212 } |
207 | 213 |
208 void | 214 void |
209 CodedAudioFileReader::addSamplesToDecodeCache(float *samples, int nframes) | 215 CodedAudioFileReader::addSamplesToDecodeCache(float *samples, sv_frame_t nframes) |
210 { | 216 { |
211 QMutexLocker locker(&m_cacheMutex); | 217 QMutexLocker locker(&m_cacheMutex); |
212 | 218 |
213 if (!m_initialised) return; | 219 if (!m_initialised) return; |
214 | 220 |
215 for (int i = 0; i < nframes; ++i) { | 221 for (sv_frame_t i = 0; i < nframes; ++i) { |
216 | 222 |
217 for (int c = 0; c < m_channelCount; ++c) { | 223 for (int c = 0; c < m_channelCount; ++c) { |
218 | 224 |
219 float sample = samples[i * m_channelCount + c]; | 225 float sample = samples[i * m_channelCount + c]; |
220 | 226 |
240 { | 246 { |
241 QMutexLocker locker(&m_cacheMutex); | 247 QMutexLocker locker(&m_cacheMutex); |
242 | 248 |
243 if (!m_initialised) return; | 249 if (!m_initialised) return; |
244 | 250 |
245 for (int i = 0; i < (int)samples.size(); ++i) { | 251 for (float sample: samples) { |
246 | |
247 float sample = samples[i]; | |
248 | 252 |
249 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample; | 253 m_cacheWriteBuffer[m_cacheWriteBufferIndex++] = sample; |
250 | 254 |
251 if (m_cacheWriteBufferIndex == | 255 if (m_cacheWriteBufferIndex == |
252 m_cacheWriteBufferSize * m_channelCount) { | 256 m_cacheWriteBufferSize * m_channelCount) { |
293 if (m_cacheFileReader) m_cacheFileReader->updateFrameCount(); | 297 if (m_cacheFileReader) m_cacheFileReader->updateFrameCount(); |
294 } | 298 } |
295 } | 299 } |
296 | 300 |
297 void | 301 void |
298 CodedAudioFileReader::pushBuffer(float *buffer, int sz, bool final) | 302 CodedAudioFileReader::pushBuffer(float *buffer, sv_frame_t sz, bool final) |
299 { | 303 { |
300 m_fileFrameCount += sz; | 304 m_fileFrameCount += sz; |
301 | 305 |
302 float ratio = 1.f; | 306 double ratio = 1.0; |
303 if (m_resampler && m_fileRate != 0) { | 307 if (m_resampler && m_fileRate != 0) { |
304 ratio = float(m_sampleRate) / float(m_fileRate); | 308 ratio = m_sampleRate / m_fileRate; |
305 } | 309 } |
306 | 310 |
307 if (ratio != 1.f) { | 311 if (ratio != 1.0) { |
308 pushBufferResampling(buffer, sz, ratio, final); | 312 pushBufferResampling(buffer, sz, ratio, final); |
309 } else { | 313 } else { |
310 pushBufferNonResampling(buffer, sz); | 314 pushBufferNonResampling(buffer, sz); |
311 } | 315 } |
312 } | 316 } |
313 | 317 |
314 void | 318 void |
315 CodedAudioFileReader::pushBufferNonResampling(float *buffer, int sz) | 319 CodedAudioFileReader::pushBufferNonResampling(float *buffer, sv_frame_t sz) |
316 { | 320 { |
317 float clip = 1.0; | 321 float clip = 1.0; |
318 int count = sz * m_channelCount; | 322 sv_frame_t count = sz * m_channelCount; |
319 | 323 |
320 if (m_normalised) { | 324 if (m_normalised) { |
321 for (int i = 0; i < count; ++i) { | 325 for (sv_frame_t i = 0; i < count; ++i) { |
322 float v = fabsf(buffer[i]); | 326 float v = fabsf(buffer[i]); |
323 if (v > m_max) { | 327 if (v > m_max) { |
324 m_max = v; | 328 m_max = v; |
325 m_gain = 1.f / m_max; | 329 m_gain = 1.f / m_max; |
326 } | 330 } |
327 } | 331 } |
328 } else { | 332 } else { |
329 for (int i = 0; i < count; ++i) { | 333 for (sv_frame_t i = 0; i < count; ++i) { |
330 if (buffer[i] > clip) buffer[i] = clip; | 334 if (buffer[i] > clip) buffer[i] = clip; |
331 } | 335 } |
332 for (int i = 0; i < count; ++i) { | 336 for (sv_frame_t i = 0; i < count; ++i) { |
333 if (buffer[i] < -clip) buffer[i] = -clip; | 337 if (buffer[i] < -clip) buffer[i] = -clip; |
334 } | 338 } |
335 } | 339 } |
336 | 340 |
337 m_frameCount += sz; | 341 m_frameCount += sz; |
338 | 342 |
339 switch (m_cacheMode) { | 343 switch (m_cacheMode) { |
340 | 344 |
341 case CacheInTemporaryFile: | 345 case CacheInTemporaryFile: |
342 if (sf_writef_float(m_cacheFileWritePtr, buffer, sz) < (int)sz) { | 346 if (sf_writef_float(m_cacheFileWritePtr, buffer, sz) < sz) { |
343 sf_close(m_cacheFileWritePtr); | 347 sf_close(m_cacheFileWritePtr); |
344 m_cacheFileWritePtr = 0; | 348 m_cacheFileWritePtr = 0; |
345 throw InsufficientDiscSpace(TempDirectory::getInstance()->getPath()); | 349 throw InsufficientDiscSpace(TempDirectory::getInstance()->getPath()); |
346 } | 350 } |
347 break; | 351 break; |
348 | 352 |
349 case CacheInMemory: | 353 case CacheInMemory: |
350 m_dataLock.lockForWrite(); | 354 m_dataLock.lockForWrite(); |
351 for (int s = 0; s < count; ++s) { | 355 for (sv_frame_t s = 0; s < count; ++s) { |
352 m_data.push_back(buffer[s]); | 356 m_data.push_back(buffer[s]); |
353 } | 357 } |
354 MUNLOCK_SAMPLEBLOCK(m_data); | |
355 m_dataLock.unlock(); | 358 m_dataLock.unlock(); |
356 break; | 359 break; |
357 } | 360 } |
358 } | 361 } |
359 | 362 |
360 void | 363 void |
361 CodedAudioFileReader::pushBufferResampling(float *buffer, int sz, | 364 CodedAudioFileReader::pushBufferResampling(float *buffer, sv_frame_t sz, |
362 float ratio, bool final) | 365 double ratio, bool final) |
363 { | 366 { |
364 SVDEBUG << "pushBufferResampling: ratio = " << ratio << ", sz = " << sz << ", final = " << final << endl; | 367 SVDEBUG << "pushBufferResampling: ratio = " << ratio << ", sz = " << sz << ", final = " << final << endl; |
365 | 368 |
366 if (sz > 0) { | 369 if (sz > 0) { |
367 | 370 |
368 int out = m_resampler->resampleInterleaved | 371 sv_frame_t out = m_resampler->resampleInterleaved |
369 (buffer, | 372 (buffer, |
370 m_resampleBuffer, | 373 m_resampleBuffer, |
371 sz, | 374 sz, |
372 ratio, | 375 ratio, |
373 false); | 376 false); |
375 pushBufferNonResampling(m_resampleBuffer, out); | 378 pushBufferNonResampling(m_resampleBuffer, out); |
376 } | 379 } |
377 | 380 |
378 if (final) { | 381 if (final) { |
379 | 382 |
380 int padFrames = 1; | 383 sv_frame_t padFrames = 1; |
381 if (m_frameCount / ratio < m_fileFrameCount) { | 384 if (double(m_frameCount) / ratio < double(m_fileFrameCount)) { |
382 padFrames = m_fileFrameCount - (m_frameCount / ratio) + 1; | 385 padFrames = m_fileFrameCount - sv_frame_t(double(m_frameCount) / ratio) + 1; |
383 } | 386 } |
384 | 387 |
385 int padSamples = padFrames * m_channelCount; | 388 sv_frame_t padSamples = padFrames * m_channelCount; |
386 | 389 |
387 SVDEBUG << "frameCount = " << m_frameCount << ", equivFileFrames = " << m_frameCount / ratio << ", m_fileFrameCount = " << m_fileFrameCount << ", padFrames= " << padFrames << ", padSamples = " << padSamples << endl; | 390 SVDEBUG << "frameCount = " << m_frameCount << ", equivFileFrames = " << double(m_frameCount) / ratio << ", m_fileFrameCount = " << m_fileFrameCount << ", padFrames= " << padFrames << ", padSamples = " << padSamples << endl; |
388 | 391 |
389 float *padding = new float[padSamples]; | 392 float *padding = new float[padSamples]; |
390 for (int i = 0; i < padSamples; ++i) padding[i] = 0.f; | 393 for (sv_frame_t i = 0; i < padSamples; ++i) padding[i] = 0.f; |
391 | 394 |
392 int out = m_resampler->resampleInterleaved | 395 sv_frame_t out = m_resampler->resampleInterleaved |
393 (padding, | 396 (padding, |
394 m_resampleBuffer, | 397 m_resampleBuffer, |
395 padFrames, | 398 padFrames, |
396 ratio, | 399 ratio, |
397 true); | 400 true); |
398 | 401 |
399 if (int(m_frameCount + out) > int(m_fileFrameCount * ratio)) { | 402 if (m_frameCount + out > sv_frame_t(double(m_fileFrameCount) * ratio)) { |
400 out = int(m_fileFrameCount * ratio) - int(m_frameCount); | 403 out = sv_frame_t(double(m_fileFrameCount) * ratio) - m_frameCount; |
401 } | 404 } |
402 | 405 |
403 pushBufferNonResampling(m_resampleBuffer, out); | 406 pushBufferNonResampling(m_resampleBuffer, out); |
404 delete[] padding; | 407 delete[] padding; |
405 } | 408 } |
406 } | 409 } |
407 | 410 |
408 void | 411 SampleBlock |
409 CodedAudioFileReader::getInterleavedFrames(int start, int count, | 412 CodedAudioFileReader::getInterleavedFrames(sv_frame_t start, sv_frame_t count) const |
410 SampleBlock &frames) const | |
411 { | 413 { |
412 // Lock is only required in CacheInMemory mode (the cache file | 414 // Lock is only required in CacheInMemory mode (the cache file |
413 // reader is expected to be thread safe and manage its own | 415 // reader is expected to be thread safe and manage its own |
414 // locking) | 416 // locking) |
415 | 417 |
416 if (!m_initialised) { | 418 if (!m_initialised) { |
417 SVDEBUG << "CodedAudioFileReader::getInterleavedFrames: not initialised" << endl; | 419 SVDEBUG << "CodedAudioFileReader::getInterleavedFrames: not initialised" << endl; |
418 return; | 420 return SampleBlock(); |
419 } | 421 } |
420 | 422 |
423 SampleBlock frames; | |
424 | |
421 switch (m_cacheMode) { | 425 switch (m_cacheMode) { |
422 | 426 |
423 case CacheInTemporaryFile: | 427 case CacheInTemporaryFile: |
424 if (m_cacheFileReader) { | 428 if (m_cacheFileReader) { |
425 m_cacheFileReader->getInterleavedFrames(start, count, frames); | 429 frames = m_cacheFileReader->getInterleavedFrames(start, count); |
426 } | 430 } |
427 break; | 431 break; |
428 | 432 |
429 case CacheInMemory: | 433 case CacheInMemory: |
430 { | 434 { |
431 frames.clear(); | 435 if (!isOK()) return SampleBlock(); |
432 if (!isOK()) return; | 436 if (count == 0) return SampleBlock(); |
433 if (count == 0) return; | 437 |
434 frames.reserve(count * m_channelCount); | 438 sv_frame_t idx = start * m_channelCount; |
435 | 439 sv_frame_t i = 0; |
436 int idx = start * m_channelCount; | 440 sv_frame_t n = count * m_channelCount; |
437 int i = 0; | 441 |
442 frames.resize(n); | |
438 | 443 |
439 m_dataLock.lockForRead(); | 444 m_dataLock.lockForRead(); |
440 while (i < count * m_channelCount && idx < (int)m_data.size()) { | 445 while (i < n && in_range_for(m_data, idx)) { |
441 frames.push_back(m_data[idx]); | 446 frames[i++] = m_data[idx++]; |
442 ++idx; | |
443 } | 447 } |
444 m_dataLock.unlock(); | 448 m_dataLock.unlock(); |
449 | |
450 frames.resize(i); | |
445 } | 451 } |
446 } | 452 } |
447 | 453 |
448 if (m_normalised) { | 454 if (m_normalised) { |
449 for (int i = 0; i < (int)(count * m_channelCount); ++i) { | 455 for (auto &f: frames) f *= m_gain; |
450 frames[i] *= m_gain; | 456 } |
451 } | 457 |
452 } | 458 return frames; |
453 } | 459 } |
454 | 460 |