annotate data/model/ReadOnlyWaveFileModel.cpp @ 1394:9ef1cc26024c

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