annotate data/fft/FFTFileCacheReader.cpp @ 537:3cc4b7cd2aa5

* Merge from one-fftdataserver-per-fftmodel branch. This bit of reworking (which is not described very accurately by the title of the branch) turns the MatrixFile object into something that either reads or writes, but not both, and separates the FFT file cache reader and writer implementations separately. This allows the FFT data server to have a single thread owning writers and one reader per "customer" thread, and for all locking to be vastly simplified and concentrated in the data server alone (because none of the classes it makes use of is used in more than one thread at a time). The result is faster and more trustworthy code.
author Chris Cannam
date Tue, 27 Jan 2009 13:25:10 +0000
parents
children 60482f13e627
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@537 37 m_storageType(writer->getStorageType()),
Chris@537 38 m_factorSize(m_storageType == FFTCache::Compact ? 2 : 1),
Chris@537 39 m_mfc(new MatrixFile
Chris@537 40 (writer->getFileBase(),
Chris@537 41 MatrixFile::ReadOnly,
Chris@537 42 m_storageType == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float),
Chris@537 43 writer->getWidth(),
Chris@537 44 writer->getHeight() * 2 + m_factorSize))
Chris@537 45 {
Chris@537 46 // std::cerr << "FFTFileCacheReader: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
Chris@537 47 }
Chris@537 48
Chris@537 49 FFTFileCacheReader::~FFTFileCacheReader()
Chris@537 50 {
Chris@537 51 if (m_readbuf) delete[] m_readbuf;
Chris@537 52 delete m_mfc;
Chris@537 53 }
Chris@537 54
Chris@537 55 size_t
Chris@537 56 FFTFileCacheReader::getWidth() const
Chris@537 57 {
Chris@537 58 return m_mfc->getWidth();
Chris@537 59 }
Chris@537 60
Chris@537 61 size_t
Chris@537 62 FFTFileCacheReader::getHeight() const
Chris@537 63 {
Chris@537 64 size_t mh = m_mfc->getHeight();
Chris@537 65 if (mh > m_factorSize) return (mh - m_factorSize) / 2;
Chris@537 66 else return 0;
Chris@537 67 }
Chris@537 68
Chris@537 69 float
Chris@537 70 FFTFileCacheReader::getMagnitudeAt(size_t x, size_t y) const
Chris@537 71 {
Chris@537 72 Profiler profiler("FFTFileCacheReader::getMagnitudeAt", false);
Chris@537 73
Chris@537 74 float value = 0.f;
Chris@537 75
Chris@537 76 switch (m_storageType) {
Chris@537 77
Chris@537 78 case FFTCache::Compact:
Chris@537 79 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 80 * getNormalizationFactor(x);
Chris@537 81 break;
Chris@537 82
Chris@537 83 case FFTCache::Rectangular:
Chris@537 84 {
Chris@537 85 float real, imag;
Chris@537 86 getValuesAt(x, y, real, imag);
Chris@537 87 value = sqrtf(real * real + imag * imag);
Chris@537 88 break;
Chris@537 89 }
Chris@537 90
Chris@537 91 case FFTCache::Polar:
Chris@537 92 value = getFromReadBufStandard(x, y * 2);
Chris@537 93 break;
Chris@537 94 }
Chris@537 95
Chris@537 96 return value;
Chris@537 97 }
Chris@537 98
Chris@537 99 float
Chris@537 100 FFTFileCacheReader::getNormalizedMagnitudeAt(size_t x, size_t y) const
Chris@537 101 {
Chris@537 102 float value = 0.f;
Chris@537 103
Chris@537 104 switch (m_storageType) {
Chris@537 105
Chris@537 106 case FFTCache::Compact:
Chris@537 107 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0;
Chris@537 108 break;
Chris@537 109
Chris@537 110 default:
Chris@537 111 {
Chris@537 112 float mag = getMagnitudeAt(x, y);
Chris@537 113 float factor = getNormalizationFactor(x);
Chris@537 114 if (factor != 0) value = mag / factor;
Chris@537 115 else value = 0.f;
Chris@537 116 break;
Chris@537 117 }
Chris@537 118 }
Chris@537 119
Chris@537 120 return value;
Chris@537 121 }
Chris@537 122
Chris@537 123 float
Chris@537 124 FFTFileCacheReader::getMaximumMagnitudeAt(size_t x) const
Chris@537 125 {
Chris@537 126 return getNormalizationFactor(x);
Chris@537 127 }
Chris@537 128
Chris@537 129 float
Chris@537 130 FFTFileCacheReader::getPhaseAt(size_t x, size_t y) const
Chris@537 131 {
Chris@537 132 float value = 0.f;
Chris@537 133
Chris@537 134 switch (m_storageType) {
Chris@537 135
Chris@537 136 case FFTCache::Compact:
Chris@537 137 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI;
Chris@537 138 break;
Chris@537 139
Chris@537 140 case FFTCache::Rectangular:
Chris@537 141 {
Chris@537 142 float real, imag;
Chris@537 143 getValuesAt(x, y, real, imag);
Chris@537 144 value = atan2f(imag, real);
Chris@537 145 break;
Chris@537 146 }
Chris@537 147
Chris@537 148 case FFTCache::Polar:
Chris@537 149 value = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 150 break;
Chris@537 151 }
Chris@537 152
Chris@537 153 return value;
Chris@537 154 }
Chris@537 155
Chris@537 156 void
Chris@537 157 FFTFileCacheReader::getValuesAt(size_t x, size_t y, float &real, float &imag) const
Chris@537 158 {
Chris@537 159 switch (m_storageType) {
Chris@537 160
Chris@537 161 case FFTCache::Rectangular:
Chris@537 162 real = getFromReadBufStandard(x, y * 2);
Chris@537 163 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 164 return;
Chris@537 165
Chris@537 166 default:
Chris@537 167 float mag = getMagnitudeAt(x, y);
Chris@537 168 float phase = getPhaseAt(x, y);
Chris@537 169 real = mag * cosf(phase);
Chris@537 170 imag = mag * sinf(phase);
Chris@537 171 return;
Chris@537 172 }
Chris@537 173 }
Chris@537 174
Chris@537 175 void
Chris@537 176 FFTFileCacheReader::getMagnitudesAt(size_t x, float *values, size_t minbin, size_t count, size_t step) const
Chris@537 177 {
Chris@537 178 Profiler profiler("FFTFileCacheReader::getMagnitudesAt");
Chris@537 179
Chris@537 180 switch (m_storageType) {
Chris@537 181
Chris@537 182 case FFTCache::Compact:
Chris@537 183 for (size_t i = 0; i < count; ++i) {
Chris@537 184 size_t y = minbin + i * step;
Chris@537 185 values[i] = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0)
Chris@537 186 * getNormalizationFactor(x);
Chris@537 187 }
Chris@537 188 break;
Chris@537 189
Chris@537 190 case FFTCache::Rectangular:
Chris@537 191 {
Chris@537 192 float real, imag;
Chris@537 193 for (size_t i = 0; i < count; ++i) {
Chris@537 194 size_t y = minbin + i * step;
Chris@537 195 real = getFromReadBufStandard(x, y * 2);
Chris@537 196 imag = getFromReadBufStandard(x, y * 2 + 1);
Chris@537 197 values[i] = sqrtf(real * real + imag * imag);
Chris@537 198 }
Chris@537 199 break;
Chris@537 200 }
Chris@537 201
Chris@537 202 case FFTCache::Polar:
Chris@537 203 for (size_t i = 0; i < count; ++i) {
Chris@537 204 size_t y = minbin + i * step;
Chris@537 205 values[i] = getFromReadBufStandard(x, y * 2);
Chris@537 206 }
Chris@537 207 break;
Chris@537 208 }
Chris@537 209 }
Chris@537 210
Chris@537 211 bool
Chris@537 212 FFTFileCacheReader::haveSetColumnAt(size_t x) const
Chris@537 213 {
Chris@537 214 return m_mfc->haveSetColumnAt(x);
Chris@537 215 }
Chris@537 216
Chris@537 217 size_t
Chris@537 218 FFTFileCacheReader::getCacheSize(size_t width, size_t height,
Chris@537 219 FFTCache::StorageType type)
Chris@537 220 {
Chris@537 221 return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width *
Chris@537 222 (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) +
Chris@537 223 2 * sizeof(size_t); // matrix file header size
Chris@537 224 }
Chris@537 225
Chris@537 226 void
Chris@537 227 FFTFileCacheReader::populateReadBuf(size_t x) const
Chris@537 228 {
Chris@537 229 Profiler profiler("FFTFileCacheReader::populateReadBuf", false);
Chris@537 230
Chris@537 231 if (!m_readbuf) {
Chris@537 232 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()];
Chris@537 233 }
Chris@537 234
Chris@537 235 try {
Chris@537 236 m_mfc->getColumnAt(x, m_readbuf);
Chris@537 237 if (m_mfc->haveSetColumnAt(x + 1)) {
Chris@537 238 m_mfc->getColumnAt
Chris@537 239 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight());
Chris@537 240 m_readbufWidth = 2;
Chris@537 241 } else {
Chris@537 242 m_readbufWidth = 1;
Chris@537 243 }
Chris@537 244 } catch (FileReadFailed f) {
Chris@537 245 std::cerr << "ERROR: FFTFileCacheReader::populateReadBuf: File read failed: "
Chris@537 246 << f.what() << std::endl;
Chris@537 247 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize());
Chris@537 248 }
Chris@537 249 m_readbufCol = x;
Chris@537 250 }
Chris@537 251