annotate data/fft/FFTFileCache.cpp @ 295:a2dc34ce146a

* Window should be centred on its nominal time. I'm not sure what the reasoning was behind the previous formulations of these two lines.
author Chris Cannam
date Thu, 06 Sep 2007 15:14:47 +0000
parents 92e8dbde73cd
children 7cc6b7b0d819
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@266 29 // [m_height * 2]. In compact mode, the factor takes two cells.
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@266 41 m_storageType(storageType),
Chris@266 42 m_factorSize(storageType == Compact ? 2 : 1)
Chris@148 43 {
Chris@259 44 // std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
Chris@148 45 }
Chris@148 46
Chris@148 47 FFTFileCache::~FFTFileCache()
Chris@148 48 {
Chris@148 49 if (m_readbuf) delete[] m_readbuf;
Chris@148 50 if (m_writebuf) delete[] m_writebuf;
Chris@148 51 delete m_mfc;
Chris@148 52 }
Chris@148 53
Chris@148 54 size_t
Chris@148 55 FFTFileCache::getWidth() const
Chris@148 56 {
Chris@148 57 return m_mfc->getWidth();
Chris@148 58 }
Chris@148 59
Chris@148 60 size_t
Chris@148 61 FFTFileCache::getHeight() const
Chris@148 62 {
Chris@148 63 size_t mh = m_mfc->getHeight();
Chris@266 64 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@148 65 else return 0;
Chris@148 66 }
Chris@148 67
Chris@148 68 void
Chris@148 69 FFTFileCache::resize(size_t width, size_t height)
Chris@148 70 {
Chris@148 71 QMutexLocker locker(&m_writeMutex);
Chris@148 72
Chris@266 73 m_mfc->resize(width, height * 2 + m_factorSize);
Chris@148 74 if (m_readbuf) {
Chris@148 75 delete[] m_readbuf;
Chris@148 76 m_readbuf = 0;
Chris@148 77 }
Chris@148 78 if (m_writebuf) {
Chris@148 79 delete[] m_writebuf;
Chris@148 80 }
Chris@266 81 m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()];
Chris@148 82 }
Chris@148 83
Chris@148 84 void
Chris@148 85 FFTFileCache::reset()
Chris@148 86 {
Chris@148 87 m_mfc->reset();
Chris@148 88 }
Chris@148 89
Chris@148 90 float
Chris@148 91 FFTFileCache::getMagnitudeAt(size_t x, size_t y) const
Chris@148 92 {
Chris@183 93 Profiler profiler("FFTFileCache::getMagnitudeAt", false);
Chris@183 94
Chris@148 95 float value = 0.f;
Chris@148 96
Chris@148 97 switch (m_storageType) {
Chris@148 98
Chris@148 99 case Compact:
Chris@148 100 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@148 101 * getNormalizationFactor(x);
Chris@148 102 break;
Chris@148 103
Chris@148 104 case Rectangular:
Chris@148 105 {
Chris@148 106 float real, imag;
Chris@148 107 getValuesAt(x, y, real, imag);
Chris@148 108 value = sqrtf(real * real + imag * imag);
Chris@148 109 break;
Chris@148 110 }
Chris@148 111
Chris@148 112 case Polar:
Chris@148 113 value = getFromReadBufStandard(x, y * 2);
Chris@148 114 break;
Chris@148 115 }
Chris@148 116
Chris@148 117 return value;
Chris@148 118 }
Chris@148 119
Chris@148 120 float
Chris@148 121 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@148 122 {
Chris@148 123 float value = 0.f;
Chris@148 124
Chris@148 125 switch (m_storageType) {
Chris@148 126
Chris@148 127 case Compact:
Chris@148 128 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@148 129 break;
Chris@148 130
Chris@148 131 default:
Chris@148 132 {
Chris@148 133 float mag = getMagnitudeAt(x, y);
Chris@148 134 float factor = getNormalizationFactor(x);
Chris@148 135 if (factor != 0) value = mag / factor;
Chris@148 136 else value = 0.f;
Chris@148 137 break;
Chris@148 138 }
Chris@148 139 }
Chris@148 140
Chris@148 141 return value;
Chris@148 142 }
Chris@148 143
Chris@148 144 float
Chris@148 145 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
Chris@148 146 {
Chris@148 147 return getNormalizationFactor(x);
Chris@148 148 }
Chris@148 149
Chris@148 150 float
Chris@148 151 FFTFileCache::getPhaseAt(size_t x, size_t y) const
Chris@148 152 {
Chris@148 153 float value = 0.f;
Chris@148 154
Chris@148 155 switch (m_storageType) {
Chris@148 156
Chris@148 157 case Compact:
Chris@148 158 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@148 159 break;
Chris@148 160
Chris@148 161 case Rectangular:
Chris@148 162 {
Chris@148 163 float real, imag;
Chris@148 164 getValuesAt(x, y, real, imag);
Chris@148 165 value = princargf(atan2f(imag, real));
Chris@148 166 break;
Chris@148 167 }
Chris@148 168
Chris@148 169 case Polar:
Chris@148 170 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 171 break;
Chris@148 172 }
Chris@148 173
Chris@148 174 return value;
Chris@148 175 }
Chris@148 176
Chris@148 177 void
Chris@148 178 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@148 179 {
Chris@148 180 switch (m_storageType) {
Chris@148 181
Chris@148 182 case Rectangular:
Chris@148 183 real = getFromReadBufStandard(x, y * 2);
Chris@148 184 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 185 return;
Chris@148 186
Chris@148 187 default:
Chris@148 188 float mag = getMagnitudeAt(x, y);
Chris@148 189 float phase = getPhaseAt(x, y);
Chris@148 190 real = mag * cosf(phase);
Chris@148 191 imag = mag * sinf(phase);
Chris@148 192 return;
Chris@148 193 }
Chris@148 194 }
Chris@148 195
Chris@148 196 bool
Chris@148 197 FFTFileCache::haveSetColumnAt(size_t x) const
Chris@148 198 {
Chris@148 199 return m_mfc->haveSetColumnAt(x);
Chris@148 200 }
Chris@148 201
Chris@148 202 void
Chris@148 203 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@148 204 {
Chris@148 205 QMutexLocker locker(&m_writeMutex);
Chris@148 206
Chris@148 207 size_t h = getHeight();
Chris@148 208
Chris@148 209 switch (m_storageType) {
Chris@148 210
Chris@148 211 case Compact:
Chris@148 212 for (size_t y = 0; y < h; ++y) {
Chris@148 213 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
Chris@148 214 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
Chris@148 215 }
Chris@148 216 break;
Chris@148 217
Chris@148 218 case Rectangular:
Chris@148 219 for (size_t y = 0; y < h; ++y) {
Chris@148 220 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
Chris@148 221 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
Chris@148 222 }
Chris@148 223 break;
Chris@148 224
Chris@148 225 case Polar:
Chris@148 226 for (size_t y = 0; y < h; ++y) {
Chris@148 227 ((float *)m_writebuf)[y * 2] = mags[y];
Chris@148 228 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
Chris@148 229 }
Chris@148 230 break;
Chris@148 231 }
Chris@148 232
Chris@266 233 // static float maxFactor = 0;
Chris@266 234 // if (factor > maxFactor) maxFactor = factor;
Chris@266 235 // std::cerr << "Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@148 236
Chris@266 237 setNormalizationFactorToWritebuf(factor);
Chris@266 238
Chris@148 239 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 240 }
Chris@148 241
Chris@148 242 void
Chris@148 243 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
Chris@148 244 {
Chris@148 245 QMutexLocker locker(&m_writeMutex);
Chris@148 246
Chris@148 247 size_t h = getHeight();
Chris@148 248
Chris@266 249 float factor = 0.0f;
Chris@148 250
Chris@148 251 switch (m_storageType) {
Chris@148 252
Chris@148 253 case Compact:
Chris@148 254 for (size_t y = 0; y < h; ++y) {
Chris@148 255 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 256 if (mag > factor) factor = mag;
Chris@148 257 }
Chris@148 258 for (size_t y = 0; y < h; ++y) {
Chris@148 259 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@148 260 float phase = princargf(atan2f(imag[y], real[y]));
Chris@266 261 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / factor) * 65535.0);
Chris@148 262 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@148 263 }
Chris@148 264 break;
Chris@148 265
Chris@148 266 case Rectangular:
Chris@148 267 for (size_t y = 0; y < h; ++y) {
Chris@148 268 ((float *)m_writebuf)[y * 2] = real[y];
Chris@148 269 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
Chris@148 270 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 271 if (mag > factor) factor = mag;
Chris@148 272 }
Chris@148 273 break;
Chris@148 274
Chris@148 275 case Polar:
Chris@148 276 for (size_t y = 0; y < h; ++y) {
Chris@148 277 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 278 if (mag > factor) factor = mag;
Chris@148 279 ((float *)m_writebuf)[y * 2] = mag;
Chris@290 280 float phase = princargf(atan2f(imag[y], real[y]));
Chris@290 281 ((float *)m_writebuf)[y * 2 + 1] = phase;
Chris@148 282 }
Chris@148 283 break;
Chris@148 284 }
Chris@148 285
Chris@266 286 // static float maxFactor = 0;
Chris@266 287 // if (factor > maxFactor) maxFactor = factor;
Chris@266 288 // std::cerr << "[RI] Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@266 289
Chris@266 290 setNormalizationFactorToWritebuf(factor);
Chris@266 291
Chris@148 292 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 293 }
Chris@148 294
Chris@170 295 size_t
Chris@170 296 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 297 {
Chris@266 298 return (height * 2 + (type == Compact ? 2 : 1)) * width *
Chris@170 299 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@170 300 2 * sizeof(size_t); // matrix file header size
Chris@170 301 }
Chris@170 302
Chris@183 303 void
Chris@183 304 FFTFileCache::populateReadBuf(size_t x) const
Chris@183 305 {
Chris@183 306 Profiler profiler("FFTFileCache::populateReadBuf", false);
Chris@183 307
Chris@183 308 if (!m_readbuf) {
Chris@183 309 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@183 310 }
Chris@183 311 m_mfc->getColumnAt(x, m_readbuf);
Chris@183 312 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@183 313 m_mfc->getColumnAt
Chris@183 314 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@183 315 m_readbufWidth = 2;
Chris@183 316 } else {
Chris@183 317 m_readbufWidth = 1;
Chris@183 318 }
Chris@183 319 m_readbufCol = x;
Chris@183 320 }
Chris@183 321