annotate data/fft/FFTFileCache.cpp @ 301:73537d900d4b

* Add MIDI file export (closes FR#1643721)
author Chris Cannam
date Thu, 04 Oct 2007 11:52:38 +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