Mercurial > hg > svcore
comparison data/fileio/CodedAudioFileReader.cpp @ 1126:39019ce29178 tony-2.0-integration
Merge through to branch for Tony 2.0
| author | Chris Cannam | 
|---|---|
| date | Thu, 20 Aug 2015 14:54:21 +0100 | 
| parents | 457a1a619c5f | 
| children | 6877f4200912 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 1119:e22bfe8ca248 | 1126:39019ce29178 | 
|---|---|
| 19 #include "base/TempDirectory.h" | 19 #include "base/TempDirectory.h" | 
| 20 #include "base/Exceptions.h" | 20 #include "base/Exceptions.h" | 
| 21 #include "base/Profiler.h" | 21 #include "base/Profiler.h" | 
| 22 #include "base/Serialiser.h" | 22 #include "base/Serialiser.h" | 
| 23 #include "base/Resampler.h" | 23 #include "base/Resampler.h" | 
| 24 #include "base/StorageAdviser.h" | |
| 24 | 25 | 
| 25 #include <stdint.h> | 26 #include <stdint.h> | 
| 26 #include <iostream> | 27 #include <iostream> | 
| 27 #include <QDir> | 28 #include <QDir> | 
| 28 #include <QMutexLocker> | 29 #include <QMutexLocker> | 
| 30 | |
| 31 using namespace std; | |
| 29 | 32 | 
| 30 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode, | 33 CodedAudioFileReader::CodedAudioFileReader(CacheMode cacheMode, | 
| 31 sv_samplerate_t targetRate, | 34 sv_samplerate_t targetRate, | 
| 32 bool normalised) : | 35 bool normalised) : | 
| 33 m_cacheMode(cacheMode), | 36 m_cacheMode(cacheMode), | 
| 55 CodedAudioFileReader::~CodedAudioFileReader() | 58 CodedAudioFileReader::~CodedAudioFileReader() | 
| 56 { | 59 { | 
| 57 QMutexLocker locker(&m_cacheMutex); | 60 QMutexLocker locker(&m_cacheMutex); | 
| 58 | 61 | 
| 59 endSerialised(); | 62 endSerialised(); | 
| 60 | 63 | 
| 61 if (m_cacheFileWritePtr) sf_close(m_cacheFileWritePtr); | 64 if (m_cacheFileWritePtr) sf_close(m_cacheFileWritePtr); | 
| 62 | 65 | 
| 63 SVDEBUG << "CodedAudioFileReader::~CodedAudioFileReader: deleting cache file reader" << endl; | 66 SVDEBUG << "CodedAudioFileReader::~CodedAudioFileReader: deleting cache file reader" << endl; | 
| 64 | 67 | 
| 65 delete m_cacheFileReader; | 68 delete m_cacheFileReader; | 
| 71 } | 74 } | 
| 72 } | 75 } | 
| 73 | 76 | 
| 74 delete m_resampler; | 77 delete m_resampler; | 
| 75 delete[] m_resampleBuffer; | 78 delete[] m_resampleBuffer; | 
| 79 | |
| 80 if (!m_data.empty()) { | |
| 81 StorageAdviser::notifyDoneAllocation | |
| 82 (StorageAdviser::MemoryAllocation, | |
| 83 (m_data.size() * sizeof(float)) / 1024); | |
| 84 } | |
| 76 } | 85 } | 
| 77 | 86 | 
| 78 void | 87 void | 
| 79 CodedAudioFileReader::startSerialised(QString id) | 88 CodedAudioFileReader::startSerialised(QString id) | 
| 80 { | 89 { | 
| 240 } | 249 } | 
| 241 } | 250 } | 
| 242 } | 251 } | 
| 243 | 252 | 
| 244 void | 253 void | 
| 245 CodedAudioFileReader::addSamplesToDecodeCache(const SampleBlock &samples) | 254 CodedAudioFileReader::addSamplesToDecodeCache(const vector<float> &samples) | 
| 246 { | 255 { | 
| 247 QMutexLocker locker(&m_cacheMutex); | 256 QMutexLocker locker(&m_cacheMutex); | 
| 248 | 257 | 
| 249 if (!m_initialised) return; | 258 if (!m_initialised) return; | 
| 250 | 259 | 
| 290 | 299 | 
| 291 delete m_resampler; | 300 delete m_resampler; | 
| 292 m_resampler = 0; | 301 m_resampler = 0; | 
| 293 | 302 | 
| 294 if (m_cacheMode == CacheInTemporaryFile) { | 303 if (m_cacheMode == CacheInTemporaryFile) { | 
| 304 | |
| 295 sf_close(m_cacheFileWritePtr); | 305 sf_close(m_cacheFileWritePtr); | 
| 296 m_cacheFileWritePtr = 0; | 306 m_cacheFileWritePtr = 0; | 
| 297 if (m_cacheFileReader) m_cacheFileReader->updateFrameCount(); | 307 if (m_cacheFileReader) m_cacheFileReader->updateFrameCount(); | 
| 308 | |
| 309 } else { | |
| 310 // I know, I know, we already allocated it... | |
| 311 StorageAdviser::notifyPlannedAllocation | |
| 312 (StorageAdviser::MemoryAllocation, | |
| 313 (m_data.size() * sizeof(float)) / 1024); | |
| 298 } | 314 } | 
| 299 } | 315 } | 
| 300 | 316 | 
| 301 void | 317 void | 
| 302 CodedAudioFileReader::pushBuffer(float *buffer, sv_frame_t sz, bool final) | 318 CodedAudioFileReader::pushBuffer(float *buffer, sv_frame_t sz, bool final) | 
| 349 throw InsufficientDiscSpace(TempDirectory::getInstance()->getPath()); | 365 throw InsufficientDiscSpace(TempDirectory::getInstance()->getPath()); | 
| 350 } | 366 } | 
| 351 break; | 367 break; | 
| 352 | 368 | 
| 353 case CacheInMemory: | 369 case CacheInMemory: | 
| 354 m_dataLock.lockForWrite(); | 370 m_dataLock.lock(); | 
| 355 for (sv_frame_t s = 0; s < count; ++s) { | 371 m_data.insert(m_data.end(), buffer, buffer + count); | 
| 356 m_data.push_back(buffer[s]); | |
| 357 } | |
| 358 m_dataLock.unlock(); | 372 m_dataLock.unlock(); | 
| 359 break; | 373 break; | 
| 360 } | 374 } | 
| 361 } | 375 } | 
| 362 | 376 | 
| 406 pushBufferNonResampling(m_resampleBuffer, out); | 420 pushBufferNonResampling(m_resampleBuffer, out); | 
| 407 delete[] padding; | 421 delete[] padding; | 
| 408 } | 422 } | 
| 409 } | 423 } | 
| 410 | 424 | 
| 411 SampleBlock | 425 vector<float> | 
| 412 CodedAudioFileReader::getInterleavedFrames(sv_frame_t start, sv_frame_t count) const | 426 CodedAudioFileReader::getInterleavedFrames(sv_frame_t start, sv_frame_t count) const | 
| 413 { | 427 { | 
| 414 // Lock is only required in CacheInMemory mode (the cache file | 428 // Lock is only required in CacheInMemory mode (the cache file | 
| 415 // reader is expected to be thread safe and manage its own | 429 // reader is expected to be thread safe and manage its own | 
| 416 // locking) | 430 // locking) | 
| 417 | 431 | 
| 418 if (!m_initialised) { | 432 if (!m_initialised) { | 
| 419 SVDEBUG << "CodedAudioFileReader::getInterleavedFrames: not initialised" << endl; | 433 SVDEBUG << "CodedAudioFileReader::getInterleavedFrames: not initialised" << endl; | 
| 420 return SampleBlock(); | 434 return {}; | 
| 421 } | 435 } | 
| 422 | 436 | 
| 423 SampleBlock frames; | 437 vector<float> frames; | 
| 424 | 438 | 
| 425 switch (m_cacheMode) { | 439 switch (m_cacheMode) { | 
| 426 | 440 | 
| 427 case CacheInTemporaryFile: | 441 case CacheInTemporaryFile: | 
| 428 if (m_cacheFileReader) { | 442 if (m_cacheFileReader) { | 
| 430 } | 444 } | 
| 431 break; | 445 break; | 
| 432 | 446 | 
| 433 case CacheInMemory: | 447 case CacheInMemory: | 
| 434 { | 448 { | 
| 435 if (!isOK()) return SampleBlock(); | 449 if (!isOK()) return {}; | 
| 436 if (count == 0) return SampleBlock(); | 450 if (count == 0) return {}; | 
| 437 | 451 | 
| 438 sv_frame_t idx = start * m_channelCount; | 452 sv_frame_t ix0 = start * m_channelCount; | 
| 439 sv_frame_t i = 0; | 453 sv_frame_t ix1 = ix0 + (count * m_channelCount); | 
| 440 sv_frame_t n = count * m_channelCount; | 454 | 
| 441 | 455 | 
| 442 frames.resize(n); | 456 // This lock used to be a QReadWriteLock, but it appears that | 
| 443 | 457 // its lock mechanism is significantly slower than QMutex so | 
| 444 m_dataLock.lockForRead(); | 458 // it's not a good idea in cases like this where we don't | 
| 445 while (i < n && in_range_for(m_data, idx)) { | 459 // really have threads taking a long time to read concurrently | 
| 446 frames[i++] = m_data[idx++]; | 460 m_dataLock.lock(); | 
| 447 } | 461 sv_frame_t n = sv_frame_t(m_data.size()); | 
| 462 if (ix1 > n) ix1 = n; | |
| 463 frames = vector<float>(m_data.begin() + ix0, m_data.begin() + ix1); | |
| 448 m_dataLock.unlock(); | 464 m_dataLock.unlock(); | 
| 449 | |
| 450 frames.resize(i); | |
| 451 } | 465 } | 
| 452 } | 466 } | 
| 453 | 467 | 
| 454 if (m_normalised) { | 468 if (m_normalised) { | 
| 455 for (auto &f: frames) f *= m_gain; | 469 for (auto &f: frames) f *= m_gain; | 
