annotate data/fft/FFTFileCache.cpp @ 217:b3dfc3714006

* Fix a crash in spectrogram * Don't clear background of curved area of thumbwheel (this way it looks better on a dark background)
author Chris Cannam
date Mon, 22 Jan 2007 16:09:03 +0000
parents 91fdc752e540
children dc46851837d6
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@148 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@148 237 ((uint16_t *)m_writebuf)[h * 2] = factor * 65535.0;
Chris@148 238 } else {
Chris@148 239 ((float *)m_writebuf)[h * 2] = factor;
Chris@148 240 }
Chris@148 241 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 242 }
Chris@148 243
Chris@148 244 void
Chris@148 245 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
Chris@148 246 {
Chris@148 247 QMutexLocker locker(&m_writeMutex);
Chris@148 248
Chris@148 249 size_t h = getHeight();
Chris@148 250
Chris@148 251 float max = 0.0f;
Chris@148 252
Chris@148 253 switch (m_storageType) {
Chris@148 254
Chris@148 255 case Compact:
Chris@148 256 for (size_t y = 0; y < h; ++y) {
Chris@148 257 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 258 if (mag > max) max = mag;
Chris@148 259 }
Chris@148 260 for (size_t y = 0; y < h; ++y) {
Chris@148 261 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 262 float phase = princargf(atan2f(imag[y], real[y]));
Chris@148 263 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / max) * 65535.0);
Chris@148 264 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@148 265 }
Chris@148 266 break;
Chris@148 267
Chris@148 268 case Rectangular:
Chris@148 269 for (size_t y = 0; y < h; ++y) {
Chris@148 270 ((float *)m_writebuf)[y * 2] = real[y];
Chris@148 271 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
Chris@148 272 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 273 if (mag > max) max = mag;
Chris@148 274 }
Chris@148 275 break;
Chris@148 276
Chris@148 277 case Polar:
Chris@148 278 for (size_t y = 0; y < h; ++y) {
Chris@148 279 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 280 if (mag > max) max = mag;
Chris@148 281 ((float *)m_writebuf)[y * 2] = mag;
Chris@148 282 ((float *)m_writebuf)[y * 2 + 1] = princargf(atan2f(imag[y], real[y]));
Chris@148 283 }
Chris@148 284 break;
Chris@148 285 }
Chris@148 286
Chris@148 287 ((float *)m_writebuf)[h * 2] = max;
Chris@148 288 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 289 }
Chris@148 290
Chris@170 291 size_t
Chris@170 292 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 293 {
Chris@170 294 return (height * 2 + 1) * width *
Chris@170 295 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@170 296 2 * sizeof(size_t); // matrix file header size
Chris@170 297 }
Chris@170 298
Chris@183 299 void
Chris@183 300 FFTFileCache::populateReadBuf(size_t x) const
Chris@183 301 {
Chris@183 302 Profiler profiler("FFTFileCache::populateReadBuf", false);
Chris@183 303
Chris@183 304 if (!m_readbuf) {
Chris@183 305 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@183 306 }
Chris@183 307 m_mfc->getColumnAt(x, m_readbuf);
Chris@183 308 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@183 309 m_mfc->getColumnAt
Chris@183 310 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@183 311 m_readbufWidth = 2;
Chris@183 312 } else {
Chris@183 313 m_readbufWidth = 1;
Chris@183 314 }
Chris@183 315 m_readbufCol = x;
Chris@183 316 }
Chris@183 317