annotate data/model/WaveFileModel.cpp @ 1061:c1e43c8d2527 tonioni

Thread-local debug was causing crash on exit with Qt 5.4.x. But we introduced that because QDebug itself was crashing when used from multiple threads. Replace with simpler fstream version
author Chris Cannam
date Tue, 31 Mar 2015 10:36:52 +0100
parents 48e4ffa9fb48
children 0fd3661bcfff
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@921 23 #include "base/Preferences.h"
Chris@921 24
Chris@147 25 #include <QFileInfo>
Chris@314 26 #include <QTextStream>
Chris@147 27
Chris@147 28 #include <iostream>
Chris@147 29 #include <unistd.h>
Chris@572 30 #include <cmath>
Chris@147 31 #include <sndfile.h>
Chris@147 32
Chris@147 33 #include <cassert>
Chris@147 34
Chris@236 35 //#define DEBUG_WAVE_FILE_MODEL 1
Chris@236 36
Chris@179 37 PowerOfSqrtTwoZoomConstraint
Chris@179 38 WaveFileModel::m_zoomConstraint;
Chris@179 39
Chris@1040 40 WaveFileModel::WaveFileModel(FileSource source, sv_samplerate_t targetRate) :
Chris@316 41 m_source(source),
Chris@316 42 m_path(source.getLocation()),
Chris@971 43 m_reader(0),
Chris@175 44 m_myReader(true),
Chris@300 45 m_startFrame(0),
Chris@147 46 m_fillThread(0),
Chris@147 47 m_updateTimer(0),
Chris@147 48 m_lastFillExtent(0),
Chris@752 49 m_exiting(false),
Chris@752 50 m_lastDirectReadStart(0),
Chris@752 51 m_lastDirectReadCount(0)
Chris@147 52 {
Chris@316 53 m_source.waitForData();
Chris@316 54 if (m_source.isOK()) {
Chris@921 55 bool normalise = Preferences::getInstance()->getNormaliseAudio();
Chris@327 56 m_reader = AudioFileReaderFactory::createThreadingReader
Chris@921 57 (m_source, targetRate, normalise);
Chris@316 58 if (m_reader) {
Chris@690 59 SVDEBUG << "WaveFileModel::WaveFileModel: reader rate: "
Chris@687 60 << m_reader->getSampleRate() << endl;
Chris@316 61 }
Chris@316 62 }
Chris@292 63 if (m_reader) setObjectName(m_reader->getTitle());
Chris@316 64 if (objectName() == "") setObjectName(QFileInfo(m_path).fileName());
Chris@175 65 if (isOK()) fillCache();
Chris@175 66 }
Chris@175 67
Chris@317 68 WaveFileModel::WaveFileModel(FileSource source, AudioFileReader *reader) :
Chris@316 69 m_source(source),
Chris@316 70 m_path(source.getLocation()),
Chris@971 71 m_reader(0),
Chris@175 72 m_myReader(false),
Chris@300 73 m_startFrame(0),
Chris@175 74 m_fillThread(0),
Chris@175 75 m_updateTimer(0),
Chris@175 76 m_lastFillExtent(0),
Chris@175 77 m_exiting(false)
Chris@175 78 {
Chris@175 79 m_reader = reader;
Chris@292 80 if (m_reader) setObjectName(m_reader->getTitle());
Chris@316 81 if (objectName() == "") setObjectName(QFileInfo(m_path).fileName());
Chris@187 82 fillCache();
Chris@147 83 }
Chris@147 84
Chris@147 85 WaveFileModel::~WaveFileModel()
Chris@147 86 {
Chris@147 87 m_exiting = true;
Chris@147 88 if (m_fillThread) m_fillThread->wait();
Chris@175 89 if (m_myReader) delete m_reader;
Chris@147 90 m_reader = 0;
Chris@147 91 }
Chris@147 92
Chris@147 93 bool
Chris@147 94 WaveFileModel::isOK() const
Chris@147 95 {
Chris@147 96 return m_reader && m_reader->isOK();
Chris@147 97 }
Chris@147 98
Chris@147 99 bool
Chris@147 100 WaveFileModel::isReady(int *completion) const
Chris@147 101 {
Chris@147 102 bool ready = (isOK() && (m_fillThread == 0));
Chris@147 103 double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
Chris@266 104 static int prevCompletion = 0;
Chris@265 105 if (completion) {
Chris@265 106 *completion = int(c * 100.0 + 0.01);
Chris@265 107 if (m_reader) {
Chris@265 108 int decodeCompletion = m_reader->getDecodeCompletion();
Chris@266 109 if (decodeCompletion < 90) *completion = decodeCompletion;
Chris@266 110 else *completion = std::min(*completion, decodeCompletion);
Chris@265 111 }
Chris@266 112 if (*completion != 0 &&
Chris@266 113 *completion != 100 &&
Chris@266 114 prevCompletion != 0 &&
Chris@266 115 prevCompletion > *completion) {
Chris@266 116 // just to avoid completion going backwards
Chris@266 117 *completion = prevCompletion;
Chris@266 118 }
Chris@266 119 prevCompletion = *completion;
Chris@265 120 }
Chris@236 121 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 122 SVDEBUG << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << endl;
Chris@236 123 #endif
Chris@147 124 return ready;
Chris@147 125 }
Chris@147 126
Chris@147 127 Model *
Chris@147 128 WaveFileModel::clone() const
Chris@147 129 {
Chris@316 130 WaveFileModel *model = new WaveFileModel(m_source);
Chris@147 131 return model;
Chris@147 132 }
Chris@147 133
Chris@1038 134 sv_frame_t
Chris@147 135 WaveFileModel::getFrameCount() const
Chris@147 136 {
Chris@147 137 if (!m_reader) return 0;
Chris@147 138 return m_reader->getFrameCount();
Chris@147 139 }
Chris@147 140
Chris@929 141 int
Chris@147 142 WaveFileModel::getChannelCount() const
Chris@147 143 {
Chris@147 144 if (!m_reader) return 0;
Chris@147 145 return m_reader->getChannelCount();
Chris@147 146 }
Chris@147 147
Chris@1040 148 sv_samplerate_t
Chris@147 149 WaveFileModel::getSampleRate() const
Chris@147 150 {
Chris@147 151 if (!m_reader) return 0;
Chris@147 152 return m_reader->getSampleRate();
Chris@147 153 }
Chris@147 154
Chris@1040 155 sv_samplerate_t
Chris@297 156 WaveFileModel::getNativeRate() const
Chris@297 157 {
Chris@297 158 if (!m_reader) return 0;
Chris@1040 159 sv_samplerate_t rate = m_reader->getNativeRate();
Chris@297 160 if (rate == 0) rate = getSampleRate();
Chris@297 161 return rate;
Chris@297 162 }
Chris@297 163
Chris@333 164 QString
Chris@333 165 WaveFileModel::getTitle() const
Chris@333 166 {
Chris@333 167 QString title;
Chris@333 168 if (m_reader) title = m_reader->getTitle();
Chris@333 169 if (title == "") title = objectName();
Chris@333 170 return title;
Chris@333 171 }
Chris@333 172
Chris@333 173 QString
Chris@333 174 WaveFileModel::getMaker() const
Chris@333 175 {
Chris@333 176 if (m_reader) return m_reader->getMaker();
Chris@333 177 return "";
Chris@333 178 }
Chris@345 179
Chris@345 180 QString
Chris@345 181 WaveFileModel::getLocation() const
Chris@345 182 {
Chris@345 183 if (m_reader) return m_reader->getLocation();
Chris@345 184 return "";
Chris@345 185 }
Chris@1010 186
Chris@1010 187 QString
Chris@1010 188 WaveFileModel::getLocalFilename() const
Chris@1010 189 {
Chris@1010 190 if (m_reader) return m_reader->getLocalFilename();
Chris@1010 191 return "";
Chris@1010 192 }
Chris@333 193
Chris@1038 194 sv_frame_t
Chris@1038 195 WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 196 float *buffer) const
Chris@147 197 {
Chris@147 198 // Always read these directly from the file.
Chris@147 199 // This is used for e.g. audio playback.
Chris@147 200 // Could be much more efficient (although compiler optimisation will help)
Chris@147 201
Chris@429 202 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@843 203 cout << "WaveFileModel::getData[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl;
Chris@429 204 #endif
Chris@429 205
Chris@363 206 if (start >= m_startFrame) {
Chris@300 207 start -= m_startFrame;
Chris@300 208 } else {
Chris@1038 209 for (sv_frame_t i = 0; i < count; ++i) {
Chris@948 210 buffer[i] = 0.f;
Chris@948 211 }
Chris@300 212 if (count <= m_startFrame - start) {
Chris@300 213 return 0;
Chris@300 214 } else {
Chris@300 215 count -= (m_startFrame - start);
Chris@300 216 start = 0;
Chris@300 217 }
Chris@147 218 }
Chris@147 219
Chris@300 220 if (!m_reader || !m_reader->isOK() || count == 0) {
Chris@1038 221 for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.f;
Chris@300 222 return 0;
Chris@300 223 }
Chris@147 224
Chris@236 225 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 226 // SVDEBUG << "WaveFileModel::getValues(" << channel << ", "
Chris@687 227 // << start << ", " << end << "): calling reader" << endl;
Chris@236 228 #endif
Chris@175 229
Chris@363 230 int channels = getChannelCount();
Chris@363 231
Chris@1041 232 SampleBlock frames = m_reader->getInterleavedFrames(start, count);
Chris@147 233
Chris@1038 234 sv_frame_t i = 0;
Chris@147 235
Chris@363 236 int ch0 = channel, ch1 = channel;
Chris@147 237 if (channel == -1) {
Chris@147 238 ch0 = 0;
Chris@147 239 ch1 = channels - 1;
Chris@147 240 }
Chris@147 241
Chris@300 242 while (i < count) {
Chris@147 243
Chris@147 244 buffer[i] = 0.0;
Chris@147 245
Chris@147 246 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 247
Chris@1038 248 sv_frame_t index = i * channels + ch;
Chris@1038 249 if (index >= (sv_frame_t)frames.size()) break;
Chris@147 250
Chris@147 251 float sample = frames[index];
Chris@147 252 buffer[i] += sample;
Chris@147 253 }
Chris@147 254
Chris@147 255 ++i;
Chris@147 256 }
Chris@147 257
Chris@147 258 return i;
Chris@147 259 }
Chris@147 260
Chris@1038 261 sv_frame_t
Chris@1038 262 WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
Chris@300 263 double *buffer) const
Chris@147 264 {
Chris@429 265 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@843 266 cout << "WaveFileModel::getData(double)[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl;
Chris@429 267 #endif
Chris@429 268
Chris@300 269 if (start > m_startFrame) {
Chris@300 270 start -= m_startFrame;
Chris@300 271 } else {
Chris@1038 272 for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.0;
Chris@300 273 if (count <= m_startFrame - start) {
Chris@300 274 return 0;
Chris@300 275 } else {
Chris@300 276 count -= (m_startFrame - start);
Chris@300 277 start = 0;
Chris@300 278 }
Chris@147 279 }
Chris@147 280
Chris@300 281 if (!m_reader || !m_reader->isOK() || count == 0) {
Chris@1038 282 for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.0;
Chris@300 283 return 0;
Chris@300 284 }
Chris@147 285
Chris@363 286 int channels = getChannelCount();
Chris@363 287
Chris@1041 288 SampleBlock frames = m_reader->getInterleavedFrames(start, count);
Chris@147 289
Chris@1038 290 sv_frame_t i = 0;
Chris@147 291
Chris@363 292 int ch0 = channel, ch1 = channel;
Chris@147 293 if (channel == -1) {
Chris@147 294 ch0 = 0;
Chris@147 295 ch1 = channels - 1;
Chris@147 296 }
Chris@147 297
Chris@300 298 while (i < count) {
Chris@147 299
Chris@147 300 buffer[i] = 0.0;
Chris@147 301
Chris@147 302 for (int ch = ch0; ch <= ch1; ++ch) {
Chris@147 303
Chris@1038 304 sv_frame_t index = i * channels + ch;
Chris@1038 305 if (index >= (sv_frame_t)frames.size()) break;
Chris@147 306
Chris@147 307 float sample = frames[index];
Chris@147 308 buffer[i] += sample;
Chris@147 309 }
Chris@147 310
Chris@147 311 ++i;
Chris@147 312 }
Chris@147 313
Chris@147 314 return i;
Chris@147 315 }
Chris@147 316
Chris@1038 317 sv_frame_t
Chris@929 318 WaveFileModel::getData(int fromchannel, int tochannel,
Chris@1038 319 sv_frame_t start, sv_frame_t count,
Chris@363 320 float **buffer) const
Chris@363 321 {
Chris@429 322 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@843 323 cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl;
Chris@429 324 #endif
Chris@429 325
Chris@929 326 int channels = getChannelCount();
Chris@363 327
Chris@363 328 if (fromchannel > tochannel) {
Chris@843 329 cerr << "ERROR: WaveFileModel::getData: fromchannel ("
Chris@363 330 << fromchannel << ") > tochannel (" << tochannel << ")"
Chris@843 331 << endl;
Chris@363 332 return 0;
Chris@363 333 }
Chris@363 334
Chris@363 335 if (tochannel >= channels) {
Chris@843 336 cerr << "ERROR: WaveFileModel::getData: tochannel ("
Chris@363 337 << tochannel << ") >= channel count (" << channels << ")"
Chris@843 338 << endl;
Chris@363 339 return 0;
Chris@363 340 }
Chris@363 341
Chris@363 342 if (fromchannel == tochannel) {
Chris@363 343 return getData(fromchannel, start, count, buffer[0]);
Chris@363 344 }
Chris@363 345
Chris@929 346 int reqchannels = (tochannel - fromchannel) + 1;
Chris@363 347
Chris@363 348 // Always read these directly from the file.
Chris@363 349 // This is used for e.g. audio playback.
Chris@363 350 // Could be much more efficient (although compiler optimisation will help)
Chris@363 351
Chris@363 352 if (start >= m_startFrame) {
Chris@363 353 start -= m_startFrame;
Chris@363 354 } else {
Chris@929 355 for (int c = 0; c < reqchannels; ++c) {
Chris@1038 356 for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
Chris@363 357 }
Chris@363 358 if (count <= m_startFrame - start) {
Chris@363 359 return 0;
Chris@363 360 } else {
Chris@363 361 count -= (m_startFrame - start);
Chris@363 362 start = 0;
Chris@363 363 }
Chris@363 364 }
Chris@363 365
Chris@363 366 if (!m_reader || !m_reader->isOK() || count == 0) {
Chris@929 367 for (int c = 0; c < reqchannels; ++c) {
Chris@1038 368 for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
Chris@363 369 }
Chris@363 370 return 0;
Chris@363 371 }
Chris@363 372
Chris@1041 373 SampleBlock frames = m_reader->getInterleavedFrames(start, count);
Chris@363 374
Chris@1038 375 sv_frame_t i = 0;
Chris@363 376
Chris@1038 377 sv_frame_t index = 0, available = frames.size();
Chris@363 378
Chris@363 379 while (i < count) {
Chris@363 380
Chris@363 381 if (index >= available) break;
Chris@363 382
Chris@929 383 int destc = 0;
Chris@363 384
Chris@929 385 for (int c = 0; c < channels; ++c) {
Chris@363 386
Chris@363 387 if (c >= fromchannel && c <= tochannel) {
Chris@363 388 buffer[destc][i] = frames[index];
Chris@363 389 ++destc;
Chris@363 390 }
Chris@363 391
Chris@363 392 ++index;
Chris@363 393 }
Chris@363 394
Chris@363 395 ++i;
Chris@363 396 }
Chris@363 397
Chris@363 398 return i;
Chris@363 399 }
Chris@363 400
Chris@929 401 int
Chris@929 402 WaveFileModel::getSummaryBlockSize(int desired) const
Chris@377 403 {
Chris@377 404 int cacheType = 0;
Chris@377 405 int power = m_zoomConstraint.getMinCachePower();
Chris@929 406 int roundedBlockSize = m_zoomConstraint.getNearestBlockSize
Chris@377 407 (desired, cacheType, power, ZoomConstraint::RoundDown);
Chris@377 408 if (cacheType != 0 && cacheType != 1) {
Chris@377 409 // We will be reading directly from file, so can satisfy any
Chris@377 410 // blocksize requirement
Chris@377 411 return desired;
Chris@377 412 } else {
Chris@377 413 return roundedBlockSize;
Chris@377 414 }
Chris@377 415 }
Chris@377 416
Chris@225 417 void
Chris@1038 418 WaveFileModel::getSummaries(int channel, sv_frame_t start, sv_frame_t count,
Chris@929 419 RangeBlock &ranges, int &blockSize) const
Chris@147 420 {
Chris@225 421 ranges.clear();
Chris@225 422 if (!isOK()) return;
Chris@377 423 ranges.reserve((count / blockSize) + 1);
Chris@147 424
Chris@300 425 if (start > m_startFrame) start -= m_startFrame;
Chris@300 426 else if (count <= m_startFrame - start) return;
Chris@300 427 else {
Chris@300 428 count -= (m_startFrame - start);
Chris@300 429 start = 0;
Chris@147 430 }
Chris@147 431
Chris@147 432 int cacheType = 0;
Chris@179 433 int power = m_zoomConstraint.getMinCachePower();
Chris@929 434 int roundedBlockSize = m_zoomConstraint.getNearestBlockSize
Chris@377 435 (blockSize, cacheType, power, ZoomConstraint::RoundDown);
Chris@147 436
Chris@929 437 int channels = getChannelCount();
Chris@147 438
Chris@147 439 if (cacheType != 0 && cacheType != 1) {
Chris@147 440
Chris@147 441 // We need to read directly from the file. We haven't got
Chris@147 442 // this cached. Hope the requested area is small. This is
Chris@147 443 // not optimal -- we'll end up reading the same frames twice
Chris@147 444 // for stereo files, in two separate calls to this method.
Chris@147 445 // We could fairly trivially handle this for most cases that
Chris@147 446 // matter by putting a single cache in getInterleavedFrames
Chris@147 447 // for short queries.
Chris@147 448
Chris@377 449 m_directReadMutex.lock();
Chris@377 450
Chris@377 451 if (m_lastDirectReadStart != start ||
Chris@377 452 m_lastDirectReadCount != count ||
Chris@377 453 m_directRead.empty()) {
Chris@377 454
Chris@1041 455 m_directRead = m_reader->getInterleavedFrames(start, count);
Chris@377 456 m_lastDirectReadStart = start;
Chris@377 457 m_lastDirectReadCount = count;
Chris@377 458 }
Chris@377 459
Chris@147 460 float max = 0.0, min = 0.0, total = 0.0;
Chris@1038 461 sv_frame_t i = 0, got = 0;
Chris@147 462
Chris@300 463 while (i < count) {
Chris@147 464
Chris@1038 465 sv_frame_t index = i * channels + channel;
Chris@1038 466 if (index >= (sv_frame_t)m_directRead.size()) break;
Chris@147 467
Chris@377 468 float sample = m_directRead[index];
Chris@300 469 if (sample > max || got == 0) max = sample;
Chris@300 470 if (sample < min || got == 0) min = sample;
Chris@147 471 total += fabsf(sample);
Chris@838 472
Chris@147 473 ++i;
Chris@300 474 ++got;
Chris@147 475
Chris@300 476 if (got == blockSize) {
Chris@1038 477 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 478 min = max = total = 0.0f;
Chris@300 479 got = 0;
Chris@147 480 }
Chris@147 481 }
Chris@147 482
Chris@377 483 m_directReadMutex.unlock();
Chris@377 484
Chris@300 485 if (got > 0) {
Chris@1038 486 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 487 }
Chris@147 488
Chris@225 489 return;
Chris@147 490
Chris@147 491 } else {
Chris@147 492
Chris@147 493 QMutexLocker locker(&m_mutex);
Chris@147 494
Chris@147 495 const RangeBlock &cache = m_cache[cacheType];
Chris@147 496
Chris@377 497 blockSize = roundedBlockSize;
Chris@377 498
Chris@1038 499 sv_frame_t cacheBlock, div;
Chris@147 500
Chris@147 501 if (cacheType == 0) {
Chris@179 502 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
Chris@147 503 div = (1 << power) / cacheBlock;
Chris@147 504 } else {
Chris@1038 505 cacheBlock = sv_frame_t((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2.) + 0.01);
Chris@1038 506 div = sv_frame_t(((1 << power) * sqrt(2.) + 0.01) / double(cacheBlock));
Chris@147 507 }
Chris@147 508
Chris@1038 509 sv_frame_t startIndex = start / cacheBlock;
Chris@1038 510 sv_frame_t endIndex = (start + count) / cacheBlock;
Chris@147 511
Chris@147 512 float max = 0.0, min = 0.0, total = 0.0;
Chris@1038 513 sv_frame_t i = 0, got = 0;
Chris@147 514
Chris@236 515 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@300 516 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 517 #endif
Chris@147 518
Chris@300 519 for (i = 0; i <= endIndex - startIndex; ) {
Chris@147 520
Chris@1038 521 sv_frame_t index = (i + startIndex) * channels + channel;
Chris@1038 522 if (index >= (sv_frame_t)cache.size()) break;
Chris@147 523
Chris@147 524 const Range &range = cache[index];
Chris@410 525 if (range.max() > max || got == 0) max = range.max();
Chris@410 526 if (range.min() < min || got == 0) min = range.min();
Chris@410 527 total += range.absmean();
Chris@147 528
Chris@147 529 ++i;
Chris@300 530 ++got;
Chris@147 531
Chris@300 532 if (got == div) {
Chris@1038 533 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 534 min = max = total = 0.0f;
Chris@300 535 got = 0;
Chris@147 536 }
Chris@147 537 }
Chris@147 538
Chris@300 539 if (got > 0) {
Chris@1038 540 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 541 }
Chris@147 542 }
Chris@147 543
Chris@236 544 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 545 SVDEBUG << "returning " << ranges.size() << " ranges" << endl;
Chris@236 546 #endif
Chris@225 547 return;
Chris@147 548 }
Chris@147 549
Chris@147 550 WaveFileModel::Range
Chris@1038 551 WaveFileModel::getSummary(int channel, sv_frame_t start, sv_frame_t count) const
Chris@147 552 {
Chris@147 553 Range range;
Chris@147 554 if (!isOK()) return range;
Chris@147 555
Chris@300 556 if (start > m_startFrame) start -= m_startFrame;
Chris@300 557 else if (count <= m_startFrame - start) return range;
Chris@300 558 else {
Chris@300 559 count -= (m_startFrame - start);
Chris@300 560 start = 0;
Chris@147 561 }
Chris@147 562
Chris@929 563 int blockSize;
Chris@300 564 for (blockSize = 1; blockSize <= count; blockSize *= 2);
Chris@300 565 if (blockSize > 1) blockSize /= 2;
Chris@147 566
Chris@147 567 bool first = false;
Chris@147 568
Chris@1038 569 sv_frame_t blockStart = (start / blockSize) * blockSize;
Chris@1038 570 sv_frame_t blockEnd = ((start + count) / blockSize) * blockSize;
Chris@147 571
Chris@147 572 if (blockStart < start) blockStart += blockSize;
Chris@147 573
Chris@147 574 if (blockEnd > blockStart) {
Chris@225 575 RangeBlock ranges;
Chris@300 576 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
Chris@929 577 for (int i = 0; i < (int)ranges.size(); ++i) {
Chris@410 578 if (first || ranges[i].min() < range.min()) range.setMin(ranges[i].min());
Chris@410 579 if (first || ranges[i].max() > range.max()) range.setMax(ranges[i].max());
Chris@410 580 if (first || ranges[i].absmean() < range.absmean()) range.setAbsmean(ranges[i].absmean());
Chris@147 581 first = false;
Chris@147 582 }
Chris@147 583 }
Chris@147 584
Chris@147 585 if (blockStart > start) {
Chris@300 586 Range startRange = getSummary(channel, start, blockStart - start);
Chris@410 587 range.setMin(std::min(range.min(), startRange.min()));
Chris@410 588 range.setMax(std::max(range.max(), startRange.max()));
Chris@410 589 range.setAbsmean(std::min(range.absmean(), startRange.absmean()));
Chris@147 590 }
Chris@147 591
Chris@300 592 if (blockEnd < start + count) {
Chris@300 593 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
Chris@410 594 range.setMin(std::min(range.min(), endRange.min()));
Chris@410 595 range.setMax(std::max(range.max(), endRange.max()));
Chris@410 596 range.setAbsmean(std::min(range.absmean(), endRange.absmean()));
Chris@147 597 }
Chris@147 598
Chris@147 599 return range;
Chris@147 600 }
Chris@147 601
Chris@147 602 void
Chris@147 603 WaveFileModel::fillCache()
Chris@147 604 {
Chris@147 605 m_mutex.lock();
Chris@188 606
Chris@147 607 m_updateTimer = new QTimer(this);
Chris@147 608 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
Chris@147 609 m_updateTimer->start(100);
Chris@188 610
Chris@147 611 m_fillThread = new RangeCacheFillThread(*this);
Chris@147 612 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
Chris@188 613
Chris@147 614 m_mutex.unlock();
Chris@147 615 m_fillThread->start();
Chris@188 616
Chris@236 617 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 618 SVDEBUG << "WaveFileModel::fillCache: started fill thread" << endl;
Chris@236 619 #endif
Chris@147 620 }
Chris@147 621
Chris@147 622 void
Chris@147 623 WaveFileModel::fillTimerTimedOut()
Chris@147 624 {
Chris@147 625 if (m_fillThread) {
Chris@1038 626 sv_frame_t fillExtent = m_fillThread->getFillExtent();
Chris@236 627 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 628 SVDEBUG << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
Chris@236 629 #endif
Chris@147 630 if (fillExtent > m_lastFillExtent) {
Chris@931 631 emit modelChangedWithin(m_lastFillExtent, fillExtent);
Chris@147 632 m_lastFillExtent = fillExtent;
Chris@147 633 }
Chris@147 634 } else {
Chris@236 635 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 636 SVDEBUG << "WaveFileModel::fillTimerTimedOut: no thread" << endl;
Chris@236 637 #endif
Chris@147 638 emit modelChanged();
Chris@147 639 }
Chris@147 640 }
Chris@147 641
Chris@147 642 void
Chris@147 643 WaveFileModel::cacheFilled()
Chris@147 644 {
Chris@147 645 m_mutex.lock();
Chris@147 646 delete m_fillThread;
Chris@147 647 m_fillThread = 0;
Chris@147 648 delete m_updateTimer;
Chris@147 649 m_updateTimer = 0;
Chris@147 650 m_mutex.unlock();
Chris@267 651 if (getEndFrame() > m_lastFillExtent) {
Chris@931 652 emit modelChangedWithin(m_lastFillExtent, getEndFrame());
Chris@267 653 }
Chris@147 654 emit modelChanged();
Chris@411 655 emit ready();
Chris@236 656 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@690 657 SVDEBUG << "WaveFileModel::cacheFilled" << endl;
Chris@236 658 #endif
Chris@175 659 }
Chris@175 660
Chris@175 661 void
Chris@147 662 WaveFileModel::RangeCacheFillThread::run()
Chris@147 663 {
Chris@929 664 int cacheBlockSize[2];
Chris@179 665 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
Chris@1038 666 cacheBlockSize[1] = (int((1 << m_model.m_zoomConstraint.getMinCachePower()) *
Chris@608 667 sqrt(2.) + 0.01));
Chris@147 668
Chris@1038 669 sv_frame_t frame = 0;
Chris@1053 670 const sv_frame_t readBlockSize = 16384;
Chris@290 671 SampleBlock block;
Chris@147 672
Chris@147 673 if (!m_model.isOK()) return;
Chris@147 674
Chris@929 675 int channels = m_model.getChannelCount();
Chris@187 676 bool updating = m_model.m_reader->isUpdating();
Chris@187 677
Chris@187 678 if (updating) {
Chris@187 679 while (channels == 0 && !m_model.m_exiting) {
Chris@690 680 // SVDEBUG << "WaveFileModel::fill: Waiting for channels..." << endl;
Chris@187 681 sleep(1);
Chris@187 682 channels = m_model.getChannelCount();
Chris@187 683 }
Chris@187 684 }
Chris@147 685
Chris@147 686 Range *range = new Range[2 * channels];
Chris@410 687 float *means = new float[2 * channels];
Chris@929 688 int count[2];
Chris@147 689 count[0] = count[1] = 0;
Chris@411 690 for (int i = 0; i < 2 * channels; ++i) {
Chris@411 691 means[i] = 0.f;
Chris@411 692 }
Chris@176 693
Chris@176 694 bool first = true;
Chris@176 695
Chris@176 696 while (first || updating) {
Chris@176 697
Chris@176 698 updating = m_model.m_reader->isUpdating();
Chris@187 699 m_frameCount = m_model.getFrameCount();
Chris@175 700
Chris@690 701 // SVDEBUG << "WaveFileModel::fill: frame = " << frame << ", count = " << m_frameCount << endl;
Chris@147 702
Chris@176 703 while (frame < m_frameCount) {
Chris@147 704
Chris@690 705 // SVDEBUG << "WaveFileModel::fill inner loop: frame = " << frame << ", count = " << m_frameCount << ", blocksize " << readBlockSize << endl;
Chris@265 706
Chris@176 707 if (updating && (frame + readBlockSize > m_frameCount)) break;
Chris@176 708
Chris@1041 709 block = m_model.m_reader->getInterleavedFrames(frame, readBlockSize);
Chris@176 710
Chris@843 711 // cerr << "block is " << block.size() << endl;
Chris@265 712
Chris@1038 713 for (sv_frame_t i = 0; i < readBlockSize; ++i) {
Chris@147 714
Chris@929 715 if (channels * i + channels > (int)block.size()) break;
Chris@232 716
Chris@411 717 for (int ch = 0; ch < channels; ++ch) {
Chris@147 718
Chris@1038 719 sv_frame_t index = channels * i + ch;
Chris@176 720 float sample = block[index];
Chris@176 721
Chris@1053 722 for (int cacheType = 0; cacheType < 2; ++cacheType) { // cache type
Chris@176 723
Chris@1053 724 sv_frame_t rangeIndex = ch * 2 + cacheType;
Chris@1053 725 range[rangeIndex].sample(sample);
Chris@410 726 means[rangeIndex] += fabsf(sample);
Chris@176 727 }
Chris@176 728 }
Chris@1042 729
Chris@1042 730 //!!! this looks like a ludicrous way to do synchronisation
Chris@176 731 QMutexLocker locker(&m_model.m_mutex);
Chris@232 732
Chris@1053 733 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@232 734
Chris@1053 735 if (++count[cacheType] == cacheBlockSize[cacheType]) {
Chris@410 736
Chris@929 737 for (int ch = 0; ch < int(channels); ++ch) {
Chris@1053 738 int rangeIndex = ch * 2 + cacheType;
Chris@1053 739 means[rangeIndex] = means[rangeIndex] / float(count[cacheType]);
Chris@410 740 range[rangeIndex].setAbsmean(means[rangeIndex]);
Chris@1053 741 m_model.m_cache[cacheType].push_back(range[rangeIndex]);
Chris@176 742 range[rangeIndex] = Range();
Chris@411 743 means[rangeIndex] = 0.f;
Chris@176 744 }
Chris@232 745
Chris@1053 746 count[cacheType] = 0;
Chris@176 747 }
Chris@176 748 }
Chris@147 749
Chris@176 750 ++frame;
Chris@147 751 }
Chris@147 752
Chris@176 753 if (m_model.m_exiting) break;
Chris@176 754
Chris@176 755 m_fillExtent = frame;
Chris@147 756 }
Chris@147 757
Chris@843 758 // cerr << "WaveFileModel: inner loop ended" << endl;
Chris@265 759
Chris@176 760 first = false;
Chris@177 761 if (m_model.m_exiting) break;
Chris@187 762 if (updating) {
Chris@843 763 // cerr << "sleeping..." << endl;
Chris@187 764 sleep(1);
Chris@187 765 }
Chris@147 766 }
Chris@147 767
Chris@177 768 if (!m_model.m_exiting) {
Chris@177 769
Chris@177 770 QMutexLocker locker(&m_model.m_mutex);
Chris@232 771
Chris@1053 772 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@232 773
Chris@1053 774 if (count[cacheType] > 0) {
Chris@232 775
Chris@929 776 for (int ch = 0; ch < int(channels); ++ch) {
Chris@1053 777 int rangeIndex = ch * 2 + cacheType;
Chris@1053 778 means[rangeIndex] = means[rangeIndex] / float(count[cacheType]);
Chris@410 779 range[rangeIndex].setAbsmean(means[rangeIndex]);
Chris@1053 780 m_model.m_cache[cacheType].push_back(range[rangeIndex]);
Chris@177 781 range[rangeIndex] = Range();
Chris@411 782 means[rangeIndex] = 0.f;
Chris@177 783 }
Chris@232 784
Chris@1053 785 count[cacheType] = 0;
Chris@147 786 }
Chris@177 787
Chris@1053 788 const Range &rr = *m_model.m_cache[cacheType].begin();
Chris@1053 789 MUNLOCK(&rr, m_model.m_cache[cacheType].capacity() * sizeof(Range));
Chris@147 790 }
Chris@147 791 }
Chris@147 792
Chris@410 793 delete[] means;
Chris@147 794 delete[] range;
Chris@147 795
Chris@175 796 m_fillExtent = m_frameCount;
Chris@236 797
Chris@236 798 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1053 799 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@1053 800 cerr << "Cache type " << cacheType << " now contains " << m_model.m_cache[cacheType].size() << " ranges" << endl;
Chris@236 801 }
Chris@236 802 #endif
Chris@147 803 }
Chris@147 804
Chris@163 805 void
Chris@163 806 WaveFileModel::toXml(QTextStream &out,
Chris@163 807 QString indent,
Chris@163 808 QString extraAttributes) const
Chris@163 809 {
Chris@163 810 Model::toXml(out, indent,
Chris@163 811 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@279 812 .arg(encodeEntities(m_path)).arg(extraAttributes));
Chris@163 813 }
Chris@163 814
Chris@147 815