svcore  1.9
FFTFileCacheReader.cpp
Go to the documentation of this file.
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