annotate data/model/WaveFileModel.cpp @ 0:fc9323a41f5a

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