annotate data/model/WaveFileModel.cpp @ 308:14e0f60435b8

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