annotate data/model/WaveFileModel.cpp @ 360:ac300d385ab2

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