svcore  1.9
WaveFileModel.cpp
Go to the documentation of this file.
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