annotate data/fft/FFTFileCache.cpp @ 263:71dfc6ab3b54

* Threaded mp3/ogg file reading. Not activated yet, as it doesn't work in context (SV needs to know the duration of its main model at the outset)
author Chris Cannam
date Thu, 24 May 2007 16:20:22 +0000
parents dc46851837d6
children 2268963dabd1
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #include "FFTFileCache.h"
Chris@148 17
Chris@150 18 #include "fileio/MatrixFile.h"
Chris@148 19
Chris@148 20 #include "base/Profiler.h"
Chris@148 21
Chris@148 22 #include <iostream>
Chris@148 23
Chris@148 24 #include <QMutexLocker>
Chris@148 25
Chris@148 26 // The underlying matrix has height (m_height * 2 + 1). In each
Chris@148 27 // column we store magnitude at [0], [2] etc and phase at [1], [3]
Chris@148 28 // etc, and then store the normalization factor (maximum magnitude) at
Chris@148 29 // [m_height * 2].
Chris@148 30
Chris@148 31 FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode,
Chris@148 32 StorageType storageType) :
Chris@148 33 m_writebuf(0),
Chris@148 34 m_readbuf(0),
Chris@148 35 m_readbufCol(0),
Chris@148 36 m_readbufWidth(0),
Chris@148 37 m_mfc(new MatrixFile
Chris@148 38 (fileBase, mode,
Chris@148 39 storageType == Compact ? sizeof(uint16_t) : sizeof(float),
Chris@148 40 mode == MatrixFile::ReadOnly)),
Chris@148 41 m_storageType(storageType)
Chris@148 42 {
Chris@259 43 // std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
Chris@148 44 }
Chris@148 45
Chris@148 46 FFTFileCache::~FFTFileCache()
Chris@148 47 {
Chris@148 48 if (m_readbuf) delete[] m_readbuf;
Chris@148 49 if (m_writebuf) delete[] m_writebuf;
Chris@148 50 delete m_mfc;
Chris@148 51 }
Chris@148 52
Chris@148 53 size_t
Chris@148 54 FFTFileCache::getWidth() const
Chris@148 55 {
Chris@148 56 return m_mfc->getWidth();
Chris@148 57 }
Chris@148 58
Chris@148 59 size_t
Chris@148 60 FFTFileCache::getHeight() const
Chris@148 61 {
Chris@148 62 size_t mh = m_mfc->getHeight();
Chris@148 63 if (mh > 0) return (mh - 1) / 2;
Chris@148 64 else return 0;
Chris@148 65 }
Chris@148 66
Chris@148 67 void
Chris@148 68 FFTFileCache::resize(size_t width, size_t height)
Chris@148 69 {
Chris@148 70 QMutexLocker locker(&m_writeMutex);
Chris@148 71
Chris@148 72 m_mfc->resize(width, height * 2 + 1);
Chris@148 73 if (m_readbuf) {
Chris@148 74 delete[] m_readbuf;
Chris@148 75 m_readbuf = 0;
Chris@148 76 }
Chris@148 77 if (m_writebuf) {
Chris@148 78 delete[] m_writebuf;
Chris@148 79 }
Chris@148 80 m_writebuf = new char[(height * 2 + 1) * m_mfc->getCellSize()];
Chris@148 81 }
Chris@148 82
Chris@148 83 void
Chris@148 84 FFTFileCache::reset()
Chris@148 85 {
Chris@148 86 m_mfc->reset();
Chris@148 87 }
Chris@148 88
Chris@148 89 float
Chris@148 90 FFTFileCache::getMagnitudeAt(size_t x, size_t y) const
Chris@148 91 {
Chris@183 92 Profiler profiler("FFTFileCache::getMagnitudeAt", false);
Chris@183 93
Chris@148 94 float value = 0.f;
Chris@148 95
Chris@148 96 switch (m_storageType) {
Chris@148 97
Chris@148 98 case Compact:
Chris@148 99 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@148 100 * getNormalizationFactor(x);
Chris@148 101 break;
Chris@148 102
Chris@148 103 case Rectangular:
Chris@148 104 {
Chris@148 105 float real, imag;
Chris@148 106 getValuesAt(x, y, real, imag);
Chris@148 107 value = sqrtf(real * real + imag * imag);
Chris@148 108 break;
Chris@148 109 }
Chris@148 110
Chris@148 111 case Polar:
Chris@148 112 value = getFromReadBufStandard(x, y * 2);
Chris@148 113 break;
Chris@148 114 }
Chris@148 115
Chris@148 116 return value;
Chris@148 117 }
Chris@148 118
Chris@148 119 float
Chris@148 120 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@148 121 {
Chris@148 122 float value = 0.f;
Chris@148 123
Chris@148 124 switch (m_storageType) {
Chris@148 125
Chris@148 126 case Compact:
Chris@148 127 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@148 128 break;
Chris@148 129
Chris@148 130 default:
Chris@148 131 {
Chris@148 132 float mag = getMagnitudeAt(x, y);
Chris@148 133 float factor = getNormalizationFactor(x);
Chris@148 134 if (factor != 0) value = mag / factor;
Chris@148 135 else value = 0.f;
Chris@148 136 break;
Chris@148 137 }
Chris@148 138 }
Chris@148 139
Chris@148 140 return value;
Chris@148 141 }
Chris@148 142
Chris@148 143 float
Chris@148 144 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
Chris@148 145 {
Chris@148 146 return getNormalizationFactor(x);
Chris@148 147 }
Chris@148 148
Chris@148 149 float
Chris@148 150 FFTFileCache::getPhaseAt(size_t x, size_t y) const
Chris@148 151 {
Chris@148 152 float value = 0.f;
Chris@148 153
Chris@148 154 switch (m_storageType) {
Chris@148 155
Chris@148 156 case Compact:
Chris@148 157 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@148 158 break;
Chris@148 159
Chris@148 160 case Rectangular:
Chris@148 161 {
Chris@148 162 float real, imag;
Chris@148 163 getValuesAt(x, y, real, imag);
Chris@148 164 value = princargf(atan2f(imag, real));
Chris@148 165 break;
Chris@148 166 }
Chris@148 167
Chris@148 168 case Polar:
Chris@148 169 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 170 break;
Chris@148 171 }
Chris@148 172
Chris@148 173 return value;
Chris@148 174 }
Chris@148 175
Chris@148 176 void
Chris@148 177 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@148 178 {
Chris@148 179 switch (m_storageType) {
Chris@148 180
Chris@148 181 case Rectangular:
Chris@148 182 real = getFromReadBufStandard(x, y * 2);
Chris@148 183 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 184 return;
Chris@148 185
Chris@148 186 default:
Chris@148 187 float mag = getMagnitudeAt(x, y);
Chris@148 188 float phase = getPhaseAt(x, y);
Chris@148 189 real = mag * cosf(phase);
Chris@148 190 imag = mag * sinf(phase);
Chris@148 191 return;
Chris@148 192 }
Chris@148 193 }
Chris@148 194
Chris@148 195 bool
Chris@148 196 FFTFileCache::haveSetColumnAt(size_t x) const
Chris@148 197 {
Chris@148 198 return m_mfc->haveSetColumnAt(x);
Chris@148 199 }
Chris@148 200
Chris@148 201 void
Chris@148 202 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@148 203 {
Chris@148 204 QMutexLocker locker(&m_writeMutex);
Chris@148 205
Chris@148 206 size_t h = getHeight();
Chris@148 207
Chris@148 208 switch (m_storageType) {
Chris@148 209
Chris@148 210 case Compact:
Chris@148 211 for (size_t y = 0; y < h; ++y) {
Chris@148 212 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
Chris@148 213 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
Chris@148 214 }
Chris@148 215 break;
Chris@148 216
Chris@148 217 case Rectangular:
Chris@148 218 for (size_t y = 0; y < h; ++y) {
Chris@148 219 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
Chris@148 220 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
Chris@148 221 }
Chris@148 222 break;
Chris@148 223
Chris@148 224 case Polar:
Chris@148 225 for (size_t y = 0; y < h; ++y) {
Chris@148 226 ((float *)m_writebuf)[y * 2] = mags[y];
Chris@148 227 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
Chris@148 228 }
Chris@148 229 break;
Chris@148 230 }
Chris@148 231
Chris@148 232 static float maxFactor = 0;
Chris@148 233 if (factor > maxFactor) maxFactor = factor;
Chris@148 234 // std::cerr << "Normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@148 235
Chris@148 236 if (m_storageType == Compact) {
Chris@259 237 if (factor < 0.f || factor > 1.f) {
Chris@259 238 std::cerr << "WARNING: FFTFileCache::setColumnAt: Normalization factor " << factor << " out of range" << std::endl;
Chris@259 239 if (factor < 0.f) factor = 0.f;
Chris@259 240 if (factor > 1.f) factor = 1.f;
Chris@259 241 }
Chris@259 242 ((uint16_t *)m_writebuf)[h * 2] = (uint16_t)(factor * 65535.0);
Chris@148 243 } else {
Chris@148 244 ((float *)m_writebuf)[h * 2] = factor;
Chris@148 245 }
Chris@148 246 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 247 }
Chris@148 248
Chris@148 249 void
Chris@148 250 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
Chris@148 251 {
Chris@148 252 QMutexLocker locker(&m_writeMutex);
Chris@148 253
Chris@148 254 size_t h = getHeight();
Chris@148 255
Chris@148 256 float max = 0.0f;
Chris@148 257
Chris@148 258 switch (m_storageType) {
Chris@148 259
Chris@148 260 case Compact:
Chris@148 261 for (size_t y = 0; y < h; ++y) {
Chris@148 262 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 263 if (mag > max) max = mag;
Chris@148 264 }
Chris@148 265 for (size_t y = 0; y < h; ++y) {
Chris@148 266 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 267 float phase = princargf(atan2f(imag[y], real[y]));
Chris@148 268 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / max) * 65535.0);
Chris@148 269 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@148 270 }
Chris@148 271 break;
Chris@148 272
Chris@148 273 case Rectangular:
Chris@148 274 for (size_t y = 0; y < h; ++y) {
Chris@148 275 ((float *)m_writebuf)[y * 2] = real[y];
Chris@148 276 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
Chris@148 277 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 278 if (mag > max) max = mag;
Chris@148 279 }
Chris@148 280 break;
Chris@148 281
Chris@148 282 case Polar:
Chris@148 283 for (size_t y = 0; y < h; ++y) {
Chris@148 284 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 285 if (mag > max) max = mag;
Chris@148 286 ((float *)m_writebuf)[y * 2] = mag;
Chris@148 287 ((float *)m_writebuf)[y * 2 + 1] = princargf(atan2f(imag[y], real[y]));
Chris@148 288 }
Chris@148 289 break;
Chris@148 290 }
Chris@148 291
Chris@148 292 ((float *)m_writebuf)[h * 2] = max;
Chris@148 293 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 294 }
Chris@148 295
Chris@170 296 size_t
Chris@170 297 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 298 {
Chris@170 299 return (height * 2 + 1) * width *
Chris@170 300 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@170 301 2 * sizeof(size_t); // matrix file header size
Chris@170 302 }
Chris@170 303
Chris@183 304 void
Chris@183 305 FFTFileCache::populateReadBuf(size_t x) const
Chris@183 306 {
Chris@183 307 Profiler profiler("FFTFileCache::populateReadBuf", false);
Chris@183 308
Chris@183 309 if (!m_readbuf) {
Chris@183 310 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@183 311 }
Chris@183 312 m_mfc->getColumnAt(x, m_readbuf);
Chris@183 313 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@183 314 m_mfc->getColumnAt
Chris@183 315 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@183 316 m_readbufWidth = 2;
Chris@183 317 } else {
Chris@183 318 m_readbufWidth = 1;
Chris@183 319 }
Chris@183 320 m_readbufCol = x;
Chris@183 321 }
Chris@183 322