annotate data/model/ReadOnlyWaveFileModel.cpp @ 1418:e7cb4fb2aee4 scale-ticks

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