annotate data/fft/FFTFileCacheReader.cpp @ 1086:9f4505ac9072

Tidy dense time-value model API a bit; add first simple unit test for FFT model
author Chris Cannam
date Wed, 10 Jun 2015 17:06:02 +0100
parents 027d8b943be5
children
rev   line source
Chris@537 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@537 2
Chris@537 3 /*
Chris@537 4 Sonic Visualiser
Chris@537 5 An audio file viewer and annotation editor.
Chris@537 6 Centre for Digital Music, Queen Mary, University of London.
Chris@537 7 This file copyright 2006-2009 Chris Cannam and QMUL.
Chris@537 8
Chris@537 9 This program is free software; you can redistribute it and/or
Chris@537 10 modify it under the terms of the GNU General Public License as
Chris@537 11 published by the Free Software Foundation; either version 2 of the
Chris@537 12 License, or (at your option) any later version. See the file
Chris@537 13 COPYING included with this distribution for more information.
Chris@537 14 */
Chris@537 15
Chris@537 16 #include "FFTFileCacheReader.h"
Chris@537 17 #include "FFTFileCacheWriter.h"
Chris@537 18
Chris@537 19 #include "fileio/MatrixFile.h"
Chris@537 20
Chris@537 21 #include "base/Profiler.h"
Chris@537 22 #include "base/Thread.h"
Chris@537 23 #include "base/Exceptions.h"
Chris@537 24
Chris@537 25 #include <iostream>
Chris@537 26
Chris@1081 27 //#define DEBUG_FFT_FILE_CACHE_READER 1
Chris@1081 28
Chris@537 29 // The underlying matrix has height (m_height * 2 + 1). In each
Chris@537 30 // column we store magnitude at [0], [2] etc and phase at [1], [3]
Chris@537 31 // etc, and then store the normalization factor (maximum magnitude) at
Chris@537 32 // [m_height * 2]. In compact mode, the factor takes two cells.
Chris@537 33
Chris@537 34 FFTFileCacheReader::FFTFileCacheReader(FFTFileCacheWriter *writer) :
Chris@537 35 m_readbuf(0),
Chris@537 36 m_readbufCol(0),
Chris@537 37 m_readbufWidth(0),
Chris@555 38 m_readbufGood(false),
Chris@537 39 m_storageType(writer->getStorageType()),
Chris@537 40 m_factorSize(m_storageType == FFTCache::Compact ? 2 : 1),
Chris@537 41 m_mfc(new MatrixFile
Chris@537 42 (writer->getFileBase(),
Chris@537 43 MatrixFile::ReadOnly,
Chris@1038 44 int((m_storageType == FFTCache::Compact) ? sizeof(uint16_t) : sizeof(float)),
Chris@537 45 writer->getWidth(),
Chris@537 46 writer->getHeight() * 2 + m_factorSize))
Chris@537 47 {
Chris@1081 48 #ifdef DEBUG_FFT_FILE_CACHE_READER
Chris@1081 49 cerr << "FFTFileCacheReader: storage type is " << (m_storageType == FFTCache::Compact ? "Compact" : m_storageType == FFTCache::Polar ? "Polar" : "Rectangular") << endl;
Chris@1081 50 #endif
Chris@537 51 }
Chris@537 52
Chris@537 53 FFTFileCacheReader::~FFTFileCacheReader()
Chris@537 54 {
Chris@537 55 if (m_readbuf) delete[] m_readbuf;
Chris@537 56 delete m_mfc;
Chris@537 57 }
Chris@537 58
Chris@929 59 int
Chris@537 60 FFTFileCacheReader::getWidth() const
Chris@537 61 {
Chris@537 62 return m_mfc->getWidth();
Chris@537 63 }
Chris@537 64
Chris@929 65 int
Chris@537 66 FFTFileCacheReader::getHeight() const
Chris@537 67 {
Chris@929 68 int mh = m_mfc->getHeight();
Chris@537 69 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@537 70 else return 0;
Chris@537 71 }
Chris@537 72
Chris@537 73 float
Chris@929 74 FFTFileCacheReader::getMagnitudeAt(int x, int y) const
Chris@537 75 {
Chris@537 76 Profiler profiler("FFTFileCacheReader::getMagnitudeAt", false);
Chris@537 77
Chris@537 78 float value = 0.f;
Chris@537 79
Chris@537 80 switch (m_storageType) {
Chris@537 81
Chris@537 82 case FFTCache::Compact:
Chris@1038 83 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.f)
Chris@537 84 * getNormalizationFactor(x);
Chris@537 85 break;
Chris@537 86
Chris@537 87 case FFTCache::Rectangular:
Chris@537 88 {
Chris@537 89 float real, imag;
Chris@537 90 getValuesAt(x, y, real, imag);
Chris@537 91 value = sqrtf(real * real + imag * imag);
Chris@537 92 break;
Chris@537 93 }
Chris@537 94
Chris@537 95 case FFTCache::Polar:
Chris@537 96 value = getFromReadBufStandard(x, y * 2);
Chris@537 97 break;
Chris@537 98 }
Chris@537 99
Chris@537 100 return value;
Chris@537 101 }
Chris@537 102
Chris@537 103 float
Chris@929 104 FFTFileCacheReader::getNormalizedMagnitudeAt(int x, int y) const
Chris@537 105 {
Chris@537 106 float value = 0.f;
Chris@537 107
Chris@537 108 switch (m_storageType) {
Chris@537 109
Chris@537 110 case FFTCache::Compact:
Chris@1038 111 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.f;
Chris@537 112 break;
Chris@537 113
Chris@929 114 case FFTCache::Rectangular:
Chris@929 115 case FFTCache::Polar:
Chris@537 116 {
Chris@537 117 float mag = getMagnitudeAt(x, y);
Chris@537 118 float factor = getNormalizationFactor(x);
Chris@537 119 if (factor != 0) value = mag / factor;
Chris@537 120 else value = 0.f;
Chris@537 121 break;
Chris@537 122 }
Chris@537 123 }
Chris@537 124
Chris@537 125 return value;
Chris@537 126 }
Chris@537 127
Chris@537 128 float
Chris@929 129 FFTFileCacheReader::getMaximumMagnitudeAt(int x) const
Chris@537 130 {
Chris@537 131 return getNormalizationFactor(x);
Chris@537 132 }
Chris@537 133
Chris@537 134 float
Chris@929 135 FFTFileCacheReader::getPhaseAt(int x, int y) const
Chris@537 136 {
Chris@537 137 float value = 0.f;
Chris@537 138
Chris@537 139 switch (m_storageType) {
Chris@537 140
Chris@537 141 case FFTCache::Compact:
Chris@1038 142 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.f) * float(M_PI);
Chris@537 143 break;
Chris@537 144
Chris@537 145 case FFTCache::Rectangular:
Chris@537 146 {
Chris@537 147 float real, imag;
Chris@537 148 getValuesAt(x, y, real, imag);
Chris@537 149 value = atan2f(imag, real);
Chris@537 150 break;
Chris@537 151 }
Chris@537 152
Chris@537 153 case FFTCache::Polar:
Chris@537 154 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 155 break;
Chris@537 156 }
Chris@537 157
Chris@537 158 return value;
Chris@537 159 }
Chris@537 160
Chris@537 161 void
Chris@929 162 FFTFileCacheReader::getValuesAt(int x, int y, float &real, float &imag) const
Chris@537 163 {
Chris@690 164 // SVDEBUG << "FFTFileCacheReader::getValuesAt(" << x << "," << y << ")" << endl;
Chris@555 165
Chris@537 166 switch (m_storageType) {
Chris@537 167
Chris@537 168 case FFTCache::Rectangular:
Chris@537 169 real = getFromReadBufStandard(x, y * 2);
Chris@537 170 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 171 return;
Chris@537 172
Chris@929 173 case FFTCache::Compact:
Chris@929 174 case FFTCache::Polar:
Chris@537 175 float mag = getMagnitudeAt(x, y);
Chris@537 176 float phase = getPhaseAt(x, y);
Chris@537 177 real = mag * cosf(phase);
Chris@537 178 imag = mag * sinf(phase);
Chris@537 179 return;
Chris@537 180 }
Chris@537 181 }
Chris@537 182
Chris@537 183 void
Chris@929 184 FFTFileCacheReader::getMagnitudesAt(int x, float *values, int minbin, int count, int step) const
Chris@537 185 {
Chris@537 186 Profiler profiler("FFTFileCacheReader::getMagnitudesAt");
Chris@537 187
Chris@537 188 switch (m_storageType) {
Chris@537 189
Chris@537 190 case FFTCache::Compact:
Chris@929 191 for (int i = 0; i < count; ++i) {
Chris@929 192 int y = minbin + i * step;
Chris@1038 193 values[i] = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.f)
Chris@537 194 * getNormalizationFactor(x);
Chris@537 195 }
Chris@537 196 break;
Chris@537 197
Chris@537 198 case FFTCache::Rectangular:
Chris@537 199 {
Chris@537 200 float real, imag;
Chris@929 201 for (int i = 0; i < count; ++i) {
Chris@929 202 int y = minbin + i * step;
Chris@537 203 real = getFromReadBufStandard(x, y * 2);
Chris@537 204 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 205 values[i] = sqrtf(real * real + imag * imag);
Chris@537 206 }
Chris@537 207 break;
Chris@537 208 }
Chris@537 209
Chris@537 210 case FFTCache::Polar:
Chris@929 211 for (int i = 0; i < count; ++i) {
Chris@929 212 int y = minbin + i * step;
Chris@537 213 values[i] = getFromReadBufStandard(x, y * 2);
Chris@537 214 }
Chris@537 215 break;
Chris@537 216 }
Chris@537 217 }
Chris@537 218
Chris@537 219 bool
Chris@929 220 FFTFileCacheReader::haveSetColumnAt(int x) const
Chris@537 221 {
Chris@555 222 if (m_readbuf && m_readbufGood &&
Chris@555 223 (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
Chris@690 224 // SVDEBUG << "FFTFileCacheReader::haveSetColumnAt: short-circuiting; we know about this one" << endl;
Chris@555 225 return true;
Chris@555 226 }
Chris@537 227 return m_mfc->haveSetColumnAt(x);
Chris@537 228 }
Chris@537 229
Chris@1038 230 size_t
Chris@929 231 FFTFileCacheReader::getCacheSize(int width, int height,
Chris@537 232 FFTCache::StorageType type)
Chris@537 233 {
Chris@537 234 return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width *
Chris@537 235 (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@929 236 2 * sizeof(int); // matrix file header size
Chris@537 237 }
Chris@537 238
Chris@537 239 void
Chris@929 240 FFTFileCacheReader::populateReadBuf(int x) const
Chris@537 241 {
Chris@537 242 Profiler profiler("FFTFileCacheReader::populateReadBuf", false);
Chris@537 243
Chris@690 244 // SVDEBUG << "FFTFileCacheReader::populateReadBuf(" << x << ")" << endl;
Chris@554 245
Chris@537 246 if (!m_readbuf) {
Chris@537 247 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@537 248 }
Chris@537 249
Chris@555 250 m_readbufGood = false;
Chris@555 251
Chris@537 252 try {
Chris@555 253 bool good = false;
Chris@555 254 if (m_mfc->haveSetColumnAt(x)) {
Chris@555 255 // If the column is not available, we have no obligation
Chris@555 256 // to do anything with the readbuf -- we can cheerfully
Chris@555 257 // return garbage. It's the responsibility of the caller
Chris@555 258 // to check haveSetColumnAt before trusting any retrieved
Chris@555 259 // data. However, we do record whether the data in the
Chris@555 260 // readbuf is good or not, because we can use that to
Chris@555 261 // return an immediate result for haveSetColumnAt if the
Chris@555 262 // column is right.
Chris@555 263 good = true;
Chris@555 264 m_mfc->getColumnAt(x, m_readbuf);
Chris@555 265 }
Chris@537 266 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@537 267 m_mfc->getColumnAt
Chris@537 268 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@537 269 m_readbufWidth = 2;
Chris@537 270 } else {
Chris@537 271 m_readbufWidth = 1;
Chris@537 272 }
Chris@555 273 m_readbufGood = good;
Chris@537 274 } catch (FileReadFailed f) {
Chris@843 275 cerr << "ERROR: FFTFileCacheReader::populateReadBuf: File read failed: "
Chris@843 276 << f.what() << endl;
Chris@537 277 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize());
Chris@537 278 }
Chris@537 279 m_readbufCol = x;
Chris@537 280 }
Chris@537 281