annotate data/model/WaveFileModel.cpp @ 316:3a6725f285d6

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