annotate data/fft/FFTFileCacheReader.cpp @ 981:c6f2b93a7d52

Respond tidily to user cancellation during download, instead of going on to attempt to load the nonexistent file as a non-audio format
author Chris Cannam
date Tue, 09 Sep 2014 16:52:24 +0100
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