annotate data/model/WaveFileModel.cpp @ 295:a2dc34ce146a

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