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