diff data/fft/FFTCache.h @ 152:21792a550ec9 last-cc-copyright

* Move the current DenseThreeDimensionalModel to EditableDenseThreeDimensionalModel (wow!), and make DTDM an abstract base * Move FFTFuzzyAdapter to FFTModel as a new subclass of DTDM
author Chris Cannam
date Mon, 31 Jul 2006 17:05:18 +0000
parents
children e5879045d22b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fft/FFTCache.h	Mon Jul 31 17:05:18 2006 +0000
@@ -0,0 +1,158 @@
+/* -*- 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 <cstdlib>
+#include <cmath>
+
+#include <stdint.h>
+
+class FFTCache
+{
+public:
+    virtual ~FFTCache() { }
+
+    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 getMaximumMagnitudeAt(size_t x) const = 0;
+    virtual float getPhaseAt(size_t x, size_t y) const = 0;
+
+    virtual void getValuesAt(size_t x, size_t y, float &real, float &imaginary) const = 0;
+
+    virtual bool haveSetColumnAt(size_t x) const = 0;
+
+    // may modify argument arrays
+    virtual void setColumnAt(size_t x, float *mags, float *phases, float factor) = 0;
+
+    // may modify argument arrays
+    virtual void setColumnAt(size_t x, float *reals, float *imags) = 0;
+
+    virtual void suspend() { }
+
+protected:
+    FFTCache() { }
+};
+
+
+/**
+ * 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 FFTCache
+{
+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 getMaximumMagnitudeAt(size_t x) const {
+        return m_factor[x];
+    }
+    
+    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 void getValuesAt(size_t x, size_t y, float &real, float &imag) const {
+        float mag = getMagnitudeAt(x, y);
+        float phase = getPhaseAt(x, y);
+        real = mag * cosf(phase);
+        imag = mag * sinf(phase);
+    }
+
+    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 bool haveSetColumnAt(size_t) const {
+        return true;
+    }
+
+    virtual void setColumnAt(size_t x, float *mags, float *phases, float factor) {
+        setNormalizationFactor(x, factor);
+        for (size_t y = 0; y < m_height; ++y) {
+            setMagnitudeAt(x, y, mags[y]);
+            setPhaseAt(x, y, phases[y]);
+        }
+    }
+
+    virtual void setColumnAt(size_t x, float *reals, float *imags);
+
+private:
+    size_t m_width;
+    size_t m_height;
+    uint16_t **m_magnitude;
+    uint16_t **m_phase;
+    float *m_factor;
+
+    void resize(uint16_t **&, size_t, size_t);
+};
+
+#endif