annotate data/fft/FFTFileCache.cpp @ 474:6d45f77e63ee

* Ensure that region features are added even if they lack any values!
author Chris Cannam
date Wed, 29 Oct 2008 12:37:32 +0000
parents f60360209e5c
children 6066bde1c126
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@408 21 #include "base/Thread.h"
Chris@455 22 #include "base/Exceptions.h"
Chris@148 23
Chris@148 24 #include <iostream>
Chris@148 25
Chris@374 26
Chris@148 27 // The underlying matrix has height (m_height * 2 + 1). In each
Chris@148 28 // column we store magnitude at [0], [2] etc and phase at [1], [3]
Chris@148 29 // etc, and then store the normalization factor (maximum magnitude) at
Chris@266 30 // [m_height * 2]. In compact mode, the factor takes two cells.
Chris@148 31
Chris@148 32 FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode,
Chris@148 33 StorageType storageType) :
Chris@148 34 m_writebuf(0),
Chris@148 35 m_readbuf(0),
Chris@148 36 m_readbufCol(0),
Chris@148 37 m_readbufWidth(0),
Chris@148 38 m_mfc(new MatrixFile
Chris@148 39 (fileBase, mode,
Chris@148 40 storageType == Compact ? sizeof(uint16_t) : sizeof(float),
Chris@148 41 mode == MatrixFile::ReadOnly)),
Chris@266 42 m_storageType(storageType),
Chris@266 43 m_factorSize(storageType == Compact ? 2 : 1)
Chris@148 44 {
Chris@259 45 // std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
Chris@148 46 }
Chris@148 47
Chris@148 48 FFTFileCache::~FFTFileCache()
Chris@148 49 {
Chris@148 50 if (m_readbuf) delete[] m_readbuf;
Chris@148 51 if (m_writebuf) delete[] m_writebuf;
Chris@148 52 delete m_mfc;
Chris@148 53 }
Chris@148 54
Chris@148 55 size_t
Chris@148 56 FFTFileCache::getWidth() const
Chris@148 57 {
Chris@148 58 return m_mfc->getWidth();
Chris@148 59 }
Chris@148 60
Chris@148 61 size_t
Chris@148 62 FFTFileCache::getHeight() const
Chris@148 63 {
Chris@148 64 size_t mh = m_mfc->getHeight();
Chris@266 65 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@148 66 else return 0;
Chris@148 67 }
Chris@148 68
Chris@148 69 void
Chris@148 70 FFTFileCache::resize(size_t width, size_t height)
Chris@148 71 {
Chris@408 72 MutexLocker locker(&m_writeMutex, "FFTFileCache::resize::m_writeMutex");
Chris@148 73
Chris@266 74 m_mfc->resize(width, height * 2 + m_factorSize);
Chris@458 75
Chris@458 76 {
Chris@458 77 MutexLocker locker(&m_readbufMutex, "FFTFileCache::resize::m_readMutex");
Chris@458 78 if (m_readbuf) {
Chris@458 79 delete[] m_readbuf;
Chris@458 80 m_readbuf = 0;
Chris@458 81 }
Chris@148 82 }
Chris@458 83
Chris@148 84 if (m_writebuf) {
Chris@148 85 delete[] m_writebuf;
Chris@148 86 }
Chris@266 87 m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()];
Chris@148 88 }
Chris@458 89
Chris@148 90 void
Chris@148 91 FFTFileCache::reset()
Chris@148 92 {
Chris@148 93 m_mfc->reset();
Chris@148 94 }
Chris@148 95
Chris@148 96 float
Chris@148 97 FFTFileCache::getMagnitudeAt(size_t x, size_t y) const
Chris@148 98 {
Chris@183 99 Profiler profiler("FFTFileCache::getMagnitudeAt", false);
Chris@183 100
Chris@148 101 float value = 0.f;
Chris@148 102
Chris@148 103 switch (m_storageType) {
Chris@148 104
Chris@148 105 case Compact:
Chris@148 106 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@148 107 * getNormalizationFactor(x);
Chris@148 108 break;
Chris@148 109
Chris@148 110 case Rectangular:
Chris@148 111 {
Chris@148 112 float real, imag;
Chris@148 113 getValuesAt(x, y, real, imag);
Chris@148 114 value = sqrtf(real * real + imag * imag);
Chris@148 115 break;
Chris@148 116 }
Chris@148 117
Chris@148 118 case Polar:
Chris@148 119 value = getFromReadBufStandard(x, y * 2);
Chris@148 120 break;
Chris@148 121 }
Chris@148 122
Chris@148 123 return value;
Chris@148 124 }
Chris@148 125
Chris@148 126 float
Chris@148 127 FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@148 128 {
Chris@148 129 float value = 0.f;
Chris@148 130
Chris@148 131 switch (m_storageType) {
Chris@148 132
Chris@148 133 case Compact:
Chris@148 134 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@148 135 break;
Chris@148 136
Chris@148 137 default:
Chris@148 138 {
Chris@148 139 float mag = getMagnitudeAt(x, y);
Chris@148 140 float factor = getNormalizationFactor(x);
Chris@148 141 if (factor != 0) value = mag / factor;
Chris@148 142 else value = 0.f;
Chris@148 143 break;
Chris@148 144 }
Chris@148 145 }
Chris@148 146
Chris@148 147 return value;
Chris@148 148 }
Chris@148 149
Chris@148 150 float
Chris@148 151 FFTFileCache::getMaximumMagnitudeAt(size_t x) const
Chris@148 152 {
Chris@148 153 return getNormalizationFactor(x);
Chris@148 154 }
Chris@148 155
Chris@148 156 float
Chris@148 157 FFTFileCache::getPhaseAt(size_t x, size_t y) const
Chris@148 158 {
Chris@148 159 float value = 0.f;
Chris@148 160
Chris@148 161 switch (m_storageType) {
Chris@148 162
Chris@148 163 case Compact:
Chris@148 164 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@148 165 break;
Chris@148 166
Chris@148 167 case Rectangular:
Chris@148 168 {
Chris@148 169 float real, imag;
Chris@148 170 getValuesAt(x, y, real, imag);
Chris@408 171 value = atan2f(imag, real);
Chris@148 172 break;
Chris@148 173 }
Chris@148 174
Chris@148 175 case Polar:
Chris@148 176 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 177 break;
Chris@148 178 }
Chris@148 179
Chris@148 180 return value;
Chris@148 181 }
Chris@148 182
Chris@148 183 void
Chris@148 184 FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@148 185 {
Chris@148 186 switch (m_storageType) {
Chris@148 187
Chris@148 188 case Rectangular:
Chris@148 189 real = getFromReadBufStandard(x, y * 2);
Chris@148 190 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@148 191 return;
Chris@148 192
Chris@148 193 default:
Chris@148 194 float mag = getMagnitudeAt(x, y);
Chris@148 195 float phase = getPhaseAt(x, y);
Chris@148 196 real = mag * cosf(phase);
Chris@148 197 imag = mag * sinf(phase);
Chris@148 198 return;
Chris@148 199 }
Chris@148 200 }
Chris@148 201
Chris@148 202 bool
Chris@148 203 FFTFileCache::haveSetColumnAt(size_t x) const
Chris@148 204 {
Chris@148 205 return m_mfc->haveSetColumnAt(x);
Chris@148 206 }
Chris@148 207
Chris@148 208 void
Chris@148 209 FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor)
Chris@148 210 {
Chris@408 211 MutexLocker locker(&m_writeMutex, "FFTFileCache::setColumnAt::m_writeMutex");
Chris@148 212
Chris@148 213 size_t h = getHeight();
Chris@148 214
Chris@148 215 switch (m_storageType) {
Chris@148 216
Chris@148 217 case Compact:
Chris@148 218 for (size_t y = 0; y < h; ++y) {
Chris@148 219 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0);
Chris@148 220 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI));
Chris@148 221 }
Chris@148 222 break;
Chris@148 223
Chris@148 224 case Rectangular:
Chris@148 225 for (size_t y = 0; y < h; ++y) {
Chris@148 226 ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]);
Chris@148 227 ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]);
Chris@148 228 }
Chris@148 229 break;
Chris@148 230
Chris@148 231 case Polar:
Chris@148 232 for (size_t y = 0; y < h; ++y) {
Chris@148 233 ((float *)m_writebuf)[y * 2] = mags[y];
Chris@148 234 ((float *)m_writebuf)[y * 2 + 1] = phases[y];
Chris@148 235 }
Chris@148 236 break;
Chris@148 237 }
Chris@148 238
Chris@266 239 // static float maxFactor = 0;
Chris@266 240 // if (factor > maxFactor) maxFactor = factor;
Chris@266 241 // std::cerr << "Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@148 242
Chris@266 243 setNormalizationFactorToWritebuf(factor);
Chris@266 244
Chris@148 245 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 246 }
Chris@148 247
Chris@148 248 void
Chris@148 249 FFTFileCache::setColumnAt(size_t x, float *real, float *imag)
Chris@148 250 {
Chris@408 251 MutexLocker locker(&m_writeMutex, "FFTFileCache::setColumnAt::m_writeMutex");
Chris@148 252
Chris@148 253 size_t h = getHeight();
Chris@148 254
Chris@266 255 float factor = 0.0f;
Chris@148 256
Chris@148 257 switch (m_storageType) {
Chris@148 258
Chris@148 259 case Compact:
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@266 262 if (mag > factor) factor = mag;
Chris@148 263 }
Chris@148 264 for (size_t y = 0; y < h; ++y) {
Chris@148 265 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@408 266 float phase = atan2f(imag[y], real[y]);
Chris@266 267 ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / factor) * 65535.0);
Chris@148 268 ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
Chris@148 269 }
Chris@148 270 break;
Chris@148 271
Chris@148 272 case Rectangular:
Chris@148 273 for (size_t y = 0; y < h; ++y) {
Chris@148 274 ((float *)m_writebuf)[y * 2] = real[y];
Chris@148 275 ((float *)m_writebuf)[y * 2 + 1] = imag[y];
Chris@148 276 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 277 if (mag > factor) factor = mag;
Chris@148 278 }
Chris@148 279 break;
Chris@148 280
Chris@148 281 case Polar:
Chris@148 282 for (size_t y = 0; y < h; ++y) {
Chris@148 283 float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]);
Chris@266 284 if (mag > factor) factor = mag;
Chris@148 285 ((float *)m_writebuf)[y * 2] = mag;
Chris@408 286 float phase = atan2f(imag[y], real[y]);
Chris@290 287 ((float *)m_writebuf)[y * 2 + 1] = phase;
Chris@148 288 }
Chris@148 289 break;
Chris@148 290 }
Chris@148 291
Chris@266 292 // static float maxFactor = 0;
Chris@266 293 // if (factor > maxFactor) maxFactor = factor;
Chris@266 294 // std::cerr << "[RI] Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
Chris@266 295
Chris@266 296 setNormalizationFactorToWritebuf(factor);
Chris@266 297
Chris@148 298 m_mfc->setColumnAt(x, m_writebuf);
Chris@148 299 }
Chris@148 300
Chris@170 301 size_t
Chris@170 302 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
Chris@170 303 {
Chris@266 304 return (height * 2 + (type == Compact ? 2 : 1)) * width *
Chris@170 305 (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@170 306 2 * sizeof(size_t); // matrix file header size
Chris@170 307 }
Chris@170 308
Chris@183 309 void
Chris@458 310 FFTFileCache::populateReadBuf(size_t x) const // m_readbufMutex already held
Chris@183 311 {
Chris@183 312 Profiler profiler("FFTFileCache::populateReadBuf", false);
Chris@183 313
Chris@183 314 if (!m_readbuf) {
Chris@183 315 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@183 316 }
Chris@455 317 try {
Chris@455 318 m_mfc->getColumnAt(x, m_readbuf);
Chris@455 319 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@455 320 m_mfc->getColumnAt
Chris@455 321 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@455 322 m_readbufWidth = 2;
Chris@455 323 } else {
Chris@455 324 m_readbufWidth = 1;
Chris@455 325 }
Chris@455 326 } catch (FileReadFailed f) {
Chris@455 327 std::cerr << "ERROR: FFTFileCache::populateReadBuf: File read failed: "
Chris@455 328 << f.what() << std::endl;
Chris@455 329 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize());
Chris@183 330 }
Chris@183 331 m_readbufCol = x;
Chris@183 332 }
Chris@183 333