annotate data/model/ReadOnlyWaveFileModel.cpp @ 1455:ec9e65fcf749

The use of the begin/end pairs here just seems to cause too many rows to be deleted (from the visual representation, not the underlying model). Things apparently work better if we just modify the underlying model and let the change signals percolate back up again. To that end, update the change handlers so as to cover their proper ranges with dataChanged signals.
author Chris Cannam
date Mon, 23 Apr 2018 16:03:35 +0100
parents 87ae75da6527
children 0925b37a3ed1
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@1428 222 SVCERR << "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@1428 281 SVCERR << "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@1428 288 SVCERR << "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