annotate data/model/WaveFileModel.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents 61681a2bc1e6
children
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7 This file copyright 2006 Chris Cannam and QMUL.
lbajardsilogic@0 8
lbajardsilogic@0 9 This program is free software; you can redistribute it and/or
lbajardsilogic@0 10 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 11 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 12 License, or (at your option) any later version. See the file
lbajardsilogic@0 13 COPYING included with this distribution for more information.
lbajardsilogic@0 14 */
lbajardsilogic@0 15
lbajardsilogic@0 16 #include "WaveFileModel.h"
lbajardsilogic@0 17
lbajardsilogic@0 18 #include "fileio/AudioFileReader.h"
lbajardsilogic@0 19 #include "fileio/AudioFileReaderFactory.h"
lbajardsilogic@0 20
lbajardsilogic@0 21 #include "system/System.h"
lbajardsilogic@0 22
lbajardsilogic@0 23 #include <QMessageBox>
lbajardsilogic@0 24 #include <QFileInfo>
lbajardsilogic@0 25
lbajardsilogic@0 26 #include <iostream>
lbajardsilogic@0 27 //#include <unistd.h>
lbajardsilogic@0 28 #include <math.h>
lbajardsilogic@0 29 #include <sndfile.h>
lbajardsilogic@0 30
lbajardsilogic@0 31 #include <cassert>
lbajardsilogic@0 32
lbajardsilogic@0 33 //#define DEBUG_WAVE_FILE_MODEL 1
lbajardsilogic@0 34
lbajardsilogic@33 35 #include "main/MainWindow.h"
lbajardsilogic@33 36
lbajardsilogic@0 37 using std::cerr;
lbajardsilogic@0 38 using std::endl;
lbajardsilogic@0 39
lbajardsilogic@0 40 PowerOfSqrtTwoZoomConstraint
lbajardsilogic@0 41 WaveFileModel::m_zoomConstraint;
lbajardsilogic@0 42
lbajardsilogic@0 43 WaveFileModel::WaveFileModel(QString path) :
lbajardsilogic@0 44 m_path(path),
lbajardsilogic@0 45 m_myReader(true),
lbajardsilogic@0 46 m_fillThread(0),
lbajardsilogic@0 47 m_updateTimer(0),
lbajardsilogic@0 48 m_lastFillExtent(0),
lbajardsilogic@0 49 m_exiting(false)
lbajardsilogic@0 50 {
lbajardsilogic@33 51 MainWindow::instance()->setCursor(Qt::BusyCursor);
lbajardsilogic@33 52 MainWindow::instance()->statusBar()->showMessage(tr("Opening audio file..."));
lbajardsilogic@0 53 m_reader = AudioFileReaderFactory::createReader(path);
lbajardsilogic@0 54 setObjectName(QFileInfo(path).fileName());
lbajardsilogic@0 55 if (isOK()) fillCache();
lbajardsilogic@0 56 }
lbajardsilogic@0 57
lbajardsilogic@0 58 WaveFileModel::WaveFileModel(QString path, QString originalLocation) :
lbajardsilogic@0 59 m_path(originalLocation),
lbajardsilogic@0 60 m_myReader(true),
lbajardsilogic@0 61 m_fillThread(0),
lbajardsilogic@0 62 m_updateTimer(0),
lbajardsilogic@0 63 m_lastFillExtent(0),
lbajardsilogic@0 64 m_exiting(false)
lbajardsilogic@0 65 {
lbajardsilogic@0 66 m_reader = AudioFileReaderFactory::createReader(path);
lbajardsilogic@0 67 setObjectName(QFileInfo(originalLocation).fileName());
lbajardsilogic@0 68 if (isOK()) fillCache();
lbajardsilogic@0 69 }
lbajardsilogic@0 70
lbajardsilogic@0 71 WaveFileModel::WaveFileModel(QString path, AudioFileReader *reader) :
lbajardsilogic@0 72 m_path(path),
lbajardsilogic@0 73 m_myReader(false),
lbajardsilogic@0 74 m_fillThread(0),
lbajardsilogic@0 75 m_updateTimer(0),
lbajardsilogic@0 76 m_lastFillExtent(0),
lbajardsilogic@0 77 m_exiting(false)
lbajardsilogic@0 78 {
lbajardsilogic@0 79 m_reader = reader;
lbajardsilogic@0 80 setObjectName(QFileInfo(path).fileName());
lbajardsilogic@0 81 fillCache();
lbajardsilogic@0 82 }
lbajardsilogic@0 83
lbajardsilogic@0 84 WaveFileModel::~WaveFileModel()
lbajardsilogic@0 85 {
lbajardsilogic@0 86 m_exiting = true;
lbajardsilogic@0 87 if (m_fillThread) m_fillThread->wait();
lbajardsilogic@0 88 if (m_myReader) delete m_reader;
lbajardsilogic@0 89 m_reader = 0;
lbajardsilogic@0 90 }
lbajardsilogic@0 91
lbajardsilogic@0 92 bool
lbajardsilogic@0 93 WaveFileModel::isOK() const
lbajardsilogic@0 94 {
lbajardsilogic@0 95 return m_reader && m_reader->isOK();
lbajardsilogic@0 96 }
lbajardsilogic@0 97
lbajardsilogic@0 98 bool
lbajardsilogic@0 99 WaveFileModel::isReady(int *completion) const
lbajardsilogic@0 100 {
lbajardsilogic@0 101 bool ready = (isOK() && (m_fillThread == 0));
lbajardsilogic@0 102 double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
lbajardsilogic@0 103 if (completion) *completion = int(c * 100.0 + 0.01);
lbajardsilogic@0 104 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 105 std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl;
lbajardsilogic@0 106 #endif
lbajardsilogic@0 107 return ready;
lbajardsilogic@0 108 }
lbajardsilogic@0 109
lbajardsilogic@0 110 Model *
lbajardsilogic@0 111 WaveFileModel::clone() const
lbajardsilogic@0 112 {
lbajardsilogic@0 113 WaveFileModel *model = new WaveFileModel(m_path);
lbajardsilogic@0 114 return model;
lbajardsilogic@0 115 }
lbajardsilogic@0 116
lbajardsilogic@0 117 size_t
lbajardsilogic@0 118 WaveFileModel::getFrameCount() const
lbajardsilogic@0 119 {
lbajardsilogic@0 120 if (!m_reader) return 0;
lbajardsilogic@0 121 return m_reader->getFrameCount();
lbajardsilogic@0 122 }
lbajardsilogic@0 123
lbajardsilogic@0 124 size_t
lbajardsilogic@0 125 WaveFileModel::getChannelCount() const
lbajardsilogic@0 126 {
lbajardsilogic@0 127 if (!m_reader) return 0;
lbajardsilogic@0 128 return m_reader->getChannelCount();
lbajardsilogic@0 129 }
lbajardsilogic@0 130
lbajardsilogic@0 131 size_t
lbajardsilogic@0 132 WaveFileModel::getSampleRate() const
lbajardsilogic@0 133 {
lbajardsilogic@0 134 if (!m_reader) return 0;
lbajardsilogic@0 135 return m_reader->getSampleRate();
lbajardsilogic@0 136 }
lbajardsilogic@0 137
lbajardsilogic@0 138 size_t
lbajardsilogic@0 139 WaveFileModel::getValues(int channel, size_t start, size_t end,
lbajardsilogic@0 140 float *buffer) const
lbajardsilogic@0 141 {
lbajardsilogic@0 142 // Always read these directly from the file.
lbajardsilogic@0 143 // This is used for e.g. audio playback.
lbajardsilogic@0 144 // Could be much more efficient (although compiler optimisation will help)
lbajardsilogic@0 145
lbajardsilogic@0 146 if (end < start) {
lbajardsilogic@0 147 std::cerr << "ERROR: WaveFileModel::getValues[float]: end < start ("
lbajardsilogic@0 148 << end << " < " << start << ")" << std::endl;
lbajardsilogic@0 149 assert(end >= start);
lbajardsilogic@0 150 }
lbajardsilogic@0 151
lbajardsilogic@0 152 if (!m_reader || !m_reader->isOK()) return 0;
lbajardsilogic@0 153
lbajardsilogic@0 154 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 155 // std::cerr << "WaveFileModel::getValues(" << channel << ", "
lbajardsilogic@0 156 // << start << ", " << end << "): calling reader" << std::endl;
lbajardsilogic@0 157 #endif
lbajardsilogic@0 158
lbajardsilogic@0 159 SampleBlock frames;
lbajardsilogic@0 160 m_reader->getInterleavedFrames(start, end - start, frames);
lbajardsilogic@0 161
lbajardsilogic@0 162 size_t i = 0;
lbajardsilogic@0 163
lbajardsilogic@0 164 int ch0 = channel, ch1 = channel, channels = getChannelCount();
lbajardsilogic@0 165 if (channel == -1) {
lbajardsilogic@0 166 ch0 = 0;
lbajardsilogic@0 167 ch1 = channels - 1;
lbajardsilogic@0 168 }
lbajardsilogic@0 169
lbajardsilogic@0 170 while (i < end - start) {
lbajardsilogic@0 171
lbajardsilogic@0 172 buffer[i] = 0.0;
lbajardsilogic@0 173
lbajardsilogic@0 174 for (int ch = ch0; ch <= ch1; ++ch) {
lbajardsilogic@0 175
lbajardsilogic@0 176 size_t index = i * channels + ch;
lbajardsilogic@0 177 if (index >= frames.size()) break;
lbajardsilogic@0 178
lbajardsilogic@0 179 float sample = frames[index];
lbajardsilogic@0 180 buffer[i] += sample;
lbajardsilogic@0 181 }
lbajardsilogic@0 182
lbajardsilogic@0 183 ++i;
lbajardsilogic@0 184 }
lbajardsilogic@0 185
lbajardsilogic@0 186 return i;
lbajardsilogic@0 187 }
lbajardsilogic@0 188
lbajardsilogic@0 189 size_t
lbajardsilogic@0 190 WaveFileModel::getValues(int channel, size_t start, size_t end,
lbajardsilogic@0 191 double *buffer) const
lbajardsilogic@0 192 {
lbajardsilogic@0 193 if (end < start) {
lbajardsilogic@0 194 std::cerr << "ERROR: WaveFileModel::getValues[double]: end < start ("
lbajardsilogic@0 195 << end << " < " << start << ")" << std::endl;
lbajardsilogic@0 196 assert(end >= start);
lbajardsilogic@0 197 }
lbajardsilogic@0 198
lbajardsilogic@0 199 if (!m_reader || !m_reader->isOK()) return 0;
lbajardsilogic@0 200
lbajardsilogic@0 201 SampleBlock frames;
lbajardsilogic@0 202 m_reader->getInterleavedFrames(start, end - start, frames);
lbajardsilogic@0 203
lbajardsilogic@0 204 size_t i = 0;
lbajardsilogic@0 205
lbajardsilogic@0 206 int ch0 = channel, ch1 = channel, channels = getChannelCount();
lbajardsilogic@0 207 if (channel == -1) {
lbajardsilogic@0 208 ch0 = 0;
lbajardsilogic@0 209 ch1 = channels - 1;
lbajardsilogic@0 210 }
lbajardsilogic@0 211
lbajardsilogic@0 212 while (i < end - start) {
lbajardsilogic@0 213
lbajardsilogic@0 214 buffer[i] = 0.0;
lbajardsilogic@0 215
lbajardsilogic@0 216 for (int ch = ch0; ch <= ch1; ++ch) {
lbajardsilogic@0 217
lbajardsilogic@0 218 size_t index = i * channels + ch;
lbajardsilogic@0 219 if (index >= frames.size()) break;
lbajardsilogic@0 220
lbajardsilogic@0 221 float sample = frames[index];
lbajardsilogic@0 222 buffer[i] += sample;
lbajardsilogic@0 223 }
lbajardsilogic@0 224
lbajardsilogic@0 225 ++i;
lbajardsilogic@0 226 }
lbajardsilogic@0 227
lbajardsilogic@0 228 return i;
lbajardsilogic@0 229 }
lbajardsilogic@0 230
lbajardsilogic@0 231 void
lbajardsilogic@0 232 WaveFileModel::getRanges(size_t channel, size_t start, size_t end,
lbajardsilogic@0 233 RangeBlock &ranges, size_t &blockSize) const
lbajardsilogic@0 234 {
lbajardsilogic@0 235 ranges.clear();
lbajardsilogic@0 236 if (!isOK()) return;
lbajardsilogic@0 237
lbajardsilogic@0 238 if (end <= start) {
lbajardsilogic@0 239 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRanges (end = " << end << ", start = " << start << ", blocksize = " << blockSize << ")" << std::endl;
lbajardsilogic@0 240 return;
lbajardsilogic@0 241 }
lbajardsilogic@0 242
lbajardsilogic@0 243 int cacheType = 0;
lbajardsilogic@0 244 int power = m_zoomConstraint.getMinCachePower();
lbajardsilogic@0 245 blockSize = m_zoomConstraint.getNearestBlockSize
lbajardsilogic@0 246 (blockSize, cacheType, power, ZoomConstraint::RoundUp);
lbajardsilogic@0 247
lbajardsilogic@0 248 size_t channels = getChannelCount();
lbajardsilogic@0 249
lbajardsilogic@0 250 if (cacheType != 0 && cacheType != 1) {
lbajardsilogic@0 251
lbajardsilogic@0 252 // We need to read directly from the file. We haven't got
lbajardsilogic@0 253 // this cached. Hope the requested area is small. This is
lbajardsilogic@0 254 // not optimal -- we'll end up reading the same frames twice
lbajardsilogic@0 255 // for stereo files, in two separate calls to this method.
lbajardsilogic@0 256 // We could fairly trivially handle this for most cases that
lbajardsilogic@0 257 // matter by putting a single cache in getInterleavedFrames
lbajardsilogic@0 258 // for short queries.
lbajardsilogic@0 259
lbajardsilogic@0 260 SampleBlock frames;
lbajardsilogic@0 261 m_reader->getInterleavedFrames(start, end - start, frames);
lbajardsilogic@0 262 float max = 0.0, min = 0.0, total = 0.0;
lbajardsilogic@0 263 size_t i = 0, count = 0;
lbajardsilogic@0 264
lbajardsilogic@0 265 while (i < end - start) {
lbajardsilogic@0 266
lbajardsilogic@0 267 size_t index = i * channels + channel;
lbajardsilogic@0 268 if (index >= frames.size()) break;
lbajardsilogic@0 269
lbajardsilogic@0 270 float sample = frames[index];
lbajardsilogic@0 271 if (sample > max || count == 0) max = sample;
lbajardsilogic@0 272 if (sample < min || count == 0) min = sample;
lbajardsilogic@0 273 total += fabsf(sample);
lbajardsilogic@0 274
lbajardsilogic@0 275 ++i;
lbajardsilogic@0 276 ++count;
lbajardsilogic@0 277
lbajardsilogic@0 278 if (count == blockSize) {
lbajardsilogic@0 279 ranges.push_back(Range(min, max, total / count));
lbajardsilogic@0 280 min = max = total = 0.0f;
lbajardsilogic@0 281 count = 0;
lbajardsilogic@0 282 }
lbajardsilogic@0 283 }
lbajardsilogic@0 284
lbajardsilogic@0 285 if (count > 0) {
lbajardsilogic@0 286 ranges.push_back(Range(min, max, total / count));
lbajardsilogic@0 287 }
lbajardsilogic@0 288
lbajardsilogic@0 289 return;
lbajardsilogic@0 290
lbajardsilogic@0 291 } else {
lbajardsilogic@0 292
lbajardsilogic@0 293 QMutexLocker locker(&m_mutex);
lbajardsilogic@0 294
lbajardsilogic@0 295 const RangeBlock &cache = m_cache[cacheType];
lbajardsilogic@0 296
lbajardsilogic@0 297 size_t cacheBlock, div;
lbajardsilogic@0 298
lbajardsilogic@0 299 if (cacheType == 0) {
lbajardsilogic@0 300 cacheBlock = (1 << m_zoomConstraint.getMinCachePower());
lbajardsilogic@0 301 div = (1 << power) / cacheBlock;
lbajardsilogic@0 302 } else {
lbajardsilogic@0 303 cacheBlock = ((unsigned int)((1 << m_zoomConstraint.getMinCachePower()) * sqrt(2.0) + 0.01));
lbajardsilogic@0 304 div = ((unsigned int)((1 << power) * sqrt(2.0) + 0.01)) / cacheBlock;
lbajardsilogic@0 305 }
lbajardsilogic@0 306
lbajardsilogic@0 307 size_t startIndex = start / cacheBlock;
lbajardsilogic@0 308 size_t endIndex = end / cacheBlock;
lbajardsilogic@0 309
lbajardsilogic@0 310 float max = 0.0, min = 0.0, total = 0.0;
lbajardsilogic@0 311 size_t i = 0, count = 0;
lbajardsilogic@0 312
lbajardsilogic@0 313 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 314 cerr << "blockSize is " << blockSize << ", cacheBlock " << cacheBlock << ", start " << start << ", end " << end << " (frame count " << getFrameCount() << "), power is " << power << ", div is " << div << ", startIndex " << startIndex << ", endIndex " << endIndex << endl;
lbajardsilogic@0 315 #endif
lbajardsilogic@0 316
lbajardsilogic@0 317 for (i = 0; i < endIndex - startIndex; ) {
lbajardsilogic@0 318
lbajardsilogic@0 319 size_t index = (i + startIndex) * channels + channel;
lbajardsilogic@0 320 if (index >= cache.size()) break;
lbajardsilogic@0 321
lbajardsilogic@0 322 const Range &range = cache[index];
lbajardsilogic@0 323 if (range.max > max || count == 0) max = range.max;
lbajardsilogic@0 324 if (range.min < min || count == 0) min = range.min;
lbajardsilogic@0 325 total += range.absmean;
lbajardsilogic@0 326
lbajardsilogic@0 327 ++i;
lbajardsilogic@0 328 ++count;
lbajardsilogic@0 329
lbajardsilogic@0 330 if (count == div) {
lbajardsilogic@0 331 ranges.push_back(Range(min, max, total / count));
lbajardsilogic@0 332 min = max = total = 0.0f;
lbajardsilogic@0 333 count = 0;
lbajardsilogic@0 334 }
lbajardsilogic@0 335 }
lbajardsilogic@0 336
lbajardsilogic@0 337 if (count > 0) {
lbajardsilogic@0 338 ranges.push_back(Range(min, max, total / count));
lbajardsilogic@0 339 }
lbajardsilogic@0 340 }
lbajardsilogic@0 341
lbajardsilogic@0 342 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 343 cerr << "returning " << ranges.size() << " ranges" << endl;
lbajardsilogic@0 344 #endif
lbajardsilogic@0 345 return;
lbajardsilogic@0 346 }
lbajardsilogic@0 347
lbajardsilogic@0 348 WaveFileModel::Range
lbajardsilogic@0 349 WaveFileModel::getRange(size_t channel, size_t start, size_t end) const
lbajardsilogic@0 350 {
lbajardsilogic@0 351 Range range;
lbajardsilogic@0 352 if (!isOK()) return range;
lbajardsilogic@0 353
lbajardsilogic@0 354 if (end <= start) {
lbajardsilogic@0 355 std::cerr << "WARNING: Internal error: end <= start in WaveFileModel::getRange (end = " << end << ", start = " << start << ")" << std::endl;
lbajardsilogic@0 356 return range;
lbajardsilogic@0 357 }
lbajardsilogic@0 358
lbajardsilogic@0 359 size_t blockSize;
lbajardsilogic@0 360 for (blockSize = 1; blockSize <= end - start; blockSize *= 2);
lbajardsilogic@0 361 blockSize /= 2;
lbajardsilogic@0 362
lbajardsilogic@0 363 bool first = false;
lbajardsilogic@0 364
lbajardsilogic@0 365 size_t blockStart = (start / blockSize) * blockSize;
lbajardsilogic@0 366 size_t blockEnd = (end / blockSize) * blockSize;
lbajardsilogic@0 367
lbajardsilogic@0 368 if (blockStart < start) blockStart += blockSize;
lbajardsilogic@0 369
lbajardsilogic@0 370 if (blockEnd > blockStart) {
lbajardsilogic@0 371 RangeBlock ranges;
lbajardsilogic@0 372 getRanges(channel, blockStart, blockEnd, ranges, blockSize);
lbajardsilogic@0 373 for (size_t i = 0; i < ranges.size(); ++i) {
lbajardsilogic@0 374 if (first || ranges[i].min < range.min) range.min = ranges[i].min;
lbajardsilogic@0 375 if (first || ranges[i].max > range.max) range.max = ranges[i].max;
lbajardsilogic@0 376 if (first || ranges[i].absmean < range.absmean) range.absmean = ranges[i].absmean;
lbajardsilogic@0 377 first = false;
lbajardsilogic@0 378 }
lbajardsilogic@0 379 }
lbajardsilogic@0 380
lbajardsilogic@0 381 if (blockStart > start) {
lbajardsilogic@0 382 Range startRange = getRange(channel, start, blockStart);
lbajardsilogic@190 383 range.min = MIN(range.min, startRange.min);
lbajardsilogic@190 384 range.max = MAX(range.max, startRange.max);
lbajardsilogic@190 385 range.absmean = MIN(range.absmean, startRange.absmean);
lbajardsilogic@0 386 }
lbajardsilogic@0 387
lbajardsilogic@0 388 if (blockEnd < end) {
lbajardsilogic@0 389 Range endRange = getRange(channel, blockEnd, end);
lbajardsilogic@190 390 range.min = MIN(range.min, endRange.min);
lbajardsilogic@190 391 range.max = MAX(range.max, endRange.max);
lbajardsilogic@190 392 range.absmean = MIN(range.absmean, endRange.absmean);
lbajardsilogic@0 393 }
lbajardsilogic@0 394
lbajardsilogic@0 395 return range;
lbajardsilogic@0 396 }
lbajardsilogic@0 397
lbajardsilogic@0 398 void
lbajardsilogic@0 399 WaveFileModel::fillCache()
lbajardsilogic@0 400 {
lbajardsilogic@0 401 m_mutex.lock();
lbajardsilogic@0 402
lbajardsilogic@0 403 m_updateTimer = new QTimer(this);
lbajardsilogic@0 404 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
lbajardsilogic@0 405 m_updateTimer->start(100);
lbajardsilogic@0 406
lbajardsilogic@0 407 m_fillThread = new RangeCacheFillThread(*this);
lbajardsilogic@0 408 connect(m_fillThread, SIGNAL(finished()), this, SLOT(cacheFilled()));
lbajardsilogic@0 409
lbajardsilogic@0 410 m_mutex.unlock();
lbajardsilogic@0 411 m_fillThread->start();
lbajardsilogic@0 412
lbajardsilogic@0 413 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 414 std::cerr << "WaveFileModel::fillCache: started fill thread" << std::endl;
lbajardsilogic@0 415 #endif
lbajardsilogic@0 416 }
lbajardsilogic@0 417
lbajardsilogic@0 418 void
lbajardsilogic@0 419 WaveFileModel::fillTimerTimedOut()
lbajardsilogic@0 420 {
lbajardsilogic@0 421 if (m_fillThread) {
lbajardsilogic@0 422 size_t fillExtent = m_fillThread->getFillExtent();
lbajardsilogic@0 423 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 424 cerr << "WaveFileModel::fillTimerTimedOut: extent = " << fillExtent << endl;
lbajardsilogic@0 425 #endif
lbajardsilogic@0 426 if (fillExtent > m_lastFillExtent) {
lbajardsilogic@0 427 emit modelChanged(m_lastFillExtent, fillExtent);
lbajardsilogic@0 428 m_lastFillExtent = fillExtent;
lbajardsilogic@0 429 }
lbajardsilogic@0 430 } else {
lbajardsilogic@0 431 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 432 cerr << "WaveFileModel::fillTimerTimedOut: no thread" << std::endl;
lbajardsilogic@0 433 #endif
lbajardsilogic@0 434 emit modelChanged();
lbajardsilogic@0 435 }
lbajardsilogic@0 436 }
lbajardsilogic@0 437
lbajardsilogic@0 438 void
lbajardsilogic@0 439 WaveFileModel::cacheFilled()
lbajardsilogic@0 440 {
lbajardsilogic@33 441 MainWindow::instance()->setCursor(Qt::ArrowCursor);
lbajardsilogic@33 442 MainWindow::instance()->statusBar()->clearMessage();
lbajardsilogic@0 443 m_mutex.lock();
lbajardsilogic@0 444 delete m_fillThread;
lbajardsilogic@0 445 m_fillThread = 0;
lbajardsilogic@0 446 delete m_updateTimer;
lbajardsilogic@0 447 m_updateTimer = 0;
lbajardsilogic@0 448 m_mutex.unlock();
lbajardsilogic@0 449 emit modelChanged();
lbajardsilogic@0 450 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 451 cerr << "WaveFileModel::cacheFilled" << endl;
lbajardsilogic@0 452 #endif
lbajardsilogic@0 453 }
lbajardsilogic@0 454
lbajardsilogic@0 455 void
lbajardsilogic@0 456 WaveFileModel::RangeCacheFillThread::run()
lbajardsilogic@0 457 {
lbajardsilogic@0 458 size_t cacheBlockSize[2];
lbajardsilogic@0 459 cacheBlockSize[0] = (1 << m_model.m_zoomConstraint.getMinCachePower());
lbajardsilogic@0 460 cacheBlockSize[1] = ((unsigned int)((1 << m_model.m_zoomConstraint.getMinCachePower()) *
lbajardsilogic@0 461 sqrt(2.0) + 0.01));
lbajardsilogic@0 462
lbajardsilogic@0 463 size_t frame = 0;
lbajardsilogic@0 464 size_t readBlockSize = 16384;
lbajardsilogic@0 465 SampleBlock block;
lbajardsilogic@0 466
lbajardsilogic@0 467 if (!m_model.isOK()) return;
lbajardsilogic@0 468
lbajardsilogic@0 469 size_t channels = m_model.getChannelCount();
lbajardsilogic@0 470 bool updating = m_model.m_reader->isUpdating();
lbajardsilogic@0 471
lbajardsilogic@0 472 if (updating) {
lbajardsilogic@0 473 while (channels == 0 && !m_model.m_exiting) {
lbajardsilogic@0 474 // std::cerr << "WaveFileModel::fill: Waiting for channels..." << std::endl;
lbajardsilogic@0 475 sleep(1);
lbajardsilogic@0 476 channels = m_model.getChannelCount();
lbajardsilogic@0 477 }
lbajardsilogic@0 478 }
lbajardsilogic@0 479
lbajardsilogic@0 480 Range *range = new Range[2 * channels];
lbajardsilogic@0 481 size_t count[2];
lbajardsilogic@0 482 count[0] = count[1] = 0;
lbajardsilogic@0 483
lbajardsilogic@0 484 bool first = true;
lbajardsilogic@0 485
lbajardsilogic@0 486 while (first || updating) {
lbajardsilogic@0 487
lbajardsilogic@0 488 updating = m_model.m_reader->isUpdating();
lbajardsilogic@0 489 m_frameCount = m_model.getFrameCount();
lbajardsilogic@0 490
lbajardsilogic@0 491 // std::cerr << "WaveFileModel::fill: frame = " << frame << ", count = " << m_frameCount << std::endl;
lbajardsilogic@0 492
lbajardsilogic@0 493 while (frame < m_frameCount) {
lbajardsilogic@0 494
lbajardsilogic@0 495 if (updating && (frame + readBlockSize > m_frameCount)) break;
lbajardsilogic@0 496
lbajardsilogic@0 497 m_model.m_reader->getInterleavedFrames(frame, readBlockSize, block);
lbajardsilogic@0 498
lbajardsilogic@0 499 for (size_t i = 0; i < readBlockSize; ++i) {
lbajardsilogic@0 500
lbajardsilogic@0 501 if (channels * i + channels > block.size()) break;
lbajardsilogic@0 502
lbajardsilogic@0 503 for (size_t ch = 0; ch < size_t(channels); ++ch) {
lbajardsilogic@0 504
lbajardsilogic@0 505 size_t index = channels * i + ch;
lbajardsilogic@0 506 float sample = block[index];
lbajardsilogic@0 507
lbajardsilogic@0 508 for (size_t ct = 0; ct < 2; ++ct) { // cache type
lbajardsilogic@0 509
lbajardsilogic@0 510 size_t rangeIndex = ch * 2 + ct;
lbajardsilogic@0 511
lbajardsilogic@0 512 if (sample > range[rangeIndex].max || count[ct] == 0) {
lbajardsilogic@0 513 range[rangeIndex].max = sample;
lbajardsilogic@0 514 }
lbajardsilogic@0 515 if (sample < range[rangeIndex].min || count[ct] == 0) {
lbajardsilogic@0 516 range[rangeIndex].min = sample;
lbajardsilogic@0 517 }
lbajardsilogic@0 518 range[rangeIndex].absmean += fabsf(sample);
lbajardsilogic@0 519 }
lbajardsilogic@0 520 }
lbajardsilogic@0 521
lbajardsilogic@0 522 QMutexLocker locker(&m_model.m_mutex);
lbajardsilogic@0 523
lbajardsilogic@0 524 for (size_t ct = 0; ct < 2; ++ct) {
lbajardsilogic@0 525
lbajardsilogic@0 526 if (++count[ct] == cacheBlockSize[ct]) {
lbajardsilogic@0 527
lbajardsilogic@0 528 for (size_t ch = 0; ch < size_t(channels); ++ch) {
lbajardsilogic@0 529 size_t rangeIndex = ch * 2 + ct;
lbajardsilogic@0 530 range[rangeIndex].absmean /= count[ct];
lbajardsilogic@0 531 m_model.m_cache[ct].push_back(range[rangeIndex]);
lbajardsilogic@0 532 range[rangeIndex] = Range();
lbajardsilogic@0 533 }
lbajardsilogic@0 534
lbajardsilogic@0 535 count[ct] = 0;
lbajardsilogic@0 536 }
lbajardsilogic@0 537 }
lbajardsilogic@0 538
lbajardsilogic@0 539 ++frame;
lbajardsilogic@0 540 }
lbajardsilogic@0 541
lbajardsilogic@0 542 if (m_model.m_exiting) break;
lbajardsilogic@0 543
lbajardsilogic@0 544 m_fillExtent = frame;
lbajardsilogic@0 545 }
lbajardsilogic@0 546
lbajardsilogic@0 547 first = false;
lbajardsilogic@0 548 if (m_model.m_exiting) break;
lbajardsilogic@0 549 if (updating) {
lbajardsilogic@0 550 sleep(1);
lbajardsilogic@0 551 }
lbajardsilogic@0 552 }
lbajardsilogic@0 553
lbajardsilogic@0 554 if (!m_model.m_exiting) {
lbajardsilogic@0 555
lbajardsilogic@0 556 QMutexLocker locker(&m_model.m_mutex);
lbajardsilogic@0 557
lbajardsilogic@0 558 for (size_t ct = 0; ct < 2; ++ct) {
lbajardsilogic@0 559
lbajardsilogic@0 560 if (count[ct] > 0) {
lbajardsilogic@0 561
lbajardsilogic@0 562 for (size_t ch = 0; ch < size_t(channels); ++ch) {
lbajardsilogic@0 563 size_t rangeIndex = ch * 2 + ct;
lbajardsilogic@0 564 range[rangeIndex].absmean /= count[ct];
lbajardsilogic@0 565 m_model.m_cache[ct].push_back(range[rangeIndex]);
lbajardsilogic@0 566 range[rangeIndex] = Range();
lbajardsilogic@0 567 }
lbajardsilogic@0 568
lbajardsilogic@0 569 count[ct] = 0;
lbajardsilogic@0 570 }
lbajardsilogic@0 571
lbajardsilogic@0 572 const Range &rr = *m_model.m_cache[ct].begin();
lbajardsilogic@0 573 MUNLOCK(&rr, m_model.m_cache[ct].capacity() * sizeof(Range));
lbajardsilogic@0 574 }
lbajardsilogic@0 575 }
lbajardsilogic@0 576
lbajardsilogic@0 577 delete[] range;
lbajardsilogic@0 578
lbajardsilogic@0 579 m_fillExtent = m_frameCount;
lbajardsilogic@0 580
lbajardsilogic@0 581 #ifdef DEBUG_WAVE_FILE_MODEL
lbajardsilogic@0 582 for (size_t ct = 0; ct < 2; ++ct) {
lbajardsilogic@0 583 cerr << "Cache type " << ct << " now contains " << m_model.m_cache[ct].size() << " ranges" << endl;
lbajardsilogic@0 584 }
lbajardsilogic@0 585 #endif
lbajardsilogic@0 586 }
lbajardsilogic@0 587
lbajardsilogic@0 588 void
lbajardsilogic@0 589 WaveFileModel::toXml(QTextStream &out,
lbajardsilogic@0 590 QString indent,
lbajardsilogic@0 591 QString extraAttributes) const
lbajardsilogic@0 592 {
lbajardsilogic@0 593 Model::toXml(out, indent,
lbajardsilogic@0 594 QString("type=\"wavefile\" file=\"%1\" %2")
lbajardsilogic@0 595 .arg(m_path).arg(extraAttributes));
lbajardsilogic@0 596 }
lbajardsilogic@0 597
lbajardsilogic@0 598 QString
lbajardsilogic@0 599 WaveFileModel::toXmlString(QString indent,
lbajardsilogic@0 600 QString extraAttributes) const
lbajardsilogic@0 601 {
lbajardsilogic@0 602 return Model::toXmlString(indent,
lbajardsilogic@0 603 QString("type=\"wavefile\" file=\"%1\" %2")
lbajardsilogic@0 604 .arg(m_path).arg(extraAttributes));
lbajardsilogic@0 605 }
lbajardsilogic@0 606