annotate data/fft/FFTFileCacheReader.cpp @ 1008:d9e0e59a1581

When using an aggregate model to pass data to a transform, zero-pad the shorter input to the duration of the longer rather than truncating the longer. (This is better behaviour for e.g. MATCH, and in any case the code was previously truncating incorrectly and ending up with garbage data at the end.)
author Chris Cannam
date Fri, 14 Nov 2014 13:51:33 +0000
parents 59e7fe1b1003
children cc27f35aa75c
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@537 27
Chris@537 28 // The underlying matrix has height (m_height * 2 + 1). In each
Chris@537 29 // column we store magnitude at [0], [2] etc and phase at [1], [3]
Chris@537 30 // etc, and then store the normalization factor (maximum magnitude) at
Chris@537 31 // [m_height * 2]. In compact mode, the factor takes two cells.
Chris@537 32
Chris@537 33 FFTFileCacheReader::FFTFileCacheReader(FFTFileCacheWriter *writer) :
Chris@537 34 m_readbuf(0),
Chris@537 35 m_readbufCol(0),
Chris@537 36 m_readbufWidth(0),
Chris@555 37 m_readbufGood(false),
Chris@537 38 m_storageType(writer->getStorageType()),
Chris@537 39 m_factorSize(m_storageType == FFTCache::Compact ? 2 : 1),
Chris@537 40 m_mfc(new MatrixFile
Chris@537 41 (writer->getFileBase(),
Chris@537 42 MatrixFile::ReadOnly,
Chris@537 43 m_storageType == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float),
Chris@537 44 writer->getWidth(),
Chris@537 45 writer->getHeight() * 2 + m_factorSize))
Chris@537 46 {
Chris@843 47 // cerr << "FFTFileCacheReader: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << endl;
Chris@537 48 }
Chris@537 49
Chris@537 50 FFTFileCacheReader::~FFTFileCacheReader()
Chris@537 51 {
Chris@537 52 if (m_readbuf) delete[] m_readbuf;
Chris@537 53 delete m_mfc;
Chris@537 54 }
Chris@537 55
Chris@929 56 int
Chris@537 57 FFTFileCacheReader::getWidth() const
Chris@537 58 {
Chris@537 59 return m_mfc->getWidth();
Chris@537 60 }
Chris@537 61
Chris@929 62 int
Chris@537 63 FFTFileCacheReader::getHeight() const
Chris@537 64 {
Chris@929 65 int mh = m_mfc->getHeight();
Chris@537 66 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@537 67 else return 0;
Chris@537 68 }
Chris@537 69
Chris@537 70 float
Chris@929 71 FFTFileCacheReader::getMagnitudeAt(int x, int y) const
Chris@537 72 {
Chris@537 73 Profiler profiler("FFTFileCacheReader::getMagnitudeAt", false);
Chris@537 74
Chris@537 75 float value = 0.f;
Chris@537 76
Chris@537 77 switch (m_storageType) {
Chris@537 78
Chris@537 79 case FFTCache::Compact:
Chris@537 80 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 81 * getNormalizationFactor(x);
Chris@537 82 break;
Chris@537 83
Chris@537 84 case FFTCache::Rectangular:
Chris@537 85 {
Chris@537 86 float real, imag;
Chris@537 87 getValuesAt(x, y, real, imag);
Chris@537 88 value = sqrtf(real * real + imag * imag);
Chris@537 89 break;
Chris@537 90 }
Chris@537 91
Chris@537 92 case FFTCache::Polar:
Chris@537 93 value = getFromReadBufStandard(x, y * 2);
Chris@537 94 break;
Chris@537 95 }
Chris@537 96
Chris@537 97 return value;
Chris@537 98 }
Chris@537 99
Chris@537 100 float
Chris@929 101 FFTFileCacheReader::getNormalizedMagnitudeAt(int x, int y) const
Chris@537 102 {
Chris@537 103 float value = 0.f;
Chris@537 104
Chris@537 105 switch (m_storageType) {
Chris@537 106
Chris@537 107 case FFTCache::Compact:
Chris@537 108 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@537 109 break;
Chris@537 110
Chris@929 111 case FFTCache::Rectangular:
Chris@929 112 case FFTCache::Polar:
Chris@537 113 {
Chris@537 114 float mag = getMagnitudeAt(x, y);
Chris@537 115 float factor = getNormalizationFactor(x);
Chris@537 116 if (factor != 0) value = mag / factor;
Chris@537 117 else value = 0.f;
Chris@537 118 break;
Chris@537 119 }
Chris@537 120 }
Chris@537 121
Chris@537 122 return value;
Chris@537 123 }
Chris@537 124
Chris@537 125 float
Chris@929 126 FFTFileCacheReader::getMaximumMagnitudeAt(int x) const
Chris@537 127 {
Chris@537 128 return getNormalizationFactor(x);
Chris@537 129 }
Chris@537 130
Chris@537 131 float
Chris@929 132 FFTFileCacheReader::getPhaseAt(int x, int y) const
Chris@537 133 {
Chris@537 134 float value = 0.f;
Chris@537 135
Chris@537 136 switch (m_storageType) {
Chris@537 137
Chris@537 138 case FFTCache::Compact:
Chris@537 139 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@537 140 break;
Chris@537 141
Chris@537 142 case FFTCache::Rectangular:
Chris@537 143 {
Chris@537 144 float real, imag;
Chris@537 145 getValuesAt(x, y, real, imag);
Chris@537 146 value = atan2f(imag, real);
Chris@537 147 break;
Chris@537 148 }
Chris@537 149
Chris@537 150 case FFTCache::Polar:
Chris@537 151 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 152 break;
Chris@537 153 }
Chris@537 154
Chris@537 155 return value;
Chris@537 156 }
Chris@537 157
Chris@537 158 void
Chris@929 159 FFTFileCacheReader::getValuesAt(int x, int y, float &real, float &imag) const
Chris@537 160 {
Chris@690 161 // SVDEBUG << "FFTFileCacheReader::getValuesAt(" << x << "," << y << ")" << endl;
Chris@555 162
Chris@537 163 switch (m_storageType) {
Chris@537 164
Chris@537 165 case FFTCache::Rectangular:
Chris@537 166 real = getFromReadBufStandard(x, y * 2);
Chris@537 167 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 168 return;
Chris@537 169
Chris@929 170 case FFTCache::Compact:
Chris@929 171 case FFTCache::Polar:
Chris@537 172 float mag = getMagnitudeAt(x, y);
Chris@537 173 float phase = getPhaseAt(x, y);
Chris@537 174 real = mag * cosf(phase);
Chris@537 175 imag = mag * sinf(phase);
Chris@537 176 return;
Chris@537 177 }
Chris@537 178 }
Chris@537 179
Chris@537 180 void
Chris@929 181 FFTFileCacheReader::getMagnitudesAt(int x, float *values, int minbin, int count, int step) const
Chris@537 182 {
Chris@537 183 Profiler profiler("FFTFileCacheReader::getMagnitudesAt");
Chris@537 184
Chris@537 185 switch (m_storageType) {
Chris@537 186
Chris@537 187 case FFTCache::Compact:
Chris@929 188 for (int i = 0; i < count; ++i) {
Chris@929 189 int y = minbin + i * step;
Chris@537 190 values[i] = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 191 * getNormalizationFactor(x);
Chris@537 192 }
Chris@537 193 break;
Chris@537 194
Chris@537 195 case FFTCache::Rectangular:
Chris@537 196 {
Chris@537 197 float real, imag;
Chris@929 198 for (int i = 0; i < count; ++i) {
Chris@929 199 int y = minbin + i * step;
Chris@537 200 real = getFromReadBufStandard(x, y * 2);
Chris@537 201 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 202 values[i] = sqrtf(real * real + imag * imag);
Chris@537 203 }
Chris@537 204 break;
Chris@537 205 }
Chris@537 206
Chris@537 207 case FFTCache::Polar:
Chris@929 208 for (int i = 0; i < count; ++i) {
Chris@929 209 int y = minbin + i * step;
Chris@537 210 values[i] = getFromReadBufStandard(x, y * 2);
Chris@537 211 }
Chris@537 212 break;
Chris@537 213 }
Chris@537 214 }
Chris@537 215
Chris@537 216 bool
Chris@929 217 FFTFileCacheReader::haveSetColumnAt(int x) const
Chris@537 218 {
Chris@555 219 if (m_readbuf && m_readbufGood &&
Chris@555 220 (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
Chris@690 221 // SVDEBUG << "FFTFileCacheReader::haveSetColumnAt: short-circuiting; we know about this one" << endl;
Chris@555 222 return true;
Chris@555 223 }
Chris@537 224 return m_mfc->haveSetColumnAt(x);
Chris@537 225 }
Chris@537 226
Chris@929 227 int
Chris@929 228 FFTFileCacheReader::getCacheSize(int width, int height,
Chris@537 229 FFTCache::StorageType type)
Chris@537 230 {
Chris@537 231 return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width *
Chris@537 232 (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@929 233 2 * sizeof(int); // matrix file header size
Chris@537 234 }
Chris@537 235
Chris@537 236 void
Chris@929 237 FFTFileCacheReader::populateReadBuf(int x) const
Chris@537 238 {
Chris@537 239 Profiler profiler("FFTFileCacheReader::populateReadBuf", false);
Chris@537 240
Chris@690 241 // SVDEBUG << "FFTFileCacheReader::populateReadBuf(" << x << ")" << endl;
Chris@554 242
Chris@537 243 if (!m_readbuf) {
Chris@537 244 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@537 245 }
Chris@537 246
Chris@555 247 m_readbufGood = false;
Chris@555 248
Chris@537 249 try {
Chris@555 250 bool good = false;
Chris@555 251 if (m_mfc->haveSetColumnAt(x)) {
Chris@555 252 // If the column is not available, we have no obligation
Chris@555 253 // to do anything with the readbuf -- we can cheerfully
Chris@555 254 // return garbage. It's the responsibility of the caller
Chris@555 255 // to check haveSetColumnAt before trusting any retrieved
Chris@555 256 // data. However, we do record whether the data in the
Chris@555 257 // readbuf is good or not, because we can use that to
Chris@555 258 // return an immediate result for haveSetColumnAt if the
Chris@555 259 // column is right.
Chris@555 260 good = true;
Chris@555 261 m_mfc->getColumnAt(x, m_readbuf);
Chris@555 262 }
Chris@537 263 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@537 264 m_mfc->getColumnAt
Chris@537 265 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@537 266 m_readbufWidth = 2;
Chris@537 267 } else {
Chris@537 268 m_readbufWidth = 1;
Chris@537 269 }
Chris@555 270 m_readbufGood = good;
Chris@537 271 } catch (FileReadFailed f) {
Chris@843 272 cerr << "ERROR: FFTFileCacheReader::populateReadBuf: File read failed: "
Chris@843 273 << f.what() << endl;
Chris@537 274 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize());
Chris@537 275 }
Chris@537 276 m_readbufCol = x;
Chris@537 277 }
Chris@537 278