Mercurial > hg > svgui
changeset 85:d31c4f5230d7
* 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 | c683705adcbf |
children | 93a7efc75fb7 |
files | layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
diffstat | 2 files changed, 4 insertions(+), 173 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Sat Apr 29 19:20:28 2006 +0000 +++ b/layer/SpectrogramLayer.cpp Tue May 02 12:27:41 2006 +0000 @@ -20,6 +20,7 @@ #include "base/AudioLevel.h" #include "base/Window.h" #include "base/Pitch.h" +#include "base/FFTCache.h" #include <QPainter> #include <QImage> @@ -1210,84 +1211,6 @@ return input; } - -SpectrogramLayer::Cache::Cache() : - m_width(0), - m_height(0), - m_magnitude(0), - m_phase(0), - m_factor(0) -{ -} - -SpectrogramLayer::Cache::~Cache() -{ - std::cerr << "SpectrogramLayer::Cache[" << this << "]::~Cache" << std::endl; - - for (size_t i = 0; i < m_width; ++i) { - if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]); - if (m_phase && m_phase[i]) free(m_phase[i]); - } - - if (m_magnitude) free(m_magnitude); - if (m_phase) free(m_phase); - if (m_factor) free(m_factor); -} - -void -SpectrogramLayer::Cache::resize(size_t width, size_t height) -{ - std::cerr << "SpectrogramLayer::Cache[" << this << "]::resize(" << width << "x" << height << " = " << width*height << ")" << std::endl; - - if (m_width == width && m_height == height) return; - - resize(m_magnitude, width, height); - resize(m_phase, width, height); - - m_factor = (float *)realloc(m_factor, width * sizeof(float)); - - m_width = width; - m_height = height; - - std::cerr << "done, width = " << m_width << " height = " << m_height << std::endl; -} - -void -SpectrogramLayer::Cache::resize(uint16_t **&array, size_t width, size_t height) -{ - for (size_t i = width; i < m_width; ++i) { - free(array[i]); - } - - if (width != m_width) { - array = (uint16_t **)realloc(array, width * sizeof(uint16_t *)); - if (!array) throw std::bad_alloc(); - MUNLOCK(array, width * sizeof(uint16_t *)); - } - - for (size_t i = m_width; i < width; ++i) { - array[i] = 0; - } - - for (size_t i = 0; i < width; ++i) { - array[i] = (uint16_t *)realloc(array[i], height * sizeof(uint16_t)); - if (!array[i]) throw std::bad_alloc(); - MUNLOCK(array[i], height * sizeof(uint16_t)); - } -} - -void -SpectrogramLayer::Cache::reset() -{ - for (size_t x = 0; x < m_width; ++x) { - for (size_t y = 0; y < m_height; ++y) { - m_magnitude[x][y] = 0; - m_phase[x][y] = 0; - } - m_factor[x] = 1.0; - } -} - void SpectrogramLayer::CacheFillThread::run() { @@ -1356,7 +1279,7 @@ size_t height = windowSize / 2; if (!m_layer.m_cache) { - m_layer.m_cache = new Cache; + m_layer.m_cache = new FFTMemoryCache; } m_layer.m_cache->resize(width, height);
--- a/layer/SpectrogramLayer.h Sat Apr 29 19:20:28 2006 +0000 +++ b/layer/SpectrogramLayer.h Tue May 02 12:27:41 2006 +0000 @@ -28,13 +28,12 @@ #include <fftw3.h> -#include <stdint.h> - class View; class QPainter; class QImage; class QPixmap; class QTimer; +class FFTCacheBase; /** * SpectrogramLayer represents waveform data (obtained from a @@ -218,100 +217,9 @@ BinDisplay m_binDisplay; bool m_normalizeColumns; - // We would like to cache magnitude in a way that can have gain - // applied afterwards and can 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 waste too much memory. - - // This implies probably 16 bits for a normalized magnitude (in - // dB?) 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 Cache { - public: - Cache(); // of size zero, call resize() before using - ~Cache(); - - size_t getWidth() const { return m_width; } - size_t getHeight() const { return m_height; } - - void resize(size_t width, size_t height); - void reset(); // zero-fill or 1-fill as appropriate without changing size - - float getMagnitudeAt(size_t x, size_t y) const { - return getNormalizedMagnitudeAt(x, y) * m_factor[x]; - } - - float getNormalizedMagnitudeAt(size_t x, size_t y) const { - return float(m_magnitude[x][y]) / 65535.0; - } - - 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; - } - - 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; - } - - bool isOverThreshold(size_t x, size_t y, float threshold) const { - if (threshold == 0.0) return true; - return getMagnitudeAt(x, y) > threshold; - } - - void setNormalizationFactor(size_t x, float factor) { - if (x < m_width) m_factor[x] = factor; - } - - void setMagnitudeAt(size_t x, size_t y, float mag) { - // norm factor must already be set - setNormalizedMagnitudeAt(x, y, mag / m_factor[x]); - } - - 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); - } - } - - 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)); - } - } - - QColor getColour(unsigned char index) const { - return m_colours[index]; - } - - 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); - }; - enum { NO_VALUE = 0 }; // colour index for unused pixels - Cache *m_cache; + FFTCacheBase *m_cache; bool m_cacheInvalid; class CacheFillThread : public QThread