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