annotate data/model/WaveFileModel.cpp @ 263:71dfc6ab3b54

* Threaded mp3/ogg file reading. Not activated yet, as it doesn't work in context (SV needs to know the duration of its main model at the outset)
author Chris Cannam
date Thu, 24 May 2007 16:20:22 +0000
parents 96a6dd889c68
children e08f486e8d8c
rev   line source
Chris@147 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@147 2
Chris@147 3 /*
Chris@147 4 Sonic Visualiser
Chris@147 5 An audio file viewer and annotation editor.
Chris@147 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@147 8
Chris@147 9 This program is free software; you can redistribute it and/or
Chris@147 10 modify it under the terms of the GNU General Public License as
Chris@147 11 published by the Free Software Foundation; either version 2 of the
Chris@147 12 License, or (at your option) any later version. See the file
Chris@147 13 COPYING included with this distribution for more information.
Chris@147 14 */
Chris@147 15
Chris@150 16 #include "WaveFileModel.h"
Chris@147 17
Chris@147 18 #include "fileio/AudioFileReader.h"
Chris@147 19 #include "fileio/AudioFileReaderFactory.h"
Chris@147 20
Chris@150 21 #include "system/System.h"
Chris@147 22
Chris@147 23 #include <QMessageBox>
Chris@147 24 #include <QFileInfo>
Chris@147 25
Chris@147 26 #include <iostream>
Chris@147 27 #include <unistd.h>
Chris@147 28 #include <math.h>
Chris@147 29 #include <sndfile.h>
Chris@147 30
Chris@147 31 #include <cassert>
Chris@147 32
Chris@236 33 //#define DEBUG_WAVE_FILE_MODEL 1
Chris@236 34
Chris@147 35 using std::cerr;
Chris@147 36 using std::endl;
Chris@147 37
Chris@179 38 PowerOfSqrtTwoZoomConstraint
Chris@179 39 WaveFileModel::m_zoomConstraint;
Chris@179 40
Chris@147 41 WaveFileModel::WaveFileModel(QString path) :
Chris@147 42 m_path(path),
Chris@175 43 m_myReader(true),
Chris@147 44 m_fillThread(0),
Chris@147 45 m_updateTimer(0),
Chris@147 46 m_lastFillExtent(0),
Chris@147 47 m_exiting(false)
Chris@147 48 {
Chris@147 49 m_reader = AudioFileReaderFactory::createReader(path);
Chris@175 50 setObjectName(QFileInfo(path).fileName());
Chris@175 51 if (isOK()) fillCache();
Chris@175 52 }
Chris@175 53
Chris@211 54 WaveFileModel::WaveFileModel(QString path, QString originalLocation) :
Chris@211 55 m_path(originalLocation),
Chris@211 56 m_myReader(true),
Chris@211 57 m_fillThread(0),
Chris@211 58 m_updateTimer(0),
Chris@211 59 m_lastFillExtent(0),
Chris@211 60 m_exiting(false)
Chris@211 61 {
Chris@211 62 m_reader = AudioFileReaderFactory::createReader(path);
Chris@211 63 setObjectName(QFileInfo(originalLocation).fileName());
Chris@211 64 if (isOK()) fillCache();
Chris@211 65 }
Chris@211 66
Chris@175 67 WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) :
Chris@175 68 m_path(path),
Chris@175 69 m_myReader(false),
Chris@175 70 m_fillThread(0),
Chris@175 71 m_updateTimer(0),
Chris@175 72 m_lastFillExtent(0),
Chris@175 73 m_exiting(false)
Chris@175 74 {
Chris@175 75 m_reader = reader;
Chris@147 76 setObjectName(QFileInfo(path).fileName());
Chris@187 77 fillCache();
Chris@147 78 }
Chris@147 79
Chris@147 80 WaveFileModel::~WaveFileModel()
Chris@147 81 {
Chris@147 82 m_exiting = true;
Chris@147 83 if (m_fillThread) m_fillThread->wait();
Chris@175 84 if (m_myReader) delete m_reader;
Chris@147 85 m_reader = 0;
Chris@147 86 }
Chris@147 87
Chris@147 88 bool
Chris@147 89 WaveFileModel::isOK() const
Chris@147 90 {
Chris@147 91 return m_reader && m_reader->isOK();
Chris@147 92 }
Chris@147 93
Chris@147 94 bool
Chris@147 95 WaveFileModel::isReady(int *completion) const
Chris@147 96 {
Chris@147 97 bool ready = (isOK() && (m_fillThread == 0));
Chris@147 98 double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
Chris@147 99 if (completion) *completion = int(c * 100.0 + 0.01);
Chris@236 100 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 101 std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl;
Chris@236 102 #endif
Chris@147 103 return ready;
Chris@147 104 }
Chris@147 105
Chris@147 106 Model *
Chris@147 107 WaveFileModel::clone() const
Chris@147 108 {
Chris@147 109 WaveFileModel *model = new WaveFileModel(m_path);
Chris@147 110 return model;
Chris@147 111 }
Chris@147 112
Chris@147 113 size_t
Chris@147 114 WaveFileModel::getFrameCount() const
Chris@147 115 {
Chris@147 116 if (!m_reader) return 0;
Chris@147 117 return m_reader->getFrameCount();
Chris@147 118 }
Chris@147 119
Chris@147 120 size_t
Chris@147 121 WaveFileModel::getChannelCount() const
Chris@147 122 {
Chris@147 123 if (!m_reader) return 0;
Chris@147 124 return m_reader->getChannelCount();
Chris@147 125 }
Chris@147 126
Chris@147 127 size_t
Chris@147 128 WaveFileModel::getSampleRate() const
Chris@147 129 {
Chris@147 130 if (!m_reader) return 0;
Chris@147 131 return m_reader->getSampleRate();
Chris@147 132 }
Chris@147 133
Chris@147 134 size_t
Chris@147 135 WaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@147 136 float *buffer) const
Chris@147 137 {
Chris@147 138 // Always read these directly from the file.
Chris@147 139 // This is used for e.g. audio playback.
Chris@147 140 // Could be much more efficient (although compiler optimisation will help)
Chris@147 141
Chris@147 142 if (end < start) {
Chris@147 143 std::cerr << "ERROR: WaveFileModel::getValues[float]: end < start ("
Chris@147 144 << end << " < " << start << ")" << std::endl;
Chris@147 145 assert(end >= start);
Chris@147 146 }
Chris@147 147
Chris@147 148 if (!m_reader || !m_reader->isOK()) return 0;
Chris@147 149
Chris@236 150 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@258 151 // std::cerr << "WaveFileModel::getValues(" << channel << ", "
Chris@258 152 // << start << ", " << end << "): calling reader" << std::endl;
Chris@236 153 #endif
Chris@175 154
Chris@147 155 SampleBlock frames;
Chris@147 156 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 157
Chris@147 158 size_t i = 0;
Chris@147 159
Chris@147 160 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 161 if (channel == -1) {
Chris@147 162 ch0 = 0;
Chris@147 163 ch1 = channels - 1;
Chris@147 164 }
Chris@147 165
Chris@147 166 while (i < end - start) {
Chris@147 167
Chris@147 168 buffer[i] = 0.0;
Chris@147 169
Chris@147 170 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 171
Chris@147 172 size_t index = i * channels + ch;
Chris@147 173 if (index >= frames.size()) break;
Chris@147 174
Chris@147 175 float sample = frames[index];
Chris@147 176 buffer[i] += sample;
Chris@147 177 }
Chris@147 178
Chris@147 179 ++i;
Chris@147 180 }
Chris@147 181
Chris@147 182 return i;
Chris@147 183 }
Chris@147 184
Chris@147 185 size_t
Chris@147 186 WaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@147 187 double *buffer) const
Chris@147 188 {
Chris@147 189 if (end < start) {
Chris@147 190 std::cerr << "ERROR: WaveFileModel::getValues[double]: end < start ("
Chris@147 191 << end << " < " << start << ")" << std::endl;
Chris@147 192 assert(end >= start);
Chris@147 193 }
Chris@147 194
Chris@147 195 if (!m_reader || !m_reader->isOK()) return 0;
Chris@147 196
Chris@147 197 SampleBlock frames;
Chris@147 198 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 199
Chris@147 200 size_t i = 0;
Chris@147 201
Chris@147 202 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 203 if (channel == -1) {
Chris@147 204 ch0 = 0;
Chris@147 205 ch1 = channels - 1;
Chris@147 206 }
Chris@147 207
Chris@147 208 while (i < end - start) {
Chris@147 209
Chris@147 210 buffer[i] = 0.0;
Chris@147 211
Chris@147 212 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 213
Chris@147 214 size_t index = i * channels + ch;
Chris@147 215 if (index >= frames.size()) break;
Chris@147 216
Chris@147 217 float sample = frames[index];
Chris@147 218 buffer[i] += sample;
Chris@147 219 }
Chris@147 220
Chris@147 221 ++i;
Chris@147 222 }
Chris@147 223
Chris@147 224 return i;
Chris@147 225 }
Chris@147 226
Chris@225 227 void
Chris@147 228 WaveFileModel::getRanges(size_t channel, size_t start, size_t end,
Chris@225 229 RangeBlock &ranges, size_t &blockSize) const
Chris@147 230 {
Chris@225 231 ranges.clear();
Chris@225 232 if (!isOK()) return;
Chris@147 233
Chris@147 234 if (end <= start) {
Chris@147 235 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRanges (end = " << end << ", start = " << start << ", blocksize = " << blockSize << ")" << std::endl;
Chris@225 236 return;
Chris@147 237 }
Chris@147 238
Chris@147 239 int cacheType = 0;
Chris@179 240 int power = m_zoomConstraint.getMinCachePower();
Chris@179 241 blockSize = m_zoomConstraint.getNearestBlockSize
Chris@179 242 (blockSize, cacheType, power, ZoomConstraint::RoundUp);
Chris@147 243
Chris@147 244 size_t channels = getChannelCount();
Chris@147 245
Chris@147 246 if (cacheType != 0 && cacheType != 1) {
Chris@147 247
Chris@147 248 // We need to read directly from the file. We haven't got
Chris@147 249 // this cached. Hope the requested area is small. This is
Chris@147 250 // not optimal -- we'll end up reading the same frames twice
Chris@147 251 // for stereo files, in two separate calls to this method.
Chris@147 252 // We could fairly trivially handle this for most cases that
Chris@147 253 // matter by putting a single cache in getInterleavedFrames
Chris@147 254 // for short queries.
Chris@147 255
Chris@147 256 SampleBlock frames;
Chris@147 257 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 258 float max = 0.0, min = 0.0, total = 0.0;
Chris@147 259 size_t i = 0, count = 0;
Chris@147 260
Chris@147 261 while (i < end - start) {
Chris@147 262
Chris@147 263 size_t index = i * channels + channel;
Chris@147 264 if (index >= frames.size()) break;
Chris@147 265
Chris@147 266 float sample = frames[index];
Chris@147 267 if (sample > max || count == 0) max = sample;
Chris@147 268 if (sample < min || count == 0) min = sample;
Chris@147 269 total += fabsf(sample);
Chris@147 270
Chris@147 271 ++i;
Chris@147 272 ++count;
Chris@147 273
Chris@147 274 if (count == blockSize) {
Chris@147 275 ranges.push_back(Range(min, max, total / count));
Chris@147 276 min = max = total = 0.0f;
Chris@147 277 count = 0;
Chris@147 278 }
Chris@147 279 }
Chris@147 280
Chris@147 281 if (count > 0) {
Chris@147 282 ranges.push_back(Range(min, max, total / count));
Chris@147 283 }
Chris@147 284
Chris@225 285 return;
Chris@147 286
Chris@147 287 } else {
Chris@147 288
Chris@147 289 QMutexLocker locker(&m_mutex);
Chris@147 290
Chris@147 291 const RangeBlock &cache = m_cache[cacheType];
Chris@147 292
Chris@147 293 size_t cacheBlock, div;
Chris@147 294
Chris@147 295 if (cacheType == 0) {
Chris@179 296 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
Chris@147 297 div = (1 << power) / cacheBlock;
Chris@147 298 } else {
Chris@179 299 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01));
Chris@147 300 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock;
Chris@147 301 }
Chris@147 302
Chris@147 303 size_t startIndex = start / cacheBlock;
Chris@147 304 size_t endIndex = end / cacheBlock;
Chris@147 305
Chris@147 306 float max = 0.0, min = 0.0, total = 0.0;
Chris@147 307 size_t i = 0, count = 0;
Chris@147 308
Chris@236 309 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@232 310 cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", end " << end << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl;
Chris@236 311 #endif
Chris@147 312
Chris@147 313 for (i = 0; i < endIndex - startIndex; ) {
Chris@147 314
Chris@147 315 size_t index = (i + startIndex) * channels + channel;
Chris@147 316 if (index >= cache.size()) break;
Chris@147 317
Chris@147 318 const Range &range = cache[index];
Chris@147 319 if (range.max > max || count == 0) max = range.max;
Chris@147 320 if (range.min < min || count == 0) min = range.min;
Chris@147 321 total += range.absmean;
Chris@147 322
Chris@147 323 ++i;
Chris@147 324 ++count;
Chris@147 325
Chris@147 326 if (count == div) {
Chris@147 327 ranges.push_back(Range(min, max, total / count));
Chris@147 328 min = max = total = 0.0f;
Chris@147 329 count = 0;
Chris@147 330 }
Chris@147 331 }
Chris@147 332
Chris@147 333 if (count > 0) {
Chris@147 334 ranges.push_back(Range(min, max, total / count));
Chris@147 335 }
Chris@147 336 }
Chris@147 337
Chris@236 338 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@232 339 cerr << "returning " << ranges.size() << " ranges" << endl;
Chris@236 340 #endif
Chris@225 341 return;
Chris@147 342 }
Chris@147 343
Chris@147 344 WaveFileModel::Range
Chris@147 345 WaveFileModel::getRange(size_t channel, size_t start, size_t end) const
Chris@147 346 {
Chris@147 347 Range range;
Chris@147 348 if (!isOK()) return range;
Chris@147 349
Chris@147 350 if (end <= start) {
Chris@147 351 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRange (end = " << end << ", start = " << start << ")" << std::endl;
Chris@147 352 return range;
Chris@147 353 }
Chris@147 354
Chris@147 355 size_t blockSize;
Chris@147 356 for (blockSize = 1; blockSize <= end - start; blockSize *= 2);
Chris@147 357 blockSize /= 2;
Chris@147 358
Chris@147 359 bool first = false;
Chris@147 360
Chris@147 361 size_t blockStart = (start / blockSize) * blockSize;
Chris@147 362 size_t blockEnd = (end / blockSize) * blockSize;
Chris@147 363
Chris@147 364 if (blockStart < start) blockStart += blockSize;
Chris@147 365
Chris@147 366 if (blockEnd > blockStart) {
Chris@225 367 RangeBlock ranges;
Chris@225 368 getRanges(channel, blockStart, blockEnd, ranges, blockSize);
Chris@147 369 for (size_t i = 0; i < ranges.size(); ++i) {
Chris@147 370 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
Chris@147 371 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
Chris@147 372 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
Chris@147 373 first = false;
Chris@147 374 }
Chris@147 375 }
Chris@147 376
Chris@147 377 if (blockStart > start) {
Chris@147 378 Range startRange = getRange(channel, start, blockStart);
Chris@147 379 range.min = std::min(range.min, startRange.min);
Chris@147 380 range.max = std::max(range.max, startRange.max);
Chris@147 381 range.absmean = std::min(range.absmean, startRange.absmean);
Chris@147 382 }
Chris@147 383
Chris@147 384 if (blockEnd < end) {
Chris@147 385 Range endRange = getRange(channel, blockEnd, end);
Chris@147 386 range.min = std::min(range.min, endRange.min);
Chris@147 387 range.max = std::max(range.max, endRange.max);
Chris@147 388 range.absmean = std::min(range.absmean, endRange.absmean);
Chris@147 389 }
Chris@147 390
Chris@147 391 return range;
Chris@147 392 }
Chris@147 393
Chris@147 394 void
Chris@147 395 WaveFileModel::fillCache()
Chris@147 396 {
Chris@147 397 m_mutex.lock();
Chris@188 398
Chris@147 399 m_updateTimer = new QTimer(this);
Chris@147 400 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
Chris@147 401 m_updateTimer->start(100);
Chris@188 402
Chris@147 403 m_fillThread = new RangeCacheFillThread(*this);
Chris@147 404 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
Chris@188 405
Chris@147 406 m_mutex.unlock();
Chris@147 407 m_fillThread->start();
Chris@188 408
Chris@236 409 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 410 std::cerr << "WaveFileModel::fillCache: started fill thread" << std::endl;
Chris@236 411 #endif
Chris@147 412 }
Chris@147 413
Chris@147 414 void
Chris@147 415 WaveFileModel::fillTimerTimedOut()
Chris@147 416 {
Chris@147 417 if (m_fillThread) {
Chris@147 418 size_t fillExtent = m_fillThread->getFillExtent();
Chris@236 419 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 420 cerr << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
Chris@236 421 #endif
Chris@147 422 if (fillExtent > m_lastFillExtent) {
Chris@147 423 emit modelChanged(m_lastFillExtent, fillExtent);
Chris@147 424 m_lastFillExtent = fillExtent;
Chris@147 425 }
Chris@147 426 } else {
Chris@236 427 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 428 cerr << "WaveFileModel::fillTimerTimedOut: no thread" << std::endl;
Chris@236 429 #endif
Chris@147 430 emit modelChanged();
Chris@147 431 }
Chris@147 432 }
Chris@147 433
Chris@147 434 void
Chris@147 435 WaveFileModel::cacheFilled()
Chris@147 436 {
Chris@147 437 m_mutex.lock();
Chris@147 438 delete m_fillThread;
Chris@147 439 m_fillThread = 0;
Chris@147 440 delete m_updateTimer;
Chris@147 441 m_updateTimer = 0;
Chris@147 442 m_mutex.unlock();
Chris@147 443 emit modelChanged();
Chris@236 444 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 445 cerr << "WaveFileModel::cacheFilled" << endl;
Chris@236 446 #endif
Chris@175 447 }
Chris@175 448
Chris@175 449 void
Chris@147 450 WaveFileModel::RangeCacheFillThread::run()
Chris@147 451 {
Chris@147 452 size_t cacheBlockSize[2];
Chris@179 453 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
Chris@179 454 cacheBlockSize[1] = ((unsigned int)((1 << m_model.m_zoomConstraint.getMinCachePower()) *
Chris@147 455 sqrt(2) + 0.01));
Chris@147 456
Chris@147 457 size_t frame = 0;
Chris@147 458 size_t readBlockSize = 16384;
Chris@147 459 SampleBlock block;
Chris@147 460
Chris@147 461 if (!m_model.isOK()) return;
Chris@147 462
Chris@147 463 size_t channels = m_model.getChannelCount();
Chris@187 464 bool updating = m_model.m_reader->isUpdating();
Chris@187 465
Chris@187 466 if (updating) {
Chris@187 467 while (channels == 0 && !m_model.m_exiting) {
Chris@188 468 // std::cerr << "WaveFileModel::fill: Waiting for channels..." << std::endl;
Chris@187 469 sleep(1);
Chris@187 470 channels = m_model.getChannelCount();
Chris@187 471 }
Chris@187 472 }
Chris@147 473
Chris@147 474 Range *range = new Range[2 * channels];
Chris@147 475 size_t count[2];
Chris@147 476 count[0] = count[1] = 0;
Chris@176 477
Chris@176 478 bool first = true;
Chris@176 479
Chris@176 480 while (first || updating) {
Chris@176 481
Chris@176 482 updating = m_model.m_reader->isUpdating();
Chris@187 483 m_frameCount = m_model.getFrameCount();
Chris@175 484
Chris@188 485 // std::cerr << "WaveFileModel::fill: frame = " << frame << ", count = " << m_frameCount << std::endl;
Chris@147 486
Chris@176 487 while (frame < m_frameCount) {
Chris@147 488
Chris@176 489 if (updating && (frame + readBlockSize > m_frameCount)) break;
Chris@176 490
Chris@176 491 m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block);
Chris@176 492
Chris@176 493 for (size_t i = 0; i < readBlockSize; ++i) {
Chris@147 494
Chris@232 495 if (channels * i + channels > block.size()) break;
Chris@232 496
Chris@176 497 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@147 498
Chris@176 499 size_t index = channels * i + ch;
Chris@176 500 float sample = block[index];
Chris@176 501
Chris@232 502 for (size_t ct = 0; ct < 2; ++ct) { // cache type
Chris@176 503
Chris@176 504 size_t rangeIndex = ch * 2 + ct;
Chris@176 505
Chris@176 506 if (sample > range[rangeIndex].max || count[ct] == 0) {
Chris@176 507 range[rangeIndex].max = sample;
Chris@176 508 }
Chris@176 509 if (sample < range[rangeIndex].min || count[ct] == 0) {
Chris@176 510 range[rangeIndex].min = sample;
Chris@176 511 }
Chris@176 512 range[rangeIndex].absmean += fabsf(sample);
Chris@176 513 }
Chris@176 514 }
Chris@147 515
Chris@176 516 QMutexLocker locker(&m_model.m_mutex);
Chris@232 517
Chris@147 518 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 519
Chris@176 520 if (++count[ct] == cacheBlockSize[ct]) {
Chris@232 521
Chris@176 522 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@176 523 size_t rangeIndex = ch * 2 + ct;
Chris@176 524 range[rangeIndex].absmean /= count[ct];
Chris@176 525 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@176 526 range[rangeIndex] = Range();
Chris@176 527 }
Chris@232 528
Chris@176 529 count[ct] = 0;
Chris@176 530 }
Chris@176 531 }
Chris@147 532
Chris@176 533 ++frame;
Chris@147 534 }
Chris@147 535
Chris@176 536 if (m_model.m_exiting) break;
Chris@176 537
Chris@176 538 m_fillExtent = frame;
Chris@147 539 }
Chris@147 540
Chris@176 541 first = false;
Chris@177 542 if (m_model.m_exiting) break;
Chris@187 543 if (updating) {
Chris@187 544 sleep(1);
Chris@187 545 }
Chris@147 546 }
Chris@147 547
Chris@177 548 if (!m_model.m_exiting) {
Chris@177 549
Chris@177 550 QMutexLocker locker(&m_model.m_mutex);
Chris@232 551
Chris@177 552 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 553
Chris@177 554 if (count[ct] > 0) {
Chris@232 555
Chris@177 556 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@177 557 size_t rangeIndex = ch * 2 + ct;
Chris@177 558 range[rangeIndex].absmean /= count[ct];
Chris@177 559 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@177 560 range[rangeIndex] = Range();
Chris@177 561 }
Chris@232 562
Chris@177 563 count[ct] = 0;
Chris@147 564 }
Chris@177 565
Chris@177 566 const Range &rr = *m_model.m_cache[ct].begin();
Chris@177 567 MUNLOCK(&rr, m_model.m_cache[ct].capacity() * sizeof(Range));
Chris@147 568 }
Chris@147 569 }
Chris@147 570
Chris@147 571 delete[] range;
Chris@147 572
Chris@175 573 m_fillExtent = m_frameCount;
Chris@236 574
Chris@236 575 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 576 for (size_t ct = 0; ct < 2; ++ct) {
Chris@236 577 cerr << "Cache type " << ct << " now contains " << m_model.m_cache[ct].size() << " ranges" << endl;
Chris@236 578 }
Chris@236 579 #endif
Chris@147 580 }
Chris@147 581
Chris@163 582 void
Chris@163 583 WaveFileModel::toXml(QTextStream &out,
Chris@163 584 QString indent,
Chris@163 585 QString extraAttributes) const
Chris@163 586 {
Chris@163 587 Model::toXml(out, indent,
Chris@163 588 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@163 589 .arg(m_path).arg(extraAttributes));
Chris@163 590 }
Chris@163 591
Chris@147 592 QString
Chris@147 593 WaveFileModel::toXmlString(QString indent,
Chris@147 594 QString extraAttributes) const
Chris@147 595 {
Chris@147 596 return Model::toXmlString(indent,
Chris@147 597 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@147 598 .arg(m_path).arg(extraAttributes));
Chris@147 599 }
Chris@147 600