annotate data/model/WaveFileModel.cpp @ 299:576be0d0d218

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents c022976d18e8
children 5877d68815c7
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@297 41 WaveFileModel::WaveFileModel(QString path, size_t targetRate) :
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@297 49 m_reader = AudioFileReaderFactory::createReader(path, targetRate);
Chris@297 50 if (m_reader) std::cerr << "WaveFileModel::WaveFileModel: reader rate: " << m_reader->getSampleRate() << std::endl;
Chris@292 51 if (m_reader) setObjectName(m_reader->getTitle());
Chris@271 52 if (objectName() == "") setObjectName(QFileInfo(path).fileName());
Chris@175 53 if (isOK()) fillCache();
Chris@175 54 }
Chris@175 55
Chris@297 56 WaveFileModel::WaveFileModel(QString path, QString originalLocation, size_t targetRate) :
Chris@211 57 m_path(originalLocation),
Chris@211 58 m_myReader(true),
Chris@211 59 m_fillThread(0),
Chris@211 60 m_updateTimer(0),
Chris@211 61 m_lastFillExtent(0),
Chris@211 62 m_exiting(false)
Chris@211 63 {
Chris@297 64 m_reader = AudioFileReaderFactory::createReader(path, targetRate);
Chris@297 65 if (m_reader) std::cerr << "WaveFileModel::WaveFileModel: reader rate: " << m_reader->getSampleRate() << std::endl;
Chris@292 66 if (m_reader) setObjectName(m_reader->getTitle());
Chris@271 67 if (objectName() == "") setObjectName(QFileInfo(originalLocation).fileName());
Chris@211 68 if (isOK()) fillCache();
Chris@211 69 }
Chris@211 70
Chris@175 71 WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) :
Chris@175 72 m_path(path),
Chris@175 73 m_myReader(false),
Chris@175 74 m_fillThread(0),
Chris@175 75 m_updateTimer(0),
Chris@175 76 m_lastFillExtent(0),
Chris@175 77 m_exiting(false)
Chris@175 78 {
Chris@175 79 m_reader = reader;
Chris@292 80 if (m_reader) setObjectName(m_reader->getTitle());
Chris@271 81 if (objectName() == "") setObjectName(QFileInfo(path).fileName());
Chris@187 82 fillCache();
Chris@147 83 }
Chris@147 84
Chris@147 85 WaveFileModel::~WaveFileModel()
Chris@147 86 {
Chris@147 87 m_exiting = true;
Chris@147 88 if (m_fillThread) m_fillThread->wait();
Chris@175 89 if (m_myReader) delete m_reader;
Chris@147 90 m_reader = 0;
Chris@147 91 }
Chris@147 92
Chris@147 93 bool
Chris@147 94 WaveFileModel::isOK() const
Chris@147 95 {
Chris@147 96 return m_reader && m_reader->isOK();
Chris@147 97 }
Chris@147 98
Chris@147 99 bool
Chris@147 100 WaveFileModel::isReady(int *completion) const
Chris@147 101 {
Chris@147 102 bool ready = (isOK() && (m_fillThread == 0));
Chris@147 103 double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
Chris@266 104 static int prevCompletion = 0;
Chris@265 105 if (completion) {
Chris@265 106 *completion = int(c * 100.0 + 0.01);
Chris@265 107 if (m_reader) {
Chris@265 108 int decodeCompletion = m_reader->getDecodeCompletion();
Chris@266 109 if (decodeCompletion < 90) *completion = decodeCompletion;
Chris@266 110 else *completion = std::min(*completion, decodeCompletion);
Chris@265 111 }
Chris@266 112 if (*completion != 0 &&
Chris@266 113 *completion != 100 &&
Chris@266 114 prevCompletion != 0 &&
Chris@266 115 prevCompletion > *completion) {
Chris@266 116 // just to avoid completion going backwards
Chris@266 117 *completion = prevCompletion;
Chris@266 118 }
Chris@266 119 prevCompletion = *completion;
Chris@265 120 }
Chris@236 121 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 122 std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl;
Chris@236 123 #endif
Chris@147 124 return ready;
Chris@147 125 }
Chris@147 126
Chris@147 127 Model *
Chris@147 128 WaveFileModel::clone() const
Chris@147 129 {
Chris@147 130 WaveFileModel *model = new WaveFileModel(m_path);
Chris@147 131 return model;
Chris@147 132 }
Chris@147 133
Chris@147 134 size_t
Chris@147 135 WaveFileModel::getFrameCount() const
Chris@147 136 {
Chris@147 137 if (!m_reader) return 0;
Chris@147 138 return m_reader->getFrameCount();
Chris@147 139 }
Chris@147 140
Chris@147 141 size_t
Chris@147 142 WaveFileModel::getChannelCount() const
Chris@147 143 {
Chris@147 144 if (!m_reader) return 0;
Chris@147 145 return m_reader->getChannelCount();
Chris@147 146 }
Chris@147 147
Chris@147 148 size_t
Chris@147 149 WaveFileModel::getSampleRate() const
Chris@147 150 {
Chris@147 151 if (!m_reader) return 0;
Chris@147 152 return m_reader->getSampleRate();
Chris@147 153 }
Chris@147 154
Chris@147 155 size_t
Chris@297 156 WaveFileModel::getNativeRate() const
Chris@297 157 {
Chris@297 158 if (!m_reader) return 0;
Chris@297 159 size_t rate = m_reader->getNativeRate();
Chris@297 160 if (rate == 0) rate = getSampleRate();
Chris@297 161 return rate;
Chris@297 162 }
Chris@297 163
Chris@297 164 size_t
Chris@147 165 WaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@147 166 float *buffer) const
Chris@147 167 {
Chris@147 168 // Always read these directly from the file.
Chris@147 169 // This is used for e.g. audio playback.
Chris@147 170 // Could be much more efficient (although compiler optimisation will help)
Chris@147 171
Chris@147 172 if (end < start) {
Chris@147 173 std::cerr << "ERROR: WaveFileModel::getValues[float]: end < start ("
Chris@147 174 << end << " < " << start << ")" << std::endl;
Chris@147 175 assert(end >= start);
Chris@147 176 }
Chris@147 177
Chris@147 178 if (!m_reader || !m_reader->isOK()) return 0;
Chris@147 179
Chris@236 180 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@258 181 // std::cerr << "WaveFileModel::getValues(" << channel << ", "
Chris@258 182 // << start << ", " << end << "): calling reader" << std::endl;
Chris@236 183 #endif
Chris@175 184
Chris@290 185 SampleBlock frames;
Chris@147 186 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 187
Chris@147 188 size_t i = 0;
Chris@147 189
Chris@147 190 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 191 if (channel == -1) {
Chris@147 192 ch0 = 0;
Chris@147 193 ch1 = channels - 1;
Chris@147 194 }
Chris@147 195
Chris@147 196 while (i < end - start) {
Chris@147 197
Chris@147 198 buffer[i] = 0.0;
Chris@147 199
Chris@147 200 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 201
Chris@147 202 size_t index = i * channels + ch;
Chris@147 203 if (index >= frames.size()) break;
Chris@147 204
Chris@147 205 float sample = frames[index];
Chris@147 206 buffer[i] += sample;
Chris@147 207 }
Chris@147 208
Chris@147 209 ++i;
Chris@147 210 }
Chris@147 211
Chris@147 212 return i;
Chris@147 213 }
Chris@147 214
Chris@147 215 size_t
Chris@147 216 WaveFileModel::getValues(int channel, size_t start, size_t end,
Chris@147 217 double *buffer) const
Chris@147 218 {
Chris@147 219 if (end < start) {
Chris@147 220 std::cerr << "ERROR: WaveFileModel::getValues[double]: end < start ("
Chris@147 221 << end << " < " << start << ")" << std::endl;
Chris@147 222 assert(end >= start);
Chris@147 223 }
Chris@147 224
Chris@147 225 if (!m_reader || !m_reader->isOK()) return 0;
Chris@147 226
Chris@290 227 SampleBlock frames;
Chris@147 228 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 229
Chris@147 230 size_t i = 0;
Chris@147 231
Chris@147 232 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 233 if (channel == -1) {
Chris@147 234 ch0 = 0;
Chris@147 235 ch1 = channels - 1;
Chris@147 236 }
Chris@147 237
Chris@147 238 while (i < end - start) {
Chris@147 239
Chris@147 240 buffer[i] = 0.0;
Chris@147 241
Chris@147 242 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 243
Chris@147 244 size_t index = i * channels + ch;
Chris@147 245 if (index >= frames.size()) break;
Chris@147 246
Chris@147 247 float sample = frames[index];
Chris@147 248 buffer[i] += sample;
Chris@147 249 }
Chris@147 250
Chris@147 251 ++i;
Chris@147 252 }
Chris@147 253
Chris@147 254 return i;
Chris@147 255 }
Chris@147 256
Chris@225 257 void
Chris@147 258 WaveFileModel::getRanges(size_t channel, size_t start, size_t end,
Chris@225 259 RangeBlock &ranges, size_t &blockSize) const
Chris@147 260 {
Chris@225 261 ranges.clear();
Chris@225 262 if (!isOK()) return;
Chris@147 263
Chris@147 264 if (end <= start) {
Chris@147 265 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRanges (end = " << end << ", start = " << start << ", blocksize = " << blockSize << ")" << std::endl;
Chris@225 266 return;
Chris@147 267 }
Chris@147 268
Chris@147 269 int cacheType = 0;
Chris@179 270 int power = m_zoomConstraint.getMinCachePower();
Chris@179 271 blockSize = m_zoomConstraint.getNearestBlockSize
Chris@179 272 (blockSize, cacheType, power, ZoomConstraint::RoundUp);
Chris@147 273
Chris@147 274 size_t channels = getChannelCount();
Chris@147 275
Chris@147 276 if (cacheType != 0 && cacheType != 1) {
Chris@147 277
Chris@147 278 // We need to read directly from the file. We haven't got
Chris@147 279 // this cached. Hope the requested area is small. This is
Chris@147 280 // not optimal -- we'll end up reading the same frames twice
Chris@147 281 // for stereo files, in two separate calls to this method.
Chris@147 282 // We could fairly trivially handle this for most cases that
Chris@147 283 // matter by putting a single cache in getInterleavedFrames
Chris@147 284 // for short queries.
Chris@147 285
Chris@290 286 SampleBlock frames;
Chris@147 287 m_reader->getInterleavedFrames(start, end - start, frames);
Chris@147 288 float max = 0.0, min = 0.0, total = 0.0;
Chris@147 289 size_t i = 0, count = 0;
Chris@147 290
Chris@147 291 while (i < end - start) {
Chris@147 292
Chris@147 293 size_t index = i * channels + channel;
Chris@147 294 if (index >= frames.size()) break;
Chris@147 295
Chris@147 296 float sample = frames[index];
Chris@147 297 if (sample > max || count == 0) max = sample;
Chris@147 298 if (sample < min || count == 0) min = sample;
Chris@147 299 total += fabsf(sample);
Chris@147 300
Chris@147 301 ++i;
Chris@147 302 ++count;
Chris@147 303
Chris@147 304 if (count == blockSize) {
Chris@147 305 ranges.push_back(Range(min, max, total / count));
Chris@147 306 min = max = total = 0.0f;
Chris@147 307 count = 0;
Chris@147 308 }
Chris@147 309 }
Chris@147 310
Chris@147 311 if (count > 0) {
Chris@147 312 ranges.push_back(Range(min, max, total / count));
Chris@147 313 }
Chris@147 314
Chris@225 315 return;
Chris@147 316
Chris@147 317 } else {
Chris@147 318
Chris@147 319 QMutexLocker locker(&m_mutex);
Chris@147 320
Chris@147 321 const RangeBlock &cache = m_cache[cacheType];
Chris@147 322
Chris@147 323 size_t cacheBlock, div;
Chris@147 324
Chris@147 325 if (cacheType == 0) {
Chris@179 326 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
Chris@147 327 div = (1 << power) / cacheBlock;
Chris@147 328 } else {
Chris@179 329 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01));
Chris@147 330 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock;
Chris@147 331 }
Chris@147 332
Chris@147 333 size_t startIndex = start / cacheBlock;
Chris@147 334 size_t endIndex = end / cacheBlock;
Chris@147 335
Chris@147 336 float max = 0.0, min = 0.0, total = 0.0;
Chris@147 337 size_t i = 0, count = 0;
Chris@147 338
Chris@236 339 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@232 340 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 341 #endif
Chris@147 342
Chris@147 343 for (i = 0; i < endIndex - startIndex; ) {
Chris@147 344
Chris@147 345 size_t index = (i + startIndex) * channels + channel;
Chris@147 346 if (index >= cache.size()) break;
Chris@147 347
Chris@147 348 const Range &range = cache[index];
Chris@147 349 if (range.max > max || count == 0) max = range.max;
Chris@147 350 if (range.min < min || count == 0) min = range.min;
Chris@147 351 total += range.absmean;
Chris@147 352
Chris@147 353 ++i;
Chris@147 354 ++count;
Chris@147 355
Chris@147 356 if (count == div) {
Chris@147 357 ranges.push_back(Range(min, max, total / count));
Chris@147 358 min = max = total = 0.0f;
Chris@147 359 count = 0;
Chris@147 360 }
Chris@147 361 }
Chris@147 362
Chris@147 363 if (count > 0) {
Chris@147 364 ranges.push_back(Range(min, max, total / count));
Chris@147 365 }
Chris@147 366 }
Chris@147 367
Chris@236 368 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@232 369 cerr << "returning " << ranges.size() << " ranges" << endl;
Chris@236 370 #endif
Chris@225 371 return;
Chris@147 372 }
Chris@147 373
Chris@147 374 WaveFileModel::Range
Chris@147 375 WaveFileModel::getRange(size_t channel, size_t start, size_t end) const
Chris@147 376 {
Chris@147 377 Range range;
Chris@147 378 if (!isOK()) return range;
Chris@147 379
Chris@147 380 if (end <= start) {
Chris@147 381 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRange (end = " << end << ", start = " << start << ")" << std::endl;
Chris@147 382 return range;
Chris@147 383 }
Chris@147 384
Chris@147 385 size_t blockSize;
Chris@147 386 for (blockSize = 1; blockSize <= end - start; blockSize *= 2);
Chris@147 387 blockSize /= 2;
Chris@147 388
Chris@147 389 bool first = false;
Chris@147 390
Chris@147 391 size_t blockStart = (start / blockSize) * blockSize;
Chris@147 392 size_t blockEnd = (end / blockSize) * blockSize;
Chris@147 393
Chris@147 394 if (blockStart < start) blockStart += blockSize;
Chris@147 395
Chris@147 396 if (blockEnd > blockStart) {
Chris@225 397 RangeBlock ranges;
Chris@225 398 getRanges(channel, blockStart, blockEnd, ranges, blockSize);
Chris@147 399 for (size_t i = 0; i < ranges.size(); ++i) {
Chris@147 400 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
Chris@147 401 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
Chris@147 402 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
Chris@147 403 first = false;
Chris@147 404 }
Chris@147 405 }
Chris@147 406
Chris@147 407 if (blockStart > start) {
Chris@147 408 Range startRange = getRange(channel, start, blockStart);
Chris@147 409 range.min = std::min(range.min, startRange.min);
Chris@147 410 range.max = std::max(range.max, startRange.max);
Chris@147 411 range.absmean = std::min(range.absmean, startRange.absmean);
Chris@147 412 }
Chris@147 413
Chris@147 414 if (blockEnd < end) {
Chris@147 415 Range endRange = getRange(channel, blockEnd, end);
Chris@147 416 range.min = std::min(range.min, endRange.min);
Chris@147 417 range.max = std::max(range.max, endRange.max);
Chris@147 418 range.absmean = std::min(range.absmean, endRange.absmean);
Chris@147 419 }
Chris@147 420
Chris@147 421 return range;
Chris@147 422 }
Chris@147 423
Chris@147 424 void
Chris@147 425 WaveFileModel::fillCache()
Chris@147 426 {
Chris@147 427 m_mutex.lock();
Chris@188 428
Chris@147 429 m_updateTimer = new QTimer(this);
Chris@147 430 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
Chris@147 431 m_updateTimer->start(100);
Chris@188 432
Chris@147 433 m_fillThread = new RangeCacheFillThread(*this);
Chris@147 434 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
Chris@188 435
Chris@147 436 m_mutex.unlock();
Chris@147 437 m_fillThread->start();
Chris@188 438
Chris@236 439 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 440 std::cerr << "WaveFileModel::fillCache: started fill thread" << std::endl;
Chris@236 441 #endif
Chris@147 442 }
Chris@147 443
Chris@147 444 void
Chris@147 445 WaveFileModel::fillTimerTimedOut()
Chris@147 446 {
Chris@147 447 if (m_fillThread) {
Chris@147 448 size_t fillExtent = m_fillThread->getFillExtent();
Chris@236 449 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 450 cerr << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
Chris@236 451 #endif
Chris@147 452 if (fillExtent > m_lastFillExtent) {
Chris@147 453 emit modelChanged(m_lastFillExtent, fillExtent);
Chris@147 454 m_lastFillExtent = fillExtent;
Chris@147 455 }
Chris@147 456 } else {
Chris@236 457 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 458 cerr << "WaveFileModel::fillTimerTimedOut: no thread" << std::endl;
Chris@236 459 #endif
Chris@147 460 emit modelChanged();
Chris@147 461 }
Chris@147 462 }
Chris@147 463
Chris@147 464 void
Chris@147 465 WaveFileModel::cacheFilled()
Chris@147 466 {
Chris@147 467 m_mutex.lock();
Chris@147 468 delete m_fillThread;
Chris@147 469 m_fillThread = 0;
Chris@147 470 delete m_updateTimer;
Chris@147 471 m_updateTimer = 0;
Chris@147 472 m_mutex.unlock();
Chris@267 473 if (getEndFrame() > m_lastFillExtent) {
Chris@267 474 emit modelChanged(m_lastFillExtent, getEndFrame());
Chris@267 475 }
Chris@147 476 emit modelChanged();
Chris@236 477 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 478 cerr << "WaveFileModel::cacheFilled" << endl;
Chris@236 479 #endif
Chris@175 480 }
Chris@175 481
Chris@175 482 void
Chris@147 483 WaveFileModel::RangeCacheFillThread::run()
Chris@147 484 {
Chris@147 485 size_t cacheBlockSize[2];
Chris@179 486 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
Chris@179 487 cacheBlockSize[1] = ((unsigned int)((1 << m_model.m_zoomConstraint.getMinCachePower()) *
Chris@147 488 sqrt(2) + 0.01));
Chris@147 489
Chris@147 490 size_t frame = 0;
Chris@147 491 size_t readBlockSize = 16384;
Chris@290 492 SampleBlock block;
Chris@147 493
Chris@147 494 if (!m_model.isOK()) return;
Chris@147 495
Chris@147 496 size_t channels = m_model.getChannelCount();
Chris@187 497 bool updating = m_model.m_reader->isUpdating();
Chris@187 498
Chris@187 499 if (updating) {
Chris@187 500 while (channels == 0 && !m_model.m_exiting) {
Chris@188 501 // std::cerr << "WaveFileModel::fill: Waiting for channels..." << std::endl;
Chris@187 502 sleep(1);
Chris@187 503 channels = m_model.getChannelCount();
Chris@187 504 }
Chris@187 505 }
Chris@147 506
Chris@147 507 Range *range = new Range[2 * channels];
Chris@147 508 size_t count[2];
Chris@147 509 count[0] = count[1] = 0;
Chris@176 510
Chris@176 511 bool first = true;
Chris@176 512
Chris@176 513 while (first || updating) {
Chris@176 514
Chris@176 515 updating = m_model.m_reader->isUpdating();
Chris@187 516 m_frameCount = m_model.getFrameCount();
Chris@175 517
Chris@188 518 // std::cerr << "WaveFileModel::fill: frame = " << frame << ", count = " << m_frameCount << std::endl;
Chris@147 519
Chris@176 520 while (frame < m_frameCount) {
Chris@147 521
Chris@265 522 // std::cerr << "WaveFileModel::fill inner loop: frame = " << frame << ", count = " << m_frameCount << ", blocksize " << readBlockSize << std::endl;
Chris@265 523
Chris@176 524 if (updating && (frame + readBlockSize > m_frameCount)) break;
Chris@176 525
Chris@176 526 m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block);
Chris@176 527
Chris@265 528 // std::cerr << "block is " << block.size() << std::endl;
Chris@265 529
Chris@176 530 for (size_t i = 0; i < readBlockSize; ++i) {
Chris@147 531
Chris@232 532 if (channels * i + channels > block.size()) break;
Chris@232 533
Chris@176 534 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@147 535
Chris@176 536 size_t index = channels * i + ch;
Chris@176 537 float sample = block[index];
Chris@176 538
Chris@232 539 for (size_t ct = 0; ct < 2; ++ct) { // cache type
Chris@176 540
Chris@176 541 size_t rangeIndex = ch * 2 + ct;
Chris@176 542
Chris@176 543 if (sample > range[rangeIndex].max || count[ct] == 0) {
Chris@176 544 range[rangeIndex].max = sample;
Chris@176 545 }
Chris@176 546 if (sample < range[rangeIndex].min || count[ct] == 0) {
Chris@176 547 range[rangeIndex].min = sample;
Chris@176 548 }
Chris@176 549 range[rangeIndex].absmean += fabsf(sample);
Chris@176 550 }
Chris@176 551 }
Chris@147 552
Chris@176 553 QMutexLocker locker(&m_model.m_mutex);
Chris@232 554
Chris@147 555 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 556
Chris@176 557 if (++count[ct] == cacheBlockSize[ct]) {
Chris@232 558
Chris@176 559 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@176 560 size_t rangeIndex = ch * 2 + ct;
Chris@176 561 range[rangeIndex].absmean /= count[ct];
Chris@176 562 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@176 563 range[rangeIndex] = Range();
Chris@176 564 }
Chris@232 565
Chris@176 566 count[ct] = 0;
Chris@176 567 }
Chris@176 568 }
Chris@147 569
Chris@176 570 ++frame;
Chris@147 571 }
Chris@147 572
Chris@176 573 if (m_model.m_exiting) break;
Chris@176 574
Chris@176 575 m_fillExtent = frame;
Chris@147 576 }
Chris@147 577
Chris@265 578 // std::cerr << "WaveFileModel: inner loop ended" << std::endl;
Chris@265 579
Chris@176 580 first = false;
Chris@177 581 if (m_model.m_exiting) break;
Chris@187 582 if (updating) {
Chris@265 583 // std::cerr << "sleeping..." << std::endl;
Chris@187 584 sleep(1);
Chris@187 585 }
Chris@147 586 }
Chris@147 587
Chris@177 588 if (!m_model.m_exiting) {
Chris@177 589
Chris@177 590 QMutexLocker locker(&m_model.m_mutex);
Chris@232 591
Chris@177 592 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 593
Chris@177 594 if (count[ct] > 0) {
Chris@232 595
Chris@177 596 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@177 597 size_t rangeIndex = ch * 2 + ct;
Chris@177 598 range[rangeIndex].absmean /= count[ct];
Chris@177 599 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@177 600 range[rangeIndex] = Range();
Chris@177 601 }
Chris@232 602
Chris@177 603 count[ct] = 0;
Chris@147 604 }
Chris@177 605
Chris@177 606 const Range &rr = *m_model.m_cache[ct].begin();
Chris@177 607 MUNLOCK(&rr, m_model.m_cache[ct].capacity() * sizeof(Range));
Chris@147 608 }
Chris@147 609 }
Chris@147 610
Chris@147 611 delete[] range;
Chris@147 612
Chris@175 613 m_fillExtent = m_frameCount;
Chris@236 614
Chris@236 615 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 616 for (size_t ct = 0; ct < 2; ++ct) {
Chris@236 617 cerr << "Cache type " << ct << " now contains " << m_model.m_cache[ct].size() << " ranges" << endl;
Chris@236 618 }
Chris@236 619 #endif
Chris@147 620 }
Chris@147 621
Chris@163 622 void
Chris@163 623 WaveFileModel::toXml(QTextStream &out,
Chris@163 624 QString indent,
Chris@163 625 QString extraAttributes) const
Chris@163 626 {
Chris@163 627 Model::toXml(out, indent,
Chris@163 628 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@279 629 .arg(encodeEntities(m_path)).arg(extraAttributes));
Chris@163 630 }
Chris@163 631
Chris@147 632