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