annotate data/fft/FFTFileCacheReader.cpp @ 823:f0558e69a074

Rename Resampling- to DecodingWavFileReader, and use it whenever we have an audio file that is not quickly seekable using libsndfile. Avoids very slow performance when analysing ogg files.
author Chris Cannam
date Wed, 17 Jul 2013 15:40:01 +0100
parents 1424aa29ae95
children e802e550a1f2
rev   line source
Chris@537 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@537 2
Chris@537 3 /*
Chris@537 4 Sonic Visualiser
Chris@537 5 An audio file viewer and annotation editor.
Chris@537 6 Centre for Digital Music, Queen Mary, University of London.
Chris@537 7 This file copyright 2006-2009 Chris Cannam and QMUL.
Chris@537 8
Chris@537 9 This program is free software; you can redistribute it and/or
Chris@537 10 modify it under the terms of the GNU General Public License as
Chris@537 11 published by the Free Software Foundation; either version 2 of the
Chris@537 12 License, or (at your option) any later version. See the file
Chris@537 13 COPYING included with this distribution for more information.
Chris@537 14 */
Chris@537 15
Chris@537 16 #include "FFTFileCacheReader.h"
Chris@537 17 #include "FFTFileCacheWriter.h"
Chris@537 18
Chris@537 19 #include "fileio/MatrixFile.h"
Chris@537 20
Chris@537 21 #include "base/Profiler.h"
Chris@537 22 #include "base/Thread.h"
Chris@537 23 #include "base/Exceptions.h"
Chris@537 24
Chris@537 25 #include <iostream>
Chris@537 26
Chris@537 27
Chris@537 28 // The underlying matrix has height (m_height * 2 + 1). In each
Chris@537 29 // column we store magnitude at [0], [2] etc and phase at [1], [3]
Chris@537 30 // etc, and then store the normalization factor (maximum magnitude) at
Chris@537 31 // [m_height * 2]. In compact mode, the factor takes two cells.
Chris@537 32
Chris@537 33 FFTFileCacheReader::FFTFileCacheReader(FFTFileCacheWriter *writer) :
Chris@537 34 m_readbuf(0),
Chris@537 35 m_readbufCol(0),
Chris@537 36 m_readbufWidth(0),
Chris@555 37 m_readbufGood(false),
Chris@537 38 m_storageType(writer->getStorageType()),
Chris@537 39 m_factorSize(m_storageType == FFTCache::Compact ? 2 : 1),
Chris@537 40 m_mfc(new MatrixFile
Chris@537 41 (writer->getFileBase(),
Chris@537 42 MatrixFile::ReadOnly,
Chris@537 43 m_storageType == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float),
Chris@537 44 writer->getWidth(),
Chris@537 45 writer->getHeight() * 2 + m_factorSize))
Chris@537 46 {
Chris@537 47 // std::cerr << "FFTFileCacheReader: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
Chris@537 48 }
Chris@537 49
Chris@537 50 FFTFileCacheReader::~FFTFileCacheReader()
Chris@537 51 {
Chris@537 52 if (m_readbuf) delete[] m_readbuf;
Chris@537 53 delete m_mfc;
Chris@537 54 }
Chris@537 55
Chris@537 56 size_t
Chris@537 57 FFTFileCacheReader::getWidth() const
Chris@537 58 {
Chris@537 59 return m_mfc->getWidth();
Chris@537 60 }
Chris@537 61
Chris@537 62 size_t
Chris@537 63 FFTFileCacheReader::getHeight() const
Chris@537 64 {
Chris@537 65 size_t mh = m_mfc->getHeight();
Chris@537 66 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@537 67 else return 0;
Chris@537 68 }
Chris@537 69
Chris@537 70 float
Chris@537 71 FFTFileCacheReader::getMagnitudeAt(size_t x, size_t y) const
Chris@537 72 {
Chris@537 73 Profiler profiler("FFTFileCacheReader::getMagnitudeAt", false);
Chris@537 74
Chris@537 75 float value = 0.f;
Chris@537 76
Chris@537 77 switch (m_storageType) {
Chris@537 78
Chris@537 79 case FFTCache::Compact:
Chris@537 80 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 81 * getNormalizationFactor(x);
Chris@537 82 break;
Chris@537 83
Chris@537 84 case FFTCache::Rectangular:
Chris@537 85 {
Chris@537 86 float real, imag;
Chris@537 87 getValuesAt(x, y, real, imag);
Chris@537 88 value = sqrtf(real * real + imag * imag);
Chris@537 89 break;
Chris@537 90 }
Chris@537 91
Chris@537 92 case FFTCache::Polar:
Chris@537 93 value = getFromReadBufStandard(x, y * 2);
Chris@537 94 break;
Chris@537 95 }
Chris@537 96
Chris@537 97 return value;
Chris@537 98 }
Chris@537 99
Chris@537 100 float
Chris@537 101 FFTFileCacheReader::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@537 102 {
Chris@537 103 float value = 0.f;
Chris@537 104
Chris@537 105 switch (m_storageType) {
Chris@537 106
Chris@537 107 case FFTCache::Compact:
Chris@537 108 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@537 109 break;
Chris@537 110
Chris@537 111 default:
Chris@537 112 {
Chris@537 113 float mag = getMagnitudeAt(x, y);
Chris@537 114 float factor = getNormalizationFactor(x);
Chris@537 115 if (factor != 0) value = mag / factor;
Chris@537 116 else value = 0.f;
Chris@537 117 break;
Chris@537 118 }
Chris@537 119 }
Chris@537 120
Chris@537 121 return value;
Chris@537 122 }
Chris@537 123
Chris@537 124 float
Chris@537 125 FFTFileCacheReader::getMaximumMagnitudeAt(size_t x) const
Chris@537 126 {
Chris@537 127 return getNormalizationFactor(x);
Chris@537 128 }
Chris@537 129
Chris@537 130 float
Chris@537 131 FFTFileCacheReader::getPhaseAt(size_t x, size_t y) const
Chris@537 132 {
Chris@537 133 float value = 0.f;
Chris@537 134
Chris@537 135 switch (m_storageType) {
Chris@537 136
Chris@537 137 case FFTCache::Compact:
Chris@537 138 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@537 139 break;
Chris@537 140
Chris@537 141 case FFTCache::Rectangular:
Chris@537 142 {
Chris@537 143 float real, imag;
Chris@537 144 getValuesAt(x, y, real, imag);
Chris@537 145 value = atan2f(imag, real);
Chris@537 146 break;
Chris@537 147 }
Chris@537 148
Chris@537 149 case FFTCache::Polar:
Chris@537 150 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 151 break;
Chris@537 152 }
Chris@537 153
Chris@537 154 return value;
Chris@537 155 }
Chris@537 156
Chris@537 157 void
Chris@537 158 FFTFileCacheReader::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@537 159 {
Chris@690 160 // SVDEBUG << "FFTFileCacheReader::getValuesAt(" << x << "," << y << ")" << endl;
Chris@555 161
Chris@537 162 switch (m_storageType) {
Chris@537 163
Chris@537 164 case FFTCache::Rectangular:
Chris@537 165 real = getFromReadBufStandard(x, y * 2);
Chris@537 166 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 167 return;
Chris@537 168
Chris@537 169 default:
Chris@537 170 float mag = getMagnitudeAt(x, y);
Chris@537 171 float phase = getPhaseAt(x, y);
Chris@537 172 real = mag * cosf(phase);
Chris@537 173 imag = mag * sinf(phase);
Chris@537 174 return;
Chris@537 175 }
Chris@537 176 }
Chris@537 177
Chris@537 178 void
Chris@537 179 FFTFileCacheReader::getMagnitudesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) const
Chris@537 180 {
Chris@537 181 Profiler profiler("FFTFileCacheReader::getMagnitudesAt");
Chris@537 182
Chris@537 183 switch (m_storageType) {
Chris@537 184
Chris@537 185 case FFTCache::Compact:
Chris@537 186 for (size_t i = 0; i < count; ++i) {
Chris@537 187 size_t y = minbin + i * step;
Chris@537 188 values[i] = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 189 * getNormalizationFactor(x);
Chris@537 190 }
Chris@537 191 break;
Chris@537 192
Chris@537 193 case FFTCache::Rectangular:
Chris@537 194 {
Chris@537 195 float real, imag;
Chris@537 196 for (size_t i = 0; i < count; ++i) {
Chris@537 197 size_t y = minbin + i * step;
Chris@537 198 real = getFromReadBufStandard(x, y * 2);
Chris@537 199 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 200 values[i] = sqrtf(real * real + imag * imag);
Chris@537 201 }
Chris@537 202 break;
Chris@537 203 }
Chris@537 204
Chris@537 205 case FFTCache::Polar:
Chris@537 206 for (size_t i = 0; i < count; ++i) {
Chris@537 207 size_t y = minbin + i * step;
Chris@537 208 values[i] = getFromReadBufStandard(x, y * 2);
Chris@537 209 }
Chris@537 210 break;
Chris@537 211 }
Chris@537 212 }
Chris@537 213
Chris@537 214 bool
Chris@537 215 FFTFileCacheReader::haveSetColumnAt(size_t x) const
Chris@537 216 {
Chris@555 217 if (m_readbuf && m_readbufGood &&
Chris@555 218 (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
Chris@690 219 // SVDEBUG << "FFTFileCacheReader::haveSetColumnAt: short-circuiting; we know about this one" << endl;
Chris@555 220 return true;
Chris@555 221 }
Chris@537 222 return m_mfc->haveSetColumnAt(x);
Chris@537 223 }
Chris@537 224
Chris@537 225 size_t
Chris@537 226 FFTFileCacheReader::getCacheSize(size_t width, size_t height,
Chris@537 227 FFTCache::StorageType type)
Chris@537 228 {
Chris@537 229 return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width *
Chris@537 230 (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@537 231 2 * sizeof(size_t); // matrix file header size
Chris@537 232 }
Chris@537 233
Chris@537 234 void
Chris@537 235 FFTFileCacheReader::populateReadBuf(size_t x) const
Chris@537 236 {
Chris@537 237 Profiler profiler("FFTFileCacheReader::populateReadBuf", false);
Chris@537 238
Chris@690 239 // SVDEBUG << "FFTFileCacheReader::populateReadBuf(" << x << ")" << endl;
Chris@554 240
Chris@537 241 if (!m_readbuf) {
Chris@537 242 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@537 243 }
Chris@537 244
Chris@555 245 m_readbufGood = false;
Chris@555 246
Chris@537 247 try {
Chris@555 248 bool good = false;
Chris@555 249 if (m_mfc->haveSetColumnAt(x)) {
Chris@555 250 // If the column is not available, we have no obligation
Chris@555 251 // to do anything with the readbuf -- we can cheerfully
Chris@555 252 // return garbage. It's the responsibility of the caller
Chris@555 253 // to check haveSetColumnAt before trusting any retrieved
Chris@555 254 // data. However, we do record whether the data in the
Chris@555 255 // readbuf is good or not, because we can use that to
Chris@555 256 // return an immediate result for haveSetColumnAt if the
Chris@555 257 // column is right.
Chris@555 258 good = true;
Chris@555 259 m_mfc->getColumnAt(x, m_readbuf);
Chris@555 260 }
Chris@537 261 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@537 262 m_mfc->getColumnAt
Chris@537 263 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@537 264 m_readbufWidth = 2;
Chris@537 265 } else {
Chris@537 266 m_readbufWidth = 1;
Chris@537 267 }
Chris@555 268 m_readbufGood = good;
Chris@537 269 } catch (FileReadFailed f) {
Chris@537 270 std::cerr << "ERROR: FFTFileCacheReader::populateReadBuf: File read failed: "
Chris@537 271 << f.what() << std::endl;
Chris@537 272 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize());
Chris@537 273 }
Chris@537 274 m_readbufCol = x;
Chris@537 275 }
Chris@537 276