annotate data/model/WaveFileModel.cpp @ 335:02d2ad95ea52 spectrogram-cache-rejig

* Get storage advice for each cache in an FFT data server. Allows us to be more confident about the actual memory situation and cut over from memory to disc part way through an FFT calculation if necessary. StorageAdviser is now a bit too optimistic though (it's too keen to allocate large numbers of small blocks in memory).
author Chris Cannam
date Tue, 13 Nov 2007 13:54:10 +0000
parents 1afaf98dbf11
children 700cd3350391 6f6ab834449d
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@333 176
Chris@297 177 size_t
Chris@300 178 WaveFileModel::getData(int channel, size_t start, size_t count,
Chris@300 179 float *buffer) const
Chris@147 180 {
Chris@147 181 // Always read these directly from the file.
Chris@147 182 // This is used for e.g. audio playback.
Chris@147 183 // Could be much more efficient (although compiler optimisation will help)
Chris@147 184
Chris@300 185 if (start > m_startFrame) {
Chris@300 186 start -= m_startFrame;
Chris@300 187 } else {
Chris@300 188 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
Chris@300 189 if (count <= m_startFrame - start) {
Chris@300 190 return 0;
Chris@300 191 } else {
Chris@300 192 count -= (m_startFrame - start);
Chris@300 193 start = 0;
Chris@300 194 }
Chris@147 195 }
Chris@147 196
Chris@300 197 if (!m_reader || !m_reader->isOK() || count == 0) {
Chris@300 198 for (size_t i = 0; i < count; ++i) buffer[i] = 0.f;
Chris@300 199 return 0;
Chris@300 200 }
Chris@147 201
Chris@236 202 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@258 203 // std::cerr << "WaveFileModel::getValues(" << channel << ", "
Chris@258 204 // << start << ", " << end << "): calling reader" << std::endl;
Chris@236 205 #endif
Chris@175 206
Chris@290 207 SampleBlock frames;
Chris@300 208 m_reader->getInterleavedFrames(start, count, frames);
Chris@147 209
Chris@147 210 size_t i = 0;
Chris@147 211
Chris@147 212 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 213 if (channel == -1) {
Chris@147 214 ch0 = 0;
Chris@147 215 ch1 = channels - 1;
Chris@147 216 }
Chris@147 217
Chris@300 218 while (i < count) {
Chris@147 219
Chris@147 220 buffer[i] = 0.0;
Chris@147 221
Chris@147 222 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 223
Chris@147 224 size_t index = i * channels + ch;
Chris@147 225 if (index >= frames.size()) break;
Chris@147 226
Chris@147 227 float sample = frames[index];
Chris@147 228 buffer[i] += sample;
Chris@147 229 }
Chris@147 230
Chris@147 231 ++i;
Chris@147 232 }
Chris@147 233
Chris@147 234 return i;
Chris@147 235 }
Chris@147 236
Chris@147 237 size_t
Chris@300 238 WaveFileModel::getData(int channel, size_t start, size_t count,
Chris@300 239 double *buffer) const
Chris@147 240 {
Chris@300 241 if (start > m_startFrame) {
Chris@300 242 start -= m_startFrame;
Chris@300 243 } else {
Chris@300 244 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
Chris@300 245 if (count <= m_startFrame - start) {
Chris@300 246 return 0;
Chris@300 247 } else {
Chris@300 248 count -= (m_startFrame - start);
Chris@300 249 start = 0;
Chris@300 250 }
Chris@147 251 }
Chris@147 252
Chris@300 253 if (!m_reader || !m_reader->isOK() || count == 0) {
Chris@300 254 for (size_t i = 0; i < count; ++i) buffer[i] = 0.0;
Chris@300 255 return 0;
Chris@300 256 }
Chris@147 257
Chris@290 258 SampleBlock frames;
Chris@300 259 m_reader->getInterleavedFrames(start, count, frames);
Chris@147 260
Chris@147 261 size_t i = 0;
Chris@147 262
Chris@147 263 int ch0 = channel, ch1 = channel, channels = getChannelCount();
Chris@147 264 if (channel == -1) {
Chris@147 265 ch0 = 0;
Chris@147 266 ch1 = channels - 1;
Chris@147 267 }
Chris@147 268
Chris@300 269 while (i < count) {
Chris@147 270
Chris@147 271 buffer[i] = 0.0;
Chris@147 272
Chris@147 273 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 274
Chris@147 275 size_t index = i * channels + ch;
Chris@147 276 if (index >= frames.size()) break;
Chris@147 277
Chris@147 278 float sample = frames[index];
Chris@147 279 buffer[i] += sample;
Chris@147 280 }
Chris@147 281
Chris@147 282 ++i;
Chris@147 283 }
Chris@147 284
Chris@147 285 return i;
Chris@147 286 }
Chris@147 287
Chris@225 288 void
Chris@300 289 WaveFileModel::getSummaries(size_t channel, size_t start, size_t count,
Chris@300 290 RangeBlock &ranges, size_t &blockSize) const
Chris@147 291 {
Chris@225 292 ranges.clear();
Chris@225 293 if (!isOK()) return;
Chris@147 294
Chris@300 295 if (start > m_startFrame) start -= m_startFrame;
Chris@300 296 else if (count <= m_startFrame - start) return;
Chris@300 297 else {
Chris@300 298 count -= (m_startFrame - start);
Chris@300 299 start = 0;
Chris@147 300 }
Chris@147 301
Chris@147 302 int cacheType = 0;
Chris@179 303 int power = m_zoomConstraint.getMinCachePower();
Chris@179 304 blockSize = m_zoomConstraint.getNearestBlockSize
Chris@179 305 (blockSize, cacheType, power, ZoomConstraint::RoundUp);
Chris@147 306
Chris@147 307 size_t channels = getChannelCount();
Chris@147 308
Chris@147 309 if (cacheType != 0 && cacheType != 1) {
Chris@147 310
Chris@147 311 // We need to read directly from the file. We haven't got
Chris@147 312 // this cached. Hope the requested area is small. This is
Chris@147 313 // not optimal -- we'll end up reading the same frames twice
Chris@147 314 // for stereo files, in two separate calls to this method.
Chris@147 315 // We could fairly trivially handle this for most cases that
Chris@147 316 // matter by putting a single cache in getInterleavedFrames
Chris@147 317 // for short queries.
Chris@147 318
Chris@290 319 SampleBlock frames;
Chris@300 320 m_reader->getInterleavedFrames(start, count, frames);
Chris@147 321 float max = 0.0, min = 0.0, total = 0.0;
Chris@300 322 size_t i = 0, got = 0;
Chris@147 323
Chris@300 324 while (i < count) {
Chris@147 325
Chris@147 326 size_t index = i * channels + channel;
Chris@147 327 if (index >= frames.size()) break;
Chris@147 328
Chris@147 329 float sample = frames[index];
Chris@300 330 if (sample > max || got == 0) max = sample;
Chris@300 331 if (sample < min || got == 0) min = sample;
Chris@147 332 total += fabsf(sample);
Chris@147 333
Chris@147 334 ++i;
Chris@300 335 ++got;
Chris@147 336
Chris@300 337 if (got == blockSize) {
Chris@300 338 ranges.push_back(Range(min, max, total / got));
Chris@147 339 min = max = total = 0.0f;
Chris@300 340 got = 0;
Chris@147 341 }
Chris@147 342 }
Chris@147 343
Chris@300 344 if (got > 0) {
Chris@300 345 ranges.push_back(Range(min, max, total / got));
Chris@147 346 }
Chris@147 347
Chris@225 348 return;
Chris@147 349
Chris@147 350 } else {
Chris@147 351
Chris@147 352 QMutexLocker locker(&m_mutex);
Chris@147 353
Chris@147 354 const RangeBlock &cache = m_cache[cacheType];
Chris@147 355
Chris@147 356 size_t cacheBlock, div;
Chris@147 357
Chris@147 358 if (cacheType == 0) {
Chris@179 359 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
Chris@147 360 div = (1 << power) / cacheBlock;
Chris@147 361 } else {
Chris@179 362 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2) + 0.01));
Chris@147 363 div = ((unsigned int)((1 << power) * sqrt(2) + 0.01)) / cacheBlock;
Chris@147 364 }
Chris@147 365
Chris@147 366 size_t startIndex = start / cacheBlock;
Chris@300 367 size_t endIndex = (start + count) / cacheBlock;
Chris@147 368
Chris@147 369 float max = 0.0, min = 0.0, total = 0.0;
Chris@300 370 size_t i = 0, got = 0;
Chris@147 371
Chris@236 372 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@300 373 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 374 #endif
Chris@147 375
Chris@300 376 for (i = 0; i <= endIndex - startIndex; ) {
Chris@147 377
Chris@147 378 size_t index = (i + startIndex) * channels + channel;
Chris@147 379 if (index >= cache.size()) break;
Chris@147 380
Chris@147 381 const Range &range = cache[index];
Chris@300 382 if (range.max > max || got == 0) max = range.max;
Chris@300 383 if (range.min < min || got == 0) min = range.min;
Chris@147 384 total += range.absmean;
Chris@147 385
Chris@147 386 ++i;
Chris@300 387 ++got;
Chris@147 388
Chris@300 389 if (got == div) {
Chris@300 390 ranges.push_back(Range(min, max, total / got));
Chris@147 391 min = max = total = 0.0f;
Chris@300 392 got = 0;
Chris@147 393 }
Chris@147 394 }
Chris@147 395
Chris@300 396 if (got > 0) {
Chris@300 397 ranges.push_back(Range(min, max, total / got));
Chris@147 398 }
Chris@147 399 }
Chris@147 400
Chris@236 401 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@232 402 cerr << "returning " << ranges.size() << " ranges" << endl;
Chris@236 403 #endif
Chris@225 404 return;
Chris@147 405 }
Chris@147 406
Chris@147 407 WaveFileModel::Range
Chris@300 408 WaveFileModel::getSummary(size_t channel, size_t start, size_t count) const
Chris@147 409 {
Chris@147 410 Range range;
Chris@147 411 if (!isOK()) return range;
Chris@147 412
Chris@300 413 if (start > m_startFrame) start -= m_startFrame;
Chris@300 414 else if (count <= m_startFrame - start) return range;
Chris@300 415 else {
Chris@300 416 count -= (m_startFrame - start);
Chris@300 417 start = 0;
Chris@147 418 }
Chris@147 419
Chris@147 420 size_t blockSize;
Chris@300 421 for (blockSize = 1; blockSize <= count; blockSize *= 2);
Chris@300 422 if (blockSize > 1) blockSize /= 2;
Chris@147 423
Chris@147 424 bool first = false;
Chris@147 425
Chris@147 426 size_t blockStart = (start / blockSize) * blockSize;
Chris@300 427 size_t blockEnd = ((start + count) / blockSize) * blockSize;
Chris@147 428
Chris@147 429 if (blockStart < start) blockStart += blockSize;
Chris@147 430
Chris@147 431 if (blockEnd > blockStart) {
Chris@225 432 RangeBlock ranges;
Chris@300 433 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
Chris@147 434 for (size_t i = 0; i < ranges.size(); ++i) {
Chris@147 435 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
Chris@147 436 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
Chris@147 437 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
Chris@147 438 first = false;
Chris@147 439 }
Chris@147 440 }
Chris@147 441
Chris@147 442 if (blockStart > start) {
Chris@300 443 Range startRange = getSummary(channel, start, blockStart - start);
Chris@147 444 range.min = std::min(range.min, startRange.min);
Chris@147 445 range.max = std::max(range.max, startRange.max);
Chris@147 446 range.absmean = std::min(range.absmean, startRange.absmean);
Chris@147 447 }
Chris@147 448
Chris@300 449 if (blockEnd < start + count) {
Chris@300 450 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
Chris@147 451 range.min = std::min(range.min, endRange.min);
Chris@147 452 range.max = std::max(range.max, endRange.max);
Chris@147 453 range.absmean = std::min(range.absmean, endRange.absmean);
Chris@147 454 }
Chris@147 455
Chris@147 456 return range;
Chris@147 457 }
Chris@147 458
Chris@147 459 void
Chris@147 460 WaveFileModel::fillCache()
Chris@147 461 {
Chris@147 462 m_mutex.lock();
Chris@188 463
Chris@147 464 m_updateTimer = new QTimer(this);
Chris@147 465 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
Chris@147 466 m_updateTimer->start(100);
Chris@188 467
Chris@147 468 m_fillThread = new RangeCacheFillThread(*this);
Chris@147 469 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
Chris@188 470
Chris@147 471 m_mutex.unlock();
Chris@147 472 m_fillThread->start();
Chris@188 473
Chris@236 474 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 475 std::cerr << "WaveFileModel::fillCache: started fill thread" << std::endl;
Chris@236 476 #endif
Chris@147 477 }
Chris@147 478
Chris@147 479 void
Chris@147 480 WaveFileModel::fillTimerTimedOut()
Chris@147 481 {
Chris@147 482 if (m_fillThread) {
Chris@147 483 size_t fillExtent = m_fillThread->getFillExtent();
Chris@236 484 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 485 cerr << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
Chris@236 486 #endif
Chris@147 487 if (fillExtent > m_lastFillExtent) {
Chris@147 488 emit modelChanged(m_lastFillExtent, fillExtent);
Chris@147 489 m_lastFillExtent = fillExtent;
Chris@147 490 }
Chris@147 491 } else {
Chris@236 492 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 493 cerr << "WaveFileModel::fillTimerTimedOut: no thread" << std::endl;
Chris@236 494 #endif
Chris@147 495 emit modelChanged();
Chris@147 496 }
Chris@147 497 }
Chris@147 498
Chris@147 499 void
Chris@147 500 WaveFileModel::cacheFilled()
Chris@147 501 {
Chris@147 502 m_mutex.lock();
Chris@147 503 delete m_fillThread;
Chris@147 504 m_fillThread = 0;
Chris@147 505 delete m_updateTimer;
Chris@147 506 m_updateTimer = 0;
Chris@147 507 m_mutex.unlock();
Chris@267 508 if (getEndFrame() > m_lastFillExtent) {
Chris@267 509 emit modelChanged(m_lastFillExtent, getEndFrame());
Chris@267 510 }
Chris@147 511 emit modelChanged();
Chris@236 512 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 513 cerr << "WaveFileModel::cacheFilled" << endl;
Chris@236 514 #endif
Chris@175 515 }
Chris@175 516
Chris@175 517 void
Chris@147 518 WaveFileModel::RangeCacheFillThread::run()
Chris@147 519 {
Chris@147 520 size_t cacheBlockSize[2];
Chris@179 521 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
Chris@179 522 cacheBlockSize[1] = ((unsigned int)((1 << m_model.m_zoomConstraint.getMinCachePower()) *
Chris@147 523 sqrt(2) + 0.01));
Chris@147 524
Chris@147 525 size_t frame = 0;
Chris@147 526 size_t readBlockSize = 16384;
Chris@290 527 SampleBlock block;
Chris@147 528
Chris@147 529 if (!m_model.isOK()) return;
Chris@147 530
Chris@147 531 size_t channels = m_model.getChannelCount();
Chris@187 532 bool updating = m_model.m_reader->isUpdating();
Chris@187 533
Chris@187 534 if (updating) {
Chris@187 535 while (channels == 0 && !m_model.m_exiting) {
Chris@188 536 // std::cerr << "WaveFileModel::fill: Waiting for channels..." << std::endl;
Chris@187 537 sleep(1);
Chris@187 538 channels = m_model.getChannelCount();
Chris@187 539 }
Chris@187 540 }
Chris@147 541
Chris@147 542 Range *range = new Range[2 * channels];
Chris@147 543 size_t count[2];
Chris@147 544 count[0] = count[1] = 0;
Chris@176 545
Chris@176 546 bool first = true;
Chris@176 547
Chris@176 548 while (first || updating) {
Chris@176 549
Chris@176 550 updating = m_model.m_reader->isUpdating();
Chris@187 551 m_frameCount = m_model.getFrameCount();
Chris@175 552
Chris@188 553 // std::cerr << "WaveFileModel::fill: frame = " << frame << ", count = " << m_frameCount << std::endl;
Chris@147 554
Chris@176 555 while (frame < m_frameCount) {
Chris@147 556
Chris@265 557 // std::cerr << "WaveFileModel::fill inner loop: frame = " << frame << ", count = " << m_frameCount << ", blocksize " << readBlockSize << std::endl;
Chris@265 558
Chris@176 559 if (updating && (frame + readBlockSize > m_frameCount)) break;
Chris@176 560
Chris@176 561 m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block);
Chris@176 562
Chris@265 563 // std::cerr << "block is " << block.size() << std::endl;
Chris@265 564
Chris@176 565 for (size_t i = 0; i < readBlockSize; ++i) {
Chris@147 566
Chris@232 567 if (channels * i + channels > block.size()) break;
Chris@232 568
Chris@176 569 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@147 570
Chris@176 571 size_t index = channels * i + ch;
Chris@176 572 float sample = block[index];
Chris@176 573
Chris@232 574 for (size_t ct = 0; ct < 2; ++ct) { // cache type
Chris@176 575
Chris@176 576 size_t rangeIndex = ch * 2 + ct;
Chris@176 577
Chris@176 578 if (sample > range[rangeIndex].max || count[ct] == 0) {
Chris@176 579 range[rangeIndex].max = sample;
Chris@176 580 }
Chris@176 581 if (sample < range[rangeIndex].min || count[ct] == 0) {
Chris@176 582 range[rangeIndex].min = sample;
Chris@176 583 }
Chris@176 584 range[rangeIndex].absmean += fabsf(sample);
Chris@176 585 }
Chris@176 586 }
Chris@147 587
Chris@176 588 QMutexLocker locker(&m_model.m_mutex);
Chris@232 589
Chris@147 590 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 591
Chris@176 592 if (++count[ct] == cacheBlockSize[ct]) {
Chris@232 593
Chris@176 594 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@176 595 size_t rangeIndex = ch * 2 + ct;
Chris@176 596 range[rangeIndex].absmean /= count[ct];
Chris@176 597 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@176 598 range[rangeIndex] = Range();
Chris@176 599 }
Chris@232 600
Chris@176 601 count[ct] = 0;
Chris@176 602 }
Chris@176 603 }
Chris@147 604
Chris@176 605 ++frame;
Chris@147 606 }
Chris@147 607
Chris@176 608 if (m_model.m_exiting) break;
Chris@176 609
Chris@176 610 m_fillExtent = frame;
Chris@147 611 }
Chris@147 612
Chris@265 613 // std::cerr << "WaveFileModel: inner loop ended" << std::endl;
Chris@265 614
Chris@176 615 first = false;
Chris@177 616 if (m_model.m_exiting) break;
Chris@187 617 if (updating) {
Chris@265 618 // std::cerr << "sleeping..." << std::endl;
Chris@187 619 sleep(1);
Chris@187 620 }
Chris@147 621 }
Chris@147 622
Chris@177 623 if (!m_model.m_exiting) {
Chris@177 624
Chris@177 625 QMutexLocker locker(&m_model.m_mutex);
Chris@232 626
Chris@177 627 for (size_t ct = 0; ct < 2; ++ct) {
Chris@232 628
Chris@177 629 if (count[ct] > 0) {
Chris@232 630
Chris@177 631 for (size_t ch = 0; ch < size_t(channels); ++ch) {
Chris@177 632 size_t rangeIndex = ch * 2 + ct;
Chris@177 633 range[rangeIndex].absmean /= count[ct];
Chris@177 634 m_model.m_cache[ct].push_back(range[rangeIndex]);
Chris@177 635 range[rangeIndex] = Range();
Chris@177 636 }
Chris@232 637
Chris@177 638 count[ct] = 0;
Chris@147 639 }
Chris@177 640
Chris@177 641 const Range &rr = *m_model.m_cache[ct].begin();
Chris@177 642 MUNLOCK(&rr, m_model.m_cache[ct].capacity() * sizeof(Range));
Chris@147 643 }
Chris@147 644 }
Chris@147 645
Chris@147 646 delete[] range;
Chris@147 647
Chris@175 648 m_fillExtent = m_frameCount;
Chris@236 649
Chris@236 650 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@236 651 for (size_t ct = 0; ct < 2; ++ct) {
Chris@236 652 cerr << "Cache type " << ct << " now contains " << m_model.m_cache[ct].size() << " ranges" << endl;
Chris@236 653 }
Chris@236 654 #endif
Chris@147 655 }
Chris@147 656
Chris@163 657 void
Chris@163 658 WaveFileModel::toXml(QTextStream &out,
Chris@163 659 QString indent,
Chris@163 660 QString extraAttributes) const
Chris@163 661 {
Chris@163 662 Model::toXml(out, indent,
Chris@163 663 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@279 664 .arg(encodeEntities(m_path)).arg(extraAttributes));
Chris@163 665 }
Chris@163 666
Chris@147 667