svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006-2009 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "FFTFileCacheReader.h" 00017 #include "FFTFileCacheWriter.h" 00018 00019 #include "fileio/MatrixFile.h" 00020 00021 #include "base/Profiler.h" 00022 #include "base/Thread.h" 00023 #include "base/Exceptions.h" 00024 00025 #include <iostream> 00026 00027 00028 // The underlying matrix has height (m_height * 2 + 1). In each 00029 // column we store magnitude at [0], [2] etc and phase at [1], [3] 00030 // etc, and then store the normalization factor (maximum magnitude) at 00031 // [m_height * 2]. In compact mode, the factor takes two cells. 00032 00033 FFTFileCacheReader::FFTFileCacheReader(FFTFileCacheWriter *writer) : 00034 m_readbuf(0), 00035 m_readbufCol(0), 00036 m_readbufWidth(0), 00037 m_readbufGood(false), 00038 m_storageType(writer->getStorageType()), 00039 m_factorSize(m_storageType == FFTCache::Compact ? 2 : 1), 00040 m_mfc(new MatrixFile 00041 (writer->getFileBase(), 00042 MatrixFile::ReadOnly, 00043 m_storageType == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float), 00044 writer->getWidth(), 00045 writer->getHeight() * 2 + m_factorSize)) 00046 { 00047 // cerr << "FFTFileCacheReader: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << endl; 00048 } 00049 00050 FFTFileCacheReader::~FFTFileCacheReader() 00051 { 00052 if (m_readbuf) delete[] m_readbuf; 00053 delete m_mfc; 00054 } 00055 00056 int 00057 FFTFileCacheReader::getWidth() const 00058 { 00059 return m_mfc->getWidth(); 00060 } 00061 00062 int 00063 FFTFileCacheReader::getHeight() const 00064 { 00065 int mh = m_mfc->getHeight(); 00066 if (mh > m_factorSize) return (mh - m_factorSize) / 2; 00067 else return 0; 00068 } 00069 00070 float 00071 FFTFileCacheReader::getMagnitudeAt(int x, int y) const 00072 { 00073 Profiler profiler("FFTFileCacheReader::getMagnitudeAt", false); 00074 00075 float value = 0.f; 00076 00077 switch (m_storageType) { 00078 00079 case FFTCache::Compact: 00080 value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0) 00081 * getNormalizationFactor(x); 00082 break; 00083 00084 case FFTCache::Rectangular: 00085 { 00086 float real, imag; 00087 getValuesAt(x, y, real, imag); 00088 value = sqrtf(real * real + imag * imag); 00089 break; 00090 } 00091 00092 case FFTCache::Polar: 00093 value = getFromReadBufStandard(x, y * 2); 00094 break; 00095 } 00096 00097 return value; 00098 } 00099 00100 float 00101 FFTFileCacheReader::getNormalizedMagnitudeAt(int x, int y) const 00102 { 00103 float value = 0.f; 00104 00105 switch (m_storageType) { 00106 00107 case FFTCache::Compact: 00108 value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0; 00109 break; 00110 00111 case FFTCache::Rectangular: 00112 case FFTCache::Polar: 00113 { 00114 float mag = getMagnitudeAt(x, y); 00115 float factor = getNormalizationFactor(x); 00116 if (factor != 0) value = mag / factor; 00117 else value = 0.f; 00118 break; 00119 } 00120 } 00121 00122 return value; 00123 } 00124 00125 float 00126 FFTFileCacheReader::getMaximumMagnitudeAt(int x) const 00127 { 00128 return getNormalizationFactor(x); 00129 } 00130 00131 float 00132 FFTFileCacheReader::getPhaseAt(int x, int y) const 00133 { 00134 float value = 0.f; 00135 00136 switch (m_storageType) { 00137 00138 case FFTCache::Compact: 00139 value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI; 00140 break; 00141 00142 case FFTCache::Rectangular: 00143 { 00144 float real, imag; 00145 getValuesAt(x, y, real, imag); 00146 value = atan2f(imag, real); 00147 break; 00148 } 00149 00150 case FFTCache::Polar: 00151 value = getFromReadBufStandard(x, y * 2 + 1); 00152 break; 00153 } 00154 00155 return value; 00156 } 00157 00158 void 00159 FFTFileCacheReader::getValuesAt(int x, int y, float &real, float &imag) const 00160 { 00161 // SVDEBUG << "FFTFileCacheReader::getValuesAt(" << x << "," << y << ")" << endl; 00162 00163 switch (m_storageType) { 00164 00165 case FFTCache::Rectangular: 00166 real = getFromReadBufStandard(x, y * 2); 00167 imag = getFromReadBufStandard(x, y * 2 + 1); 00168 return; 00169 00170 case FFTCache::Compact: 00171 case FFTCache::Polar: 00172 float mag = getMagnitudeAt(x, y); 00173 float phase = getPhaseAt(x, y); 00174 real = mag * cosf(phase); 00175 imag = mag * sinf(phase); 00176 return; 00177 } 00178 } 00179 00180 void 00181 FFTFileCacheReader::getMagnitudesAt(int x, float *values, int minbin, int count, int step) const 00182 { 00183 Profiler profiler("FFTFileCacheReader::getMagnitudesAt"); 00184 00185 switch (m_storageType) { 00186 00187 case FFTCache::Compact: 00188 for (int i = 0; i < count; ++i) { 00189 int y = minbin + i * step; 00190 values[i] = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0) 00191 * getNormalizationFactor(x); 00192 } 00193 break; 00194 00195 case FFTCache::Rectangular: 00196 { 00197 float real, imag; 00198 for (int i = 0; i < count; ++i) { 00199 int y = minbin + i * step; 00200 real = getFromReadBufStandard(x, y * 2); 00201 imag = getFromReadBufStandard(x, y * 2 + 1); 00202 values[i] = sqrtf(real * real + imag * imag); 00203 } 00204 break; 00205 } 00206 00207 case FFTCache::Polar: 00208 for (int i = 0; i < count; ++i) { 00209 int y = minbin + i * step; 00210 values[i] = getFromReadBufStandard(x, y * 2); 00211 } 00212 break; 00213 } 00214 } 00215 00216 bool 00217 FFTFileCacheReader::haveSetColumnAt(int x) const 00218 { 00219 if (m_readbuf && m_readbufGood && 00220 (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) { 00221 // SVDEBUG << "FFTFileCacheReader::haveSetColumnAt: short-circuiting; we know about this one" << endl; 00222 return true; 00223 } 00224 return m_mfc->haveSetColumnAt(x); 00225 } 00226 00227 int 00228 FFTFileCacheReader::getCacheSize(int width, int height, 00229 FFTCache::StorageType type) 00230 { 00231 return (height * 2 + (type == FFTCache::Compact ? 2 : 1)) * width * 00232 (type == FFTCache::Compact ? sizeof(uint16_t) : sizeof(float)) + 00233 2 * sizeof(int); // matrix file header size 00234 } 00235 00236 void 00237 FFTFileCacheReader::populateReadBuf(int x) const 00238 { 00239 Profiler profiler("FFTFileCacheReader::populateReadBuf", false); 00240 00241 // SVDEBUG << "FFTFileCacheReader::populateReadBuf(" << x << ")" << endl; 00242 00243 if (!m_readbuf) { 00244 m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()]; 00245 } 00246 00247 m_readbufGood = false; 00248 00249 try { 00250 bool good = false; 00251 if (m_mfc->haveSetColumnAt(x)) { 00252 // If the column is not available, we have no obligation 00253 // to do anything with the readbuf -- we can cheerfully 00254 // return garbage. It's the responsibility of the caller 00255 // to check haveSetColumnAt before trusting any retrieved 00256 // data. However, we do record whether the data in the 00257 // readbuf is good or not, because we can use that to 00258 // return an immediate result for haveSetColumnAt if the 00259 // column is right. 00260 good = true; 00261 m_mfc->getColumnAt(x, m_readbuf); 00262 } 00263 if (m_mfc->haveSetColumnAt(x + 1)) { 00264 m_mfc->getColumnAt 00265 (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight()); 00266 m_readbufWidth = 2; 00267 } else { 00268 m_readbufWidth = 1; 00269 } 00270 m_readbufGood = good; 00271 } catch (FileReadFailed f) { 00272 cerr << "ERROR: FFTFileCacheReader::populateReadBuf: File read failed: " 00273 << f.what() << endl; 00274 memset(m_readbuf, 0, m_mfc->getHeight() * 2 * m_mfc->getCellSize()); 00275 } 00276 m_readbufCol = x; 00277 } 00278