00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "WaveFileModel.h"
00017
00018 #include "fileio/AudioFileReader.h"
00019 #include "fileio/AudioFileReaderFactory.h"
00020
00021 #include "system/System.h"
00022
00023 #include <QMessageBox>
00024 #include <QFileInfo>
00025 #include <QTextStream>
00026
00027 #include <iostream>
00028 #include <unistd.h>
00029 #include <math.h>
00030 #include <sndfile.h>
00031
00032 #include <cassert>
00033
00034
00035
00036 using std::cerr;
00037 using std::endl;
00038
00039 PowerOfSqrtTwoZoomConstraint
00040 WaveFileModel::m_zoomConstraint;
00041
00042 WaveFileModel::WaveFileModel(FileSource source, size_t targetRate) :
00043 m_source(source),
00044 m_path(source.getLocation()),
00045 m_myReader(true),
00046 m_startFrame(0),
00047 m_fillThread(0),
00048 m_updateTimer(0),
00049 m_lastFillExtent(0),
00050 m_exiting(false)
00051 {
00052 m_source.waitForData();
00053 if (m_source.isOK()) {
00054 m_reader = AudioFileReaderFactory::createThreadingReader
00055 (m_source, targetRate);
00056 if (m_reader) {
00057 std::cerr << "WaveFileModel::WaveFileModel: reader rate: "
00058 << m_reader->getSampleRate() << std::endl;
00059 }
00060 }
00061 if (m_reader) setObjectName(m_reader->getTitle());
00062 if (objectName() == "") setObjectName(QFileInfo(m_path).fileName());
00063 if (isOK()) fillCache();
00064 }
00065
00066 WaveFileModel::WaveFileModel(FileSource source, AudioFileReader *reader) :
00067 m_source(source),
00068 m_path(source.getLocation()),
00069 m_myReader(false),
00070 m_startFrame(0),
00071 m_fillThread(0),
00072 m_updateTimer(0),
00073 m_lastFillExtent(0),
00074 m_exiting(false)
00075 {
00076 m_reader = reader;
00077 if (m_reader) setObjectName(m_reader->getTitle());
00078 if (objectName() == "") setObjectName(QFileInfo(m_path).fileName());
00079 fillCache();
00080 }
00081
00082 WaveFileModel::~WaveFileModel()
00083 {
00084 m_exiting = true;
00085 if (m_fillThread) m_fillThread->wait();
00086 if (m_myReader) delete m_reader;
00087 m_reader = 0;
00088 }
00089
00090 bool
00091 WaveFileModel::isOK() const
00092 {
00093 return m_reader && m_reader->isOK();
00094 }
00095
00096 bool
00097 WaveFileModel::isReady(int *completion) const
00098 {
00099 bool ready = (isOK() && (m_fillThread == 0));
00100 double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
00101 static int prevCompletion = 0;
00102 if (completion) {
00103 *completion = int(c * 100.0 + 0.01);
00104 if (m_reader) {
00105 int decodeCompletion = m_reader->getDecodeCompletion();
00106 if (decodeCompletion < 90) *completion = decodeCompletion;
00107 else *completion = std::min(*completion, decodeCompletion);
00108 }
00109 if (*completion != 0 &&
00110 *completion != 100 &&
00111 prevCompletion != 0 &&
00112 prevCompletion > *completion) {
00113
00114 *completion = prevCompletion;
00115 }
00116 prevCompletion = *completion;
00117 }
00118 #ifdef DEBUG_WAVE_FILE_MODEL
00119 std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl;
00120 #endif
00121 return ready;
00122 }
00123
00124 Model *
00125 WaveFileModel::clone() const
00126 {
00127 WaveFileModel *model = new WaveFileModel(m_source);
00128 return model;
00129 }
00130
00131 size_t
00132 WaveFileModel::getFrameCount() const
00133 {
00134 if (!m_reader) return 0;
00135 return m_reader->getFrameCount();
00136 }
00137
00138 size_t
00139 WaveFileModel::getChannelCount() const
00140 {
00141 if (!m_reader) return 0;
00142 return m_reader->getChannelCount();
00143 }
00144
00145 size_t
00146 WaveFileModel::getSampleRate() const
00147 {
00148 if (!m_reader) return 0;
00149 return m_reader->getSampleRate();
00150 }
00151
00152 size_t
00153 WaveFileModel::getNativeRate() const
00154 {
00155 if (!m_reader) return 0;
00156 size_t rate = m_reader->getNativeRate();
00157 if (rate == 0) rate = getSampleRate();
00158 return rate;
00159 }
00160
00161 QString
00162 WaveFileModel::getTitle() const
00163 {
00164 QString title;
00165 if (m_reader) title = m_reader->getTitle();
00166 if (title == "") title = objectName();
00167 return title;
00168 }
00169
00170 QString
00171 WaveFileModel::getMaker() const
00172 {
00173 if (m_reader) return m_reader->getMaker();
00174 return "";
00175 }
00176
00177 QString
00178 WaveFileModel::getLocation() const
00179 {
00180 if (m_reader) return m_reader->getLocation();
00181 return "";
00182 }
00183
00184 size_t
00185 WaveFileModel::getData(int channel, size_t start, size_t count,
00186 float *buffer) const
00187 {
00188
00189
00190
00191
00192 if (start >= m_startFrame) {
00193 start -= m_startFrame;
00194 } else {
00195 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
00196 if (count <= m_startFrame - start) {
00197 return 0;
00198 } else {
00199 count -= (m_startFrame - start);
00200 start = 0;
00201 }
00202 }
00203
00204 if (!m_reader || !m_reader->isOK() || count == 0) {
00205 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
00206 return 0;
00207 }
00208
00209 #ifdef DEBUG_WAVE_FILE_MODEL
00210
00211
00212 #endif
00213
00214 int channels = getChannelCount();
00215
00216 SampleBlock frames(count * channels);
00217 m_reader->getInterleavedFrames(start, count, frames);
00218
00219 size_t i = 0;
00220
00221 int ch0 = channel, ch1 = channel;
00222 if (channel == -1) {
00223 ch0 = 0;
00224 ch1 = channels - 1;
00225 }
00226
00227 while (i < count) {
00228
00229 buffer[i] = 0.0;
00230
00231 for (int ch = ch0; ch <= ch1; ++ch) {
00232
00233 size_t index = i * channels + ch;
00234 if (index >= frames.size()) break;
00235
00236 float sample = frames[index];
00237 buffer[i] += sample;
00238 }
00239
00240 ++i;
00241 }
00242
00243 return i;
00244 }
00245
00246 size_t
00247 WaveFileModel::getData(int channel, size_t start, size_t count,
00248 double *buffer) const
00249 {
00250 if (start > m_startFrame) {
00251 start -= m_startFrame;
00252 } else {
00253 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
00254 if (count <= m_startFrame - start) {
00255 return 0;
00256 } else {
00257 count -= (m_startFrame - start);
00258 start = 0;
00259 }
00260 }
00261
00262 if (!m_reader || !m_reader->isOK() || count == 0) {
00263 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
00264 return 0;
00265 }
00266
00267 int channels = getChannelCount();
00268
00269 SampleBlock frames(count * channels);
00270 m_reader->getInterleavedFrames(start, count, frames);
00271
00272 size_t i = 0;
00273
00274 int ch0 = channel, ch1 = channel;
00275 if (channel == -1) {
00276 ch0 = 0;
00277 ch1 = channels - 1;
00278 }
00279
00280 while (i < count) {
00281
00282 buffer[i] = 0.0;
00283
00284 for (int ch = ch0; ch <= ch1; ++ch) {
00285
00286 size_t index = i * channels + ch;
00287 if (index >= frames.size()) break;
00288
00289 float sample = frames[index];
00290 buffer[i] += sample;
00291 }
00292
00293 ++i;
00294 }
00295
00296 return i;
00297 }
00298
00299 size_t
00300 WaveFileModel::getData(size_t fromchannel, size_t tochannel,
00301 size_t start, size_t count,
00302 float **buffer) const
00303 {
00304 size_t channels = getChannelCount();
00305
00306 if (fromchannel > tochannel) {
00307 std::cerr << "ERROR: WaveFileModel::getData: fromchannel ("
00308 << fromchannel << ") > tochannel (" << tochannel << ")"
00309 << std::endl;
00310 return 0;
00311 }
00312
00313 if (tochannel >= channels) {
00314 std::cerr << "ERROR: WaveFileModel::getData: tochannel ("
00315 << tochannel << ") >= channel count (" << channels << ")"
00316 << std::endl;
00317 return 0;
00318 }
00319
00320 if (fromchannel == tochannel) {
00321 return getData(fromchannel, start, count, buffer[0]);
00322 }
00323
00324 size_t reqchannels = (tochannel - fromchannel) + 1;
00325
00326
00327
00328
00329
00330 if (start >= m_startFrame) {
00331 start -= m_startFrame;
00332 } else {
00333 for (size_t c = 0; c < reqchannels; ++c) {
00334 for (size_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
00335 }
00336 if (count <= m_startFrame - start) {
00337 return 0;
00338 } else {
00339 count -= (m_startFrame - start);
00340 start = 0;
00341 }
00342 }
00343
00344 if (!m_reader || !m_reader->isOK() || count == 0) {
00345 for (size_t c = 0; c < reqchannels; ++c) {
00346 for (size_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
00347 }
00348 return 0;
00349 }
00350
00351 SampleBlock frames(count * channels);
00352 m_reader->getInterleavedFrames(start, count, frames);
00353
00354 size_t i = 0;
00355
00356 int ch0 = fromchannel, ch1 = tochannel;
00357
00358 size_t index = 0, available = frames.size();
00359
00360 while (i < count) {
00361
00362 if (index >= available) break;
00363
00364 size_t destc = 0;
00365
00366 for (size_t c = 0; c < channels; ++c) {
00367
00368 if (c >= fromchannel && c <= tochannel) {
00369 buffer[destc][i] = frames[index];
00370 ++destc;
00371 }
00372
00373 ++index;
00374 }
00375
00376 ++i;
00377 }
00378
00379 return i;
00380 }
00381
00382 size_t
00383 WaveFileModel::getSummaryBlockSize(size_t desired) const
00384 {
00385 int cacheType = 0;
00386 int power = m_zoomConstraint.getMinCachePower();
00387 size_t roundedBlockSize = m_zoomConstraint.getNearestBlockSize
00388 (desired, cacheType, power, ZoomConstraint::RoundDown);
00389 if (cacheType != 0 && cacheType != 1) {
00390
00391
00392 return desired;
00393 } else {
00394 return roundedBlockSize;
00395 }
00396 }
00397
00398 void
00399 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count,
00400 RangeBlock &ranges, size_t &blockSize) const
00401 {
00402 ranges.clear();
00403 if (!isOK()) return;
00404 ranges.reserve((count / blockSize) + 1);
00405
00406 if (start > m_startFrame) start -= m_startFrame;
00407 else if (count <= m_startFrame - start) return;
00408 else {
00409 count -= (m_startFrame - start);
00410 start = 0;
00411 }
00412
00413 int cacheType = 0;
00414 int power = m_zoomConstraint.getMinCachePower();
00415 size_t roundedBlockSize = m_zoomConstraint.getNearestBlockSize
00416 (blockSize, cacheType, power, ZoomConstraint::RoundDown);
00417
00418 size_t channels = getChannelCount();
00419
00420 if (cacheType != 0 && cacheType != 1) {
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 m_directReadMutex.lock();
00431
00432 if (m_lastDirectReadStart != start ||
00433 m_lastDirectReadCount != count ||
00434 m_directRead.empty()) {
00435
00436 m_reader->getInterleavedFrames(start, count, m_directRead);
00437 m_lastDirectReadStart = start;
00438 m_lastDirectReadCount = count;
00439 }
00440
00441 float max = 0.0, min = 0.0, total = 0.0;
00442 size_t i = 0, got = 0;
00443
00444 while (i < count) {
00445
00446 size_t index = i * channels + channel;
00447 if (index >= m_directRead.size()) break;
00448
00449 float sample = m_directRead[index];
00450 if (sample > max || got == 0) max = sample;
00451 if (sample < min || got == 0) min = sample;
00452 total += fabsf(sample);
00453
00454 ++i;
00455 ++got;
00456
00457 if (got == blockSize) {
00458 ranges.push_back(Range(min, max, total / got));
00459 min = max = total = 0.0f;
00460 got = 0;
00461 }
00462 }
00463
00464 m_directReadMutex.unlock();
00465
00466 if (got > 0) {
00467 ranges.push_back(Range(min, max, total / got));
00468 }
00469
00470 return;
00471
00472 } else {
00473
00474 QMutexLocker locker(&m_mutex);
00475
00476 const RangeBlock &cache = m_cache[cacheType];
00477
00478 blockSize = roundedBlockSize;
00479
00480 size_t cacheBlock, div;
00481
00482 if (cacheType == 0) {
00483 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
00484 div = (1 << power) / cacheBlock;
00485 } else {
00486 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01));
00487 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock;
00488 }
00489
00490 size_t startIndex = start / cacheBlock;
00491 size_t endIndex = (start + count) / cacheBlock;
00492
00493 float max = 0.0, min = 0.0, total = 0.0;
00494 size_t i = 0, got = 0;
00495
00496 #ifdef DEBUG_WAVE_FILE_MODEL
00497 cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", count " << count << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl;
00498 #endif
00499
00500 for (i = 0; i <= endIndex - startIndex; ) {
00501
00502 size_t index = (i + startIndex) * channels + channel;
00503 if (index >= cache.size()) break;
00504
00505 const Range &range = cache[index];
00506 if (range.max > max || got == 0) max = range.max;
00507 if (range.min < min || got == 0) min = range.min;
00508 total += range.absmean;
00509
00510 ++i;
00511 ++got;
00512
00513 if (got == div) {
00514 ranges.push_back(Range(min, max, total / got));
00515 min = max = total = 0.0f;
00516 got = 0;
00517 }
00518 }
00519
00520 if (got > 0) {
00521 ranges.push_back(Range(min, max, total / got));
00522 }
00523 }
00524
00525 #ifdef DEBUG_WAVE_FILE_MODEL
00526 cerr << "returning " << ranges.size() << " ranges" << endl;
00527 #endif
00528 return;
00529 }
00530
00531 WaveFileModel::Range
00532 WaveFileModel::getSummary(size_t channel, size_t start, size_t count) const
00533 {
00534 Range range;
00535 if (!isOK()) return range;
00536
00537 if (start > m_startFrame) start -= m_startFrame;
00538 else if (count <= m_startFrame - start) return range;
00539 else {
00540 count -= (m_startFrame - start);
00541 start = 0;
00542 }
00543
00544 size_t blockSize;
00545 for (blockSize = 1; blockSize <= count; blockSize *= 2);
00546 if (blockSize > 1) blockSize /= 2;
00547
00548 bool first = false;
00549
00550 size_t blockStart = (start / blockSize) * blockSize;
00551 size_t blockEnd = ((start + count) / blockSize) * blockSize;
00552
00553 if (blockStart < start) blockStart += blockSize;
00554
00555 if (blockEnd > blockStart) {
00556 RangeBlock ranges;
00557 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
00558 for (size_t i = 0; i < ranges.size(); ++i) {
00559 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
00560 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
00561 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
00562 first = false;
00563 }
00564 }
00565
00566 if (blockStart > start) {
00567 Range startRange = getSummary(channel, start, blockStart - start);
00568 range.min = std::min(range.min, startRange.min);
00569 range.max = std::max(range.max, startRange.max);
00570 range.absmean = std::min(range.absmean, startRange.absmean);
00571 }
00572
00573 if (blockEnd < start + count) {
00574 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
00575 range.min = std::min(range.min, endRange.min);
00576 range.max = std::max(range.max, endRange.max);
00577 range.absmean = std::min(range.absmean, endRange.absmean);
00578 }
00579
00580 return range;
00581 }
00582
00583 void
00584 WaveFileModel::fillCache()
00585 {
00586 m_mutex.lock();
00587
00588 m_updateTimer = new QTimer(this);
00589 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
00590 m_updateTimer->start(100);
00591
00592 m_fillThread = new RangeCacheFillThread(*this);
00593 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
00594
00595 m_mutex.unlock();
00596 m_fillThread->start();
00597
00598 #ifdef DEBUG_WAVE_FILE_MODEL
00599 std::cerr << "WaveFileModel::fillCache: started fill thread" << std::endl;
00600 #endif
00601 }
00602
00603 void
00604 WaveFileModel::fillTimerTimedOut()
00605 {
00606 if (m_fillThread) {
00607 size_t fillExtent = m_fillThread->getFillExtent();
00608 #ifdef DEBUG_WAVE_FILE_MODEL
00609 cerr << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
00610 #endif
00611 if (fillExtent > m_lastFillExtent) {
00612 emit modelChanged(m_lastFillExtent, fillExtent);
00613 m_lastFillExtent = fillExtent;
00614 }
00615 } else {
00616 #ifdef DEBUG_WAVE_FILE_MODEL
00617 cerr << "WaveFileModel::fillTimerTimedOut: no thread" << std::endl;
00618 #endif
00619 emit modelChanged();
00620 }
00621 }
00622
00623 void
00624 WaveFileModel::cacheFilled()
00625 {
00626 m_mutex.lock();
00627 delete m_fillThread;
00628 m_fillThread = 0;
00629 delete m_updateTimer;
00630 m_updateTimer = 0;
00631 m_mutex.unlock();
00632 if (getEndFrame() > m_lastFillExtent) {
00633 emit modelChanged(m_lastFillExtent, getEndFrame());
00634 }
00635 emit modelChanged();
00636 #ifdef DEBUG_WAVE_FILE_MODEL
00637 cerr << "WaveFileModel::cacheFilled" << endl;
00638 #endif
00639 }
00640
00641 void
00642 WaveFileModel::RangeCacheFillThread::run()
00643 {
00644 size_t cacheBlockSize[2];
00645 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
00646 cacheBlockSize[1] = ((unsigned int)((1 << m_model.m_zoomConstraint.getMinCachePower()) *
00647 sqrt(2) + 0.01));
00648
00649 size_t frame = 0;
00650 size_t readBlockSize = 16384;
00651 SampleBlock block;
00652
00653 if (!m_model.isOK()) return;
00654
00655 size_t channels = m_model.getChannelCount();
00656 bool updating = m_model.m_reader->isUpdating();
00657
00658 if (updating) {
00659 while (channels == 0 && !m_model.m_exiting) {
00660
00661 sleep(1);
00662 channels = m_model.getChannelCount();
00663 }
00664 }
00665
00666 Range *range = new Range[2 * channels];
00667 size_t count[2];
00668 count[0] = count[1] = 0;
00669
00670 bool first = true;
00671
00672 while (first || updating) {
00673
00674 updating = m_model.m_reader->isUpdating();
00675 m_frameCount = m_model.getFrameCount();
00676
00677
00678
00679 while (frame < m_frameCount) {
00680
00681
00682
00683 if (updating && (frame + readBlockSize > m_frameCount)) break;
00684
00685 m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block);
00686
00687
00688
00689 for (size_t i = 0; i < readBlockSize; ++i) {
00690
00691 if (channels * i + channels > block.size()) break;
00692
00693 for (size_t ch = 0; ch < size_t(channels); ++ch) {
00694
00695 size_t index = channels * i + ch;
00696 float sample = block[index];
00697
00698 for (size_t ct = 0; ct < 2; ++ct) {
00699
00700 size_t rangeIndex = ch * 2 + ct;
00701
00702 if (sample > range[rangeIndex].max || count[ct] == 0) {
00703 range[rangeIndex].max = sample;
00704 }
00705 if (sample < range[rangeIndex].min || count[ct] == 0) {
00706 range[rangeIndex].min = sample;
00707 }
00708 range[rangeIndex].absmean += fabsf(sample);
00709 }
00710 }
00711
00712 QMutexLocker locker(&m_model.m_mutex);
00713
00714 for (size_t ct = 0; ct < 2; ++ct) {
00715
00716 if (++count[ct] == cacheBlockSize[ct]) {
00717
00718 for (size_t ch = 0; ch < size_t(channels); ++ch) {
00719 size_t rangeIndex = ch * 2 + ct;
00720 range[rangeIndex].absmean /= count[ct];
00721 m_model.m_cache[ct].push_back(range[rangeIndex]);
00722 range[rangeIndex] = Range();
00723 }
00724
00725 count[ct] = 0;
00726 }
00727 }
00728
00729 ++frame;
00730 }
00731
00732 if (m_model.m_exiting) break;
00733
00734 m_fillExtent = frame;
00735 }
00736
00737
00738
00739 first = false;
00740 if (m_model.m_exiting) break;
00741 if (updating) {
00742
00743 sleep(1);
00744 }
00745 }
00746
00747 if (!m_model.m_exiting) {
00748
00749 QMutexLocker locker(&m_model.m_mutex);
00750
00751 for (size_t ct = 0; ct < 2; ++ct) {
00752
00753 if (count[ct] > 0) {
00754
00755 for (size_t ch = 0; ch < size_t(channels); ++ch) {
00756 size_t rangeIndex = ch * 2 + ct;
00757 range[rangeIndex].absmean /= count[ct];
00758 m_model.m_cache[ct].push_back(range[rangeIndex]);
00759 range[rangeIndex] = Range();
00760 }
00761
00762 count[ct] = 0;
00763 }
00764
00765 const Range &rr = *m_model.m_cache[ct].begin();
00766 MUNLOCK(&rr, m_model.m_cache[ct].capacity() * sizeof(Range));
00767 }
00768 }
00769
00770 delete[] range;
00771
00772 m_fillExtent = m_frameCount;
00773
00774 #ifdef DEBUG_WAVE_FILE_MODEL
00775 for (size_t ct = 0; ct < 2; ++ct) {
00776 cerr << "Cache type " << ct << " now contains " << m_model.m_cache[ct].size() << " ranges" << endl;
00777 }
00778 #endif
00779 }
00780
00781 void
00782 WaveFileModel::toXml(QTextStream &out,
00783 QString indent,
00784 QString extraAttributes) const
00785 {
00786 Model::toXml(out, indent,
00787 QString("type=\"wavefile\" file=\"%1\" %2")
00788 .arg(encodeEntities(m_path)).arg(extraAttributes));
00789 }
00790
00791