annotate data/fft/FFTFileCacheReader.cpp @ 1081:027d8b943be5

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