Mercurial > hg > svcore
diff base/FFTCache.h @ 87:7de62a884810
* Start factoring out the spectrogram's FFT cache into a separate set of
classes that will permit a choice of disk or memory cache strategies
author | Chris Cannam |
---|---|
date | Tue, 02 May 2006 12:27:41 +0000 |
parents | |
children | 6a1803d578e0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/FFTCache.h Tue May 02 12:27:41 2006 +0000 @@ -0,0 +1,149 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Chris Cannam. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _FFT_CACHE_H_ +#define _FFT_CACHE_H_ + +#include <QColor> +#include <stdint.h> + +class FFTCacheBase +{ +public: + virtual ~FFTCacheBase() { } + + virtual size_t getWidth() const = 0; + virtual size_t getHeight() const = 0; + + virtual void resize(size_t width, size_t height) = 0; + virtual void reset() = 0; // zero-fill or 1-fill as appropriate without changing size + + virtual float getMagnitudeAt(size_t x, size_t y) const = 0; + virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const = 0; + virtual float getPhaseAt(size_t x, size_t y) const = 0; + + virtual bool isLocalPeak(size_t x, size_t y) const = 0; + virtual bool isOverThreshold(size_t x, size_t y, float threshold) const = 0; + + virtual void setNormalizationFactor(size_t x, float factor) = 0; + virtual void setMagnitudeAt(size_t x, size_t y, float mag) = 0; + virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) = 0; + virtual void setPhaseAt(size_t x, size_t y, float phase) = 0; + + virtual QColor getColour(unsigned char index) const = 0; + virtual void setColour(unsigned char index, QColor colour) = 0; + +protected: + FFTCacheBase() { } +}; + + +/** + * For the in-memory FFT cache, we would like to cache magnitude with + * enough resolution to have gain applied afterwards and determine + * whether something is a peak or not, and also cache phase rather + * than only phase-adjusted frequency so that we don't have to + * recalculate if switching between phase and magnitude displays. At + * the same time, we don't want to take up too much memory. It's not + * expected to be accurate enough to be used as input for DSP or + * resynthesis code. + * + * This implies probably 16 bits for a normalized magnitude and at + * most 16 bits for phase. + * + * Each column's magnitudes are expected to be stored normalized + * to [0,1] with respect to the column, so the normalization + * factor should be calculated before all values in a column, and + * set appropriately. + */ + +class FFTMemoryCache : public FFTCacheBase +{ +public: + FFTMemoryCache(); // of size zero, call resize() before using + virtual ~FFTMemoryCache(); + + virtual size_t getWidth() const { return m_width; } + virtual size_t getHeight() const { return m_height; } + + virtual void resize(size_t width, size_t height); + virtual void reset(); // zero-fill or 1-fill as appropriate without changing size + + virtual float getMagnitudeAt(size_t x, size_t y) const { + return getNormalizedMagnitudeAt(x, y) * m_factor[x]; + } + + virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const { + return float(m_magnitude[x][y]) / 65535.0; + } + + virtual float getPhaseAt(size_t x, size_t y) const { + int16_t i = (int16_t)m_phase[x][y]; + return (float(i) / 32767.0) * M_PI; + } + + virtual bool isLocalPeak(size_t x, size_t y) const { + if (y > 0 && m_magnitude[x][y] < m_magnitude[x][y-1]) return false; + if (y < m_height-1 && m_magnitude[x][y] < m_magnitude[x][y+1]) return false; + return true; + } + + virtual bool isOverThreshold(size_t x, size_t y, float threshold) const { + if (threshold == 0.0) return true; + return getMagnitudeAt(x, y) > threshold; + } + + virtual void setNormalizationFactor(size_t x, float factor) { + if (x < m_width) m_factor[x] = factor; + } + + virtual void setMagnitudeAt(size_t x, size_t y, float mag) { + // norm factor must already be set + setNormalizedMagnitudeAt(x, y, mag / m_factor[x]); + } + + virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) { + if (x < m_width && y < m_height) { + m_magnitude[x][y] = uint16_t(norm * 65535.0); + } + } + + virtual void setPhaseAt(size_t x, size_t y, float phase) { + // phase in range -pi -> pi + if (x < m_width && y < m_height) { + m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI)); + } + } + + virtual QColor getColour(unsigned char index) const { + return m_colours[index]; + } + + virtual void setColour(unsigned char index, QColor colour) { + m_colours[index] = colour; + } + +private: + size_t m_width; + size_t m_height; + uint16_t **m_magnitude; + uint16_t **m_phase; + float *m_factor; + QColor m_colours[256]; + + void resize(uint16_t **&, size_t, size_t); +}; + +#endif