annotate data/model/ReadOnlyWaveFileModel.cpp @ 1324:d4a28d1479a8 zoom

Some hackery toward having a zoomlevel type
author Chris Cannam
date Mon, 12 Dec 2016 15:18:52 +0000
parents ff9697592bef
children 710e6250a401
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@1096 205 vector<float>
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@1100 239 vector<float> 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@1100 244 vector<float> 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@1096 263 vector<vector<float>>
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@1096 307 vector<float> 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@1096 311 vector<vector<float>> result(reqchannels, vector<float>(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@1324 330
Chris@377 331 if (cacheType != 0 && cacheType != 1) {
Chris@377 332 // We will be reading directly from file, so can satisfy any
Chris@377 333 // blocksize requirement
Chris@377 334 return desired;
Chris@377 335 } else {
Chris@377 336 return roundedBlockSize;
Chris@377 337 }
Chris@377 338 }
Chris@377 339
Chris@225 340 void
Chris@1122 341 ReadOnlyWaveFileModel::getSummaries(int channel, sv_frame_t start, sv_frame_t count,
Chris@1151 342 RangeBlock &ranges, int &blockSize) const
Chris@147 343 {
Chris@225 344 ranges.clear();
Chris@225 345 if (!isOK()) return;
Chris@377 346 ranges.reserve((count / blockSize) + 1);
Chris@147 347
Chris@300 348 if (start > m_startFrame) start -= m_startFrame;
Chris@300 349 else if (count <= m_startFrame - start) return;
Chris@300 350 else {
Chris@300 351 count -= (m_startFrame - start);
Chris@300 352 start = 0;
Chris@147 353 }
Chris@147 354
Chris@147 355 int cacheType = 0;
Chris@179 356 int power = m_zoomConstraint.getMinCachePower();
Chris@929 357 int roundedBlockSize = m_zoomConstraint.getNearestBlockSize
Chris@377 358 (blockSize, cacheType, power, ZoomConstraint::RoundDown);
Chris@147 359
Chris@929 360 int channels = getChannelCount();
Chris@147 361
Chris@147 362 if (cacheType != 0 && cacheType != 1) {
Chris@147 363
Chris@147 364 // We need to read directly from the file. We haven't got
Chris@147 365 // this cached. Hope the requested area is small. This is
Chris@147 366 // not optimal -- we'll end up reading the same frames twice
Chris@147 367 // for stereo files, in two separate calls to this method.
Chris@147 368 // We could fairly trivially handle this for most cases that
Chris@147 369 // matter by putting a single cache in getInterleavedFrames
Chris@147 370 // for short queries.
Chris@147 371
Chris@377 372 m_directReadMutex.lock();
Chris@377 373
Chris@377 374 if (m_lastDirectReadStart != start ||
Chris@377 375 m_lastDirectReadCount != count ||
Chris@377 376 m_directRead.empty()) {
Chris@377 377
Chris@1041 378 m_directRead = m_reader->getInterleavedFrames(start, count);
Chris@377 379 m_lastDirectReadStart = start;
Chris@377 380 m_lastDirectReadCount = count;
Chris@377 381 }
Chris@377 382
Chris@147 383 float max = 0.0, min = 0.0, total = 0.0;
Chris@1038 384 sv_frame_t i = 0, got = 0;
Chris@147 385
Chris@300 386 while (i < count) {
Chris@147 387
Chris@1038 388 sv_frame_t index = i * channels + channel;
Chris@1038 389 if (index >= (sv_frame_t)m_directRead.size()) break;
Chris@147 390
Chris@377 391 float sample = m_directRead[index];
Chris@300 392 if (sample > max || got == 0) max = sample;
Chris@300 393 if (sample < min || got == 0) min = sample;
Chris@147 394 total += fabsf(sample);
Chris@838 395
Chris@147 396 ++i;
Chris@300 397 ++got;
Chris@147 398
Chris@300 399 if (got == blockSize) {
Chris@1038 400 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 401 min = max = total = 0.0f;
Chris@300 402 got = 0;
Chris@147 403 }
Chris@147 404 }
Chris@147 405
Chris@377 406 m_directReadMutex.unlock();
Chris@377 407
Chris@300 408 if (got > 0) {
Chris@1038 409 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 410 }
Chris@147 411
Chris@225 412 return;
Chris@147 413
Chris@147 414 } else {
Chris@147 415
Chris@147 416 QMutexLocker locker(&m_mutex);
Chris@147 417
Chris@147 418 const RangeBlock &cache = m_cache[cacheType];
Chris@147 419
Chris@377 420 blockSize = roundedBlockSize;
Chris@377 421
Chris@1038 422 sv_frame_t cacheBlock, div;
Chris@1152 423
Chris@1152 424 cacheBlock = (sv_frame_t(1) << m_zoomConstraint.getMinCachePower());
Chris@1152 425 if (cacheType == 1) {
Chris@1152 426 cacheBlock = sv_frame_t(double(cacheBlock) * sqrt(2.) + 0.01);
Chris@147 427 }
Chris@1152 428 div = blockSize / cacheBlock;
Chris@147 429
Chris@1038 430 sv_frame_t startIndex = start / cacheBlock;
Chris@1038 431 sv_frame_t endIndex = (start + count) / cacheBlock;
Chris@147 432
Chris@147 433 float max = 0.0, min = 0.0, total = 0.0;
Chris@1038 434 sv_frame_t i = 0, got = 0;
Chris@147 435
Chris@236 436 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@300 437 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 438 #endif
Chris@147 439
Chris@300 440 for (i = 0; i <= endIndex - startIndex; ) {
Chris@147 441
Chris@1038 442 sv_frame_t index = (i + startIndex) * channels + channel;
Chris@1152 443 if (!in_range_for(cache, index)) break;
Chris@147 444
Chris@147 445 const Range &range = cache[index];
Chris@410 446 if (range.max() > max || got == 0) max = range.max();
Chris@410 447 if (range.min() < min || got == 0) min = range.min();
Chris@410 448 total += range.absmean();
Chris@147 449
Chris@147 450 ++i;
Chris@300 451 ++got;
Chris@147 452
Chris@300 453 if (got == div) {
Chris@1038 454 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 455 min = max = total = 0.0f;
Chris@300 456 got = 0;
Chris@147 457 }
Chris@147 458 }
Chris@147 459
Chris@300 460 if (got > 0) {
Chris@1038 461 ranges.push_back(Range(min, max, total / float(got)));
Chris@147 462 }
Chris@147 463 }
Chris@147 464
Chris@236 465 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1151 466 cerr << "returning " << ranges.size() << " ranges" << endl;
Chris@236 467 #endif
Chris@225 468 return;
Chris@147 469 }
Chris@147 470
Chris@1122 471 ReadOnlyWaveFileModel::Range
Chris@1122 472 ReadOnlyWaveFileModel::getSummary(int channel, sv_frame_t start, sv_frame_t count) const
Chris@147 473 {
Chris@147 474 Range range;
Chris@147 475 if (!isOK()) return range;
Chris@147 476
Chris@300 477 if (start > m_startFrame) start -= m_startFrame;
Chris@300 478 else if (count <= m_startFrame - start) return range;
Chris@300 479 else {
Chris@300 480 count -= (m_startFrame - start);
Chris@300 481 start = 0;
Chris@147 482 }
Chris@147 483
Chris@929 484 int blockSize;
Chris@300 485 for (blockSize = 1; blockSize <= count; blockSize *= 2);
Chris@300 486 if (blockSize > 1) blockSize /= 2;
Chris@147 487
Chris@147 488 bool first = false;
Chris@147 489
Chris@1038 490 sv_frame_t blockStart = (start / blockSize) * blockSize;
Chris@1038 491 sv_frame_t blockEnd = ((start + count) / blockSize) * blockSize;
Chris@147 492
Chris@147 493 if (blockStart < start) blockStart += blockSize;
Chris@147 494
Chris@147 495 if (blockEnd > blockStart) {
Chris@225 496 RangeBlock ranges;
Chris@300 497 getSummaries(channel, blockStart, blockEnd - blockStart, ranges, blockSize);
Chris@929 498 for (int i = 0; i < (int)ranges.size(); ++i) {
Chris@410 499 if (first || ranges[i].min() < range.min()) range.setMin(ranges[i].min());
Chris@410 500 if (first || ranges[i].max() > range.max()) range.setMax(ranges[i].max());
Chris@410 501 if (first || ranges[i].absmean() < range.absmean()) range.setAbsmean(ranges[i].absmean());
Chris@147 502 first = false;
Chris@147 503 }
Chris@147 504 }
Chris@147 505
Chris@147 506 if (blockStart > start) {
Chris@300 507 Range startRange = getSummary(channel, start, blockStart - start);
Chris@1096 508 range.setMin(min(range.min(), startRange.min()));
Chris@1096 509 range.setMax(max(range.max(), startRange.max()));
Chris@1096 510 range.setAbsmean(min(range.absmean(), startRange.absmean()));
Chris@147 511 }
Chris@147 512
Chris@300 513 if (blockEnd < start + count) {
Chris@300 514 Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
Chris@1096 515 range.setMin(min(range.min(), endRange.min()));
Chris@1096 516 range.setMax(max(range.max(), endRange.max()));
Chris@1096 517 range.setAbsmean(min(range.absmean(), endRange.absmean()));
Chris@147 518 }
Chris@147 519
Chris@147 520 return range;
Chris@147 521 }
Chris@147 522
Chris@147 523 void
Chris@1122 524 ReadOnlyWaveFileModel::fillCache()
Chris@147 525 {
Chris@147 526 m_mutex.lock();
Chris@188 527
Chris@147 528 m_updateTimer = new QTimer(this);
Chris@147 529 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
Chris@147 530 m_updateTimer->start(100);
Chris@188 531
Chris@147 532 m_fillThread = new RangeCacheFillThread(*this);
Chris@147 533 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
Chris@188 534
Chris@147 535 m_mutex.unlock();
Chris@147 536 m_fillThread->start();
Chris@188 537
Chris@236 538 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1122 539 SVDEBUG << "ReadOnlyWaveFileModel::fillCache: started fill thread" << endl;
Chris@236 540 #endif
Chris@147 541 }
Chris@147 542
Chris@147 543 void
Chris@1122 544 ReadOnlyWaveFileModel::fillTimerTimedOut()
Chris@147 545 {
Chris@147 546 if (m_fillThread) {
Chris@1038 547 sv_frame_t fillExtent = m_fillThread->getFillExtent();
Chris@236 548 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1122 549 SVDEBUG << "ReadOnlyWaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
Chris@236 550 #endif
Chris@147 551 if (fillExtent > m_lastFillExtent) {
Chris@931 552 emit modelChangedWithin(m_lastFillExtent, fillExtent);
Chris@147 553 m_lastFillExtent = fillExtent;
Chris@147 554 }
Chris@147 555 } else {
Chris@236 556 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1122 557 SVDEBUG << "ReadOnlyWaveFileModel::fillTimerTimedOut: no thread" << endl;
Chris@236 558 #endif
Chris@147 559 emit modelChanged();
Chris@147 560 }
Chris@147 561 }
Chris@147 562
Chris@147 563 void
Chris@1122 564 ReadOnlyWaveFileModel::cacheFilled()
Chris@147 565 {
Chris@147 566 m_mutex.lock();
Chris@147 567 delete m_fillThread;
Chris@147 568 m_fillThread = 0;
Chris@147 569 delete m_updateTimer;
Chris@147 570 m_updateTimer = 0;
Chris@147 571 m_mutex.unlock();
Chris@267 572 if (getEndFrame() > m_lastFillExtent) {
Chris@931 573 emit modelChangedWithin(m_lastFillExtent, getEndFrame());
Chris@267 574 }
Chris@147 575 emit modelChanged();
Chris@411 576 emit ready();
Chris@236 577 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1122 578 SVDEBUG << "ReadOnlyWaveFileModel::cacheFilled" << endl;
Chris@236 579 #endif
Chris@175 580 }
Chris@175 581
Chris@175 582 void
Chris@1122 583 ReadOnlyWaveFileModel::RangeCacheFillThread::run()
Chris@147 584 {
Chris@929 585 int cacheBlockSize[2];
Chris@179 586 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
Chris@1038 587 cacheBlockSize[1] = (int((1 << m_model.m_zoomConstraint.getMinCachePower()) *
Chris@608 588 sqrt(2.) + 0.01));
Chris@147 589
Chris@1038 590 sv_frame_t frame = 0;
Chris@1151 591 const sv_frame_t readBlockSize = 32768;
Chris@1096 592 vector<float> block;
Chris@147 593
Chris@147 594 if (!m_model.isOK()) return;
Chris@147 595
Chris@929 596 int channels = m_model.getChannelCount();
Chris@187 597 bool updating = m_model.m_reader->isUpdating();
Chris@187 598
Chris@187 599 if (updating) {
Chris@187 600 while (channels == 0 && !m_model.m_exiting) {
Chris@1151 601 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1151 602 cerr << "ReadOnlyWaveFileModel::fill: Waiting for channels..." << endl;
Chris@1151 603 #endif
Chris@187 604 sleep(1);
Chris@187 605 channels = m_model.getChannelCount();
Chris@187 606 }
Chris@187 607 }
Chris@147 608
Chris@147 609 Range *range = new Range[2 * channels];
Chris@410 610 float *means = new float[2 * channels];
Chris@929 611 int count[2];
Chris@147 612 count[0] = count[1] = 0;
Chris@411 613 for (int i = 0; i < 2 * channels; ++i) {
Chris@411 614 means[i] = 0.f;
Chris@411 615 }
Chris@176 616
Chris@176 617 bool first = true;
Chris@176 618
Chris@176 619 while (first || updating) {
Chris@176 620
Chris@176 621 updating = m_model.m_reader->isUpdating();
Chris@187 622 m_frameCount = m_model.getFrameCount();
Chris@175 623
Chris@1151 624 m_model.m_mutex.lock();
Chris@147 625
Chris@176 626 while (frame < m_frameCount) {
Chris@147 627
Chris@1151 628 m_model.m_mutex.unlock();
Chris@1151 629
Chris@1151 630 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1151 631 cerr << "ReadOnlyWaveFileModel::fill inner loop: frame = " << frame << ", count = " << m_frameCount << ", blocksize " << readBlockSize << endl;
Chris@1151 632 #endif
Chris@265 633
Chris@1220 634 if (updating && (frame + readBlockSize > m_frameCount)) {
Chris@1220 635 m_model.m_mutex.lock(); // must be locked on exiting loop
Chris@1220 636 break;
Chris@1220 637 }
Chris@176 638
Chris@1041 639 block = m_model.m_reader->getInterleavedFrames(frame, readBlockSize);
Chris@176 640
Chris@1151 641 sv_frame_t gotBlockSize = block.size() / channels;
Chris@265 642
Chris@1151 643 m_model.m_mutex.lock();
Chris@1151 644
Chris@1151 645 for (sv_frame_t i = 0; i < gotBlockSize; ++i) {
Chris@147 646
Chris@411 647 for (int ch = 0; ch < channels; ++ch) {
Chris@147 648
Chris@1038 649 sv_frame_t index = channels * i + ch;
Chris@176 650 float sample = block[index];
Chris@176 651
Chris@1151 652 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@1053 653 sv_frame_t rangeIndex = ch * 2 + cacheType;
Chris@1053 654 range[rangeIndex].sample(sample);
Chris@410 655 means[rangeIndex] += fabsf(sample);
Chris@176 656 }
Chris@176 657 }
Chris@1042 658
Chris@1053 659 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@232 660
Chris@1053 661 if (++count[cacheType] == cacheBlockSize[cacheType]) {
Chris@410 662
Chris@929 663 for (int ch = 0; ch < int(channels); ++ch) {
Chris@1053 664 int rangeIndex = ch * 2 + cacheType;
Chris@1053 665 means[rangeIndex] = means[rangeIndex] / float(count[cacheType]);
Chris@410 666 range[rangeIndex].setAbsmean(means[rangeIndex]);
Chris@1053 667 m_model.m_cache[cacheType].push_back(range[rangeIndex]);
Chris@176 668 range[rangeIndex] = Range();
Chris@411 669 means[rangeIndex] = 0.f;
Chris@176 670 }
Chris@232 671
Chris@1053 672 count[cacheType] = 0;
Chris@176 673 }
Chris@176 674 }
Chris@147 675
Chris@176 676 ++frame;
Chris@147 677 }
Chris@1151 678
Chris@176 679 if (m_model.m_exiting) break;
Chris@176 680 m_fillExtent = frame;
Chris@147 681 }
Chris@147 682
Chris@1151 683 m_model.m_mutex.unlock();
Chris@1151 684
Chris@176 685 first = false;
Chris@177 686 if (m_model.m_exiting) break;
Chris@187 687 if (updating) {
Chris@187 688 sleep(1);
Chris@187 689 }
Chris@147 690 }
Chris@147 691
Chris@177 692 if (!m_model.m_exiting) {
Chris@177 693
Chris@177 694 QMutexLocker locker(&m_model.m_mutex);
Chris@232 695
Chris@1053 696 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@232 697
Chris@1053 698 if (count[cacheType] > 0) {
Chris@232 699
Chris@929 700 for (int ch = 0; ch < int(channels); ++ch) {
Chris@1053 701 int rangeIndex = ch * 2 + cacheType;
Chris@1053 702 means[rangeIndex] = means[rangeIndex] / float(count[cacheType]);
Chris@410 703 range[rangeIndex].setAbsmean(means[rangeIndex]);
Chris@1053 704 m_model.m_cache[cacheType].push_back(range[rangeIndex]);
Chris@177 705 range[rangeIndex] = Range();
Chris@411 706 means[rangeIndex] = 0.f;
Chris@177 707 }
Chris@232 708
Chris@1053 709 count[cacheType] = 0;
Chris@147 710 }
Chris@177 711
Chris@1053 712 const Range &rr = *m_model.m_cache[cacheType].begin();
Chris@1053 713 MUNLOCK(&rr, m_model.m_cache[cacheType].capacity() * sizeof(Range));
Chris@147 714 }
Chris@147 715 }
Chris@147 716
Chris@410 717 delete[] means;
Chris@147 718 delete[] range;
Chris@147 719
Chris@175 720 m_fillExtent = m_frameCount;
Chris@236 721
Chris@236 722 #ifdef DEBUG_WAVE_FILE_MODEL
Chris@1053 723 for (int cacheType = 0; cacheType < 2; ++cacheType) {
Chris@1053 724 cerr << "Cache type " << cacheType << " now contains " << m_model.m_cache[cacheType].size() << " ranges" << endl;
Chris@236 725 }
Chris@236 726 #endif
Chris@147 727 }
Chris@147 728
Chris@163 729 void
Chris@1122 730 ReadOnlyWaveFileModel::toXml(QTextStream &out,
Chris@163 731 QString indent,
Chris@163 732 QString extraAttributes) const
Chris@163 733 {
Chris@163 734 Model::toXml(out, indent,
Chris@163 735 QString("type=\"wavefile\" file=\"%1\" %2")
Chris@279 736 .arg(encodeEntities(m_path)).arg(extraAttributes));
Chris@163 737 }
Chris@163 738
Chris@147 739