annotate data/fileio/FFTFileCache.cpp @ 157:c03ec31005e1

* Add zoom thumbwheels to Pane. Implement horizontal thumbwheel, and vertical depending on layer type (supported for waveform and spectrogram, though wrong for log-scale spectrogram at the moment). * Add bare bones of a spectrum layer. * Add window icon * Add shortcut for "insert time instant" on laptops without keypad enter (";") * Delete FFT processing thread when it exits (at least, next time we're asked for something interesting) * Get audio file extensions from the file readers, and thus from libsndfile for the wave file reader -- leads to rather a wide combo box in file dialog though * Better refresh order for spectrogram (redraw centre section first)
author Chris Cannam
date Fri, 04 Aug 2006 17:01:37 +0000
parents 1a42221a1522
children
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@148 7 This file copyright 2006 Chris Cannam.
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@148 18 #include "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@148 92 float value = 0.f;
Chris@148 93
Chris@148 94 switch (m_storageType) {
Chris@148 95
Chris@148 96 case Compact:
Chris@148 97 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@148 98 * getNormalizationFactor(x);
Chris@148 99 break;
Chris@148 100
Chris@148 101 case Rectangular:
Chris@148 102 {
Chris@148 103 float real, imag;
Chris@148 104 getValuesAt(x, y, real, imag);
Chris@148 105 value = sqrtf(real * real + imag * imag);
Chris@148 106 break;
Chris@148 107 }
Chris@148 108
Chris@148 109 case Polar:
Chris@148 110 value = getFromReadBufStandard(x, y * 2);
Chris@148 111 break;
Chris@148 112 }
Chris@148 113
Chris@148 114 return value;
Chris@148 115 }
Chris@148 116
Chris@148 117 float
Chris@148 118 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@148 119 {
Chris@148 120 float value = 0.f;
Chris@148 121
Chris@148 122 switch (m_storageType) {
Chris@148 123
Chris@148 124 case Compact:
Chris@148 125 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@148 126 break;
Chris@148 127
Chris@148 128 default:
Chris@148 129 {
Chris@148 130 float mag = getMagnitudeAt(x, y);
Chris@148 131 float factor = getNormalizationFactor(x);
Chris@148 132 if (factor != 0) value = mag / factor;
Chris@148 133 else value = 0.f;
Chris@148 134 break;
Chris@148 135 }
Chris@148 136 }
Chris@148 137
Chris@148 138 return value;
Chris@148 139 }
Chris@148 140
Chris@148 141 float
Chris@148 142 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
Chris@148 143 {
Chris@148 144 return getNormalizationFactor(x);
Chris@148 145 }
Chris@148 146
Chris@148 147 float
Chris@148 148 FFTFileCache::getPhaseAt(size_t x, size_t y) const
Chris@148 149 {
Chris@148 150 float value = 0.f;
Chris@148 151
Chris@148 152 switch (m_storageType) {
Chris@148 153
Chris@148 154 case Compact:
Chris@148 155 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@148 156 break;
Chris@148 157
Chris@148 158 case Rectangular:
Chris@148 159 {
Chris@148 160 float real, imag;
Chris@148 161 getValuesAt(x, y, real, imag);
Chris@148 162 value = princargf(atan2f(imag, real));
Chris@148 163 break;
Chris@148 164 }
Chris@148 165
Chris@148 166 case Polar:
Chris@148 167 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 168 break;
Chris@148 169 }
Chris@148 170
Chris@148 171 return value;
Chris@148 172 }
Chris@148 173
Chris@148 174 void
Chris@148 175 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@148 176 {
Chris@148 177 switch (m_storageType) {
Chris@148 178
Chris@148 179 case Rectangular:
Chris@148 180 real = getFromReadBufStandard(x, y * 2);
Chris@148 181 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 182 return;
Chris@148 183
Chris@148 184 default:
Chris@148 185 float mag = getMagnitudeAt(x, y);
Chris@148 186 float phase = getPhaseAt(x, y);
Chris@148 187 real = mag * cosf(phase);
Chris@148 188 imag = mag * sinf(phase);
Chris@148 189 return;
Chris@148 190 }
Chris@148 191 }
Chris@148 192
Chris@148 193 bool
Chris@148 194 FFTFileCache::haveSetColumnAt(size_t x) const
Chris@148 195 {
Chris@148 196 return m_mfc->haveSetColumnAt(x);
Chris@148 197 }
Chris@148 198
Chris@148 199 void
Chris@148 200 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@148 201 {
Chris@148 202 QMutexLocker locker(&m_writeMutex);
Chris@148 203
Chris@148 204 size_t h = getHeight();
Chris@148 205
Chris@148 206 switch (m_storageType) {
Chris@148 207
Chris@148 208 case Compact:
Chris@148 209 for (size_t y = 0; y < h; ++y) {
Chris@148 210 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
Chris@148 211 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
Chris@148 212 }
Chris@148 213 break;
Chris@148 214
Chris@148 215 case Rectangular:
Chris@148 216 for (size_t y = 0; y < h; ++y) {
Chris@148 217 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
Chris@148 218 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
Chris@148 219 }
Chris@148 220 break;
Chris@148 221
Chris@148 222 case Polar:
Chris@148 223 for (size_t y = 0; y < h; ++y) {
Chris@148 224 ((float *)m_writebuf)[y * 2] = mags[y];
Chris@148 225 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
Chris@148 226 }
Chris@148 227 break;
Chris@148 228 }
Chris@148 229
Chris@148 230 static float maxFactor = 0;
Chris@148 231 if (factor > maxFactor) maxFactor = factor;
Chris@148 232 // std::cerr << "Normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@148 233
Chris@148 234 if (m_storageType == Compact) {
Chris@148 235 ((uint16_t *)m_writebuf)[h * 2] = factor * 65535.0;
Chris@148 236 } else {
Chris@148 237 ((float *)m_writebuf)[h * 2] = factor;
Chris@148 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@148 249 float max = 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@148 256 if (mag > max) max = 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@148 261 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / max) * 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@148 271 if (mag > max) max = 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@148 278 if (mag > max) max = mag;
Chris@148 279 ((float *)m_writebuf)[y * 2] = mag;
Chris@148 280 ((float *)m_writebuf)[y * 2 + 1] = princargf(atan2f(imag[y], real[y]));
Chris@148 281 }
Chris@148 282 break;
Chris@148 283 }
Chris@148 284
Chris@148 285 ((float *)m_writebuf)[h * 2] = max;
Chris@148 286 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 287 }
Chris@148 288