annotate data/model/WaveFileModel.cpp @ 184:5a916fee6d2d

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