diff data/model/FFTModel.h @ 1126:39019ce29178 tony-2.0-integration

Merge through to branch for Tony 2.0
author Chris Cannam
date Thu, 20 Aug 2015 14:54:21 +0100
parents 5cbf71022679
children e94719f941ba 546d4e417346
line wrap: on
line diff
--- a/data/model/FFTModel.h	Fri Aug 14 18:16:14 2015 +0100
+++ b/data/model/FFTModel.h	Thu Aug 20 14:54:21 2015 +0100
@@ -13,27 +13,33 @@
     COPYING included with this distribution for more information.
 */
 
-#ifndef _FFT_MODEL_H_
-#define _FFT_MODEL_H_
+#ifndef FFT_MODEL_H
+#define FFT_MODEL_H
 
-#include "data/fft/FFTDataServer.h"
 #include "DenseThreeDimensionalModel.h"
+#include "DenseTimeValueModel.h"
+
+#include "base/Window.h"
+
+#include "data/fft/FFTapi.h"
 
 #include <set>
-#include <map>
+#include <vector>
+#include <complex>
+#include <deque>
 
 /**
  * An implementation of DenseThreeDimensionalModel that makes FFT data
  * derived from a DenseTimeValueModel available as a generic data
- * grid.  The FFT data is acquired using FFTDataServer.  Note that any
- * of the accessor functions may throw AllocationFailed if a cache
- * resize fails.
+ * grid.
  */
-
 class FFTModel : public DenseThreeDimensionalModel
 {
     Q_OBJECT
 
+    //!!! threading requirements?
+    //!!! doubles? since we're not caching much
+
 public:
     /**
      * Construct an FFT model derived from the given
@@ -43,108 +49,62 @@
      * If the model has multiple channels use only the given channel,
      * unless the channel is -1 in which case merge all available
      * channels.
-     * 
-     * If polar is true, the data will normally be retrieved from the
-     * FFT model in magnitude/phase form; otherwise it will normally
-     * be retrieved in "cartesian" real/imaginary form.  The results
-     * should be the same either way, but a "polar" model addressed in
-     * "cartesian" form or vice versa may suffer a performance
-     * penalty.
-     *
-     * The fillFromColumn argument gives a hint that the FFT data
-     * server should aim to start calculating FFT data at that column
-     * number if possible, as that is likely to be requested first.
      */
     FFTModel(const DenseTimeValueModel *model,
              int channel,
              WindowType windowType,
              int windowSize,
              int windowIncrement,
-             int fftSize,
-             bool polar,
-             StorageAdviser::Criteria criteria = StorageAdviser::NoCriteria,
-             sv_frame_t fillFromFrame = 0);
+             int fftSize);
     ~FFTModel();
 
-    inline float getMagnitudeAt(int x, int y) {
-        return m_server->getMagnitudeAt(x << m_xshift, y << m_yshift);
-    }
-    inline float getNormalizedMagnitudeAt(int x, int y) {
-        return m_server->getNormalizedMagnitudeAt(x << m_xshift, y << m_yshift);
-    }
-    inline float getMaximumMagnitudeAt(int x) {
-        return m_server->getMaximumMagnitudeAt(x << m_xshift);
-    }
-    inline float getPhaseAt(int x, int y) {
-        return m_server->getPhaseAt(x << m_xshift, y << m_yshift);
-    }
-    inline void getValuesAt(int x, int y, float &real, float &imaginary) {
-        m_server->getValuesAt(x << m_xshift, y << m_yshift, real, imaginary);
-    }
-    inline bool isColumnAvailable(int x) const {
-        return m_server->isColumnReady(x << m_xshift);
-    }
-
-    inline bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) {
-        return m_server->getMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
-    }
-    inline bool getNormalizedMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) {
-        return m_server->getNormalizedMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
-    }
-    inline bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) {
-        return m_server->getPhasesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
-    }
-    inline bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) {
-        return m_server->getValuesAt(x << m_xshift, reals, imaginaries, minbin << m_yshift, count, getYRatio());
-    }
-
-    inline sv_frame_t getFillExtent() const { return m_server->getFillExtent(); }
-
     // DenseThreeDimensionalModel and Model methods:
     //
-    inline virtual int getWidth() const {
-        return m_server->getWidth() >> m_xshift;
-    }
-    inline virtual int getHeight() const {
-        // If there is no y-shift, the server's height (based on its
-        // fftsize/2 + 1) is correct.  If there is a shift, then the
-        // server is using a larger fft size than we want, so we shift
-        // it right as many times as necessary, but then we need to
-        // re-add the "+1" part (because ((fftsize*2)/2 + 1) / 2 !=
-        // fftsize/2 + 1).
-        return (m_server->getHeight() >> m_yshift) + (m_yshift > 0 ? 1 : 0);
-    }
-    virtual float getValueAt(int x, int y) const {
-        return const_cast<FFTModel *>(this)->getMagnitudeAt(x, y);
-    }
-    virtual bool isOK() const {
-        return m_server && m_server->getModel();
-    }
-    virtual sv_frame_t getStartFrame() const {
-        return 0;
-    }
+    virtual int getWidth() const;
+    virtual int getHeight() const;
+    virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); }
+    virtual bool isOK() const { return m_model && m_model->isOK(); }
+    virtual sv_frame_t getStartFrame() const { return 0; }
     virtual sv_frame_t getEndFrame() const {
         return sv_frame_t(getWidth()) * getResolution() + getResolution();
     }
-    virtual sv_samplerate_t getSampleRate() const;
-    virtual int getResolution() const {
-        return m_server->getWindowIncrement() << m_xshift;
+    virtual sv_samplerate_t getSampleRate() const {
+        return isOK() ? m_model->getSampleRate() : 0;
     }
-    virtual int getYBinCount() const {
-        return getHeight();
+    virtual int getResolution() const { return m_windowIncrement; }
+    virtual int getYBinCount() const { return getHeight(); }
+    virtual float getMinimumLevel() const { return 0.f; } // Can't provide
+    virtual float getMaximumLevel() const { return 1.f; } // Can't provide
+    virtual Column getColumn(int x) const; // magnitudes
+    virtual QString getBinName(int n) const;
+    virtual bool shouldUseLogValueScale() const { return true; }
+    virtual int getCompletion() const {
+        int c = 100;
+        if (m_model) {
+            if (m_model->isReady(&c)) return 100;
+        }
+        return c;
     }
-    virtual float getMinimumLevel() const {
-        return 0.f; // Can't provide
-    }
-    virtual float getMaximumLevel() const {
-        return 1.f; // Can't provide
-    }
-    virtual Column getColumn(int x) const;
-    virtual QString getBinName(int n) const;
+    virtual QString getError() const { return ""; } //!!!???
+    virtual sv_frame_t getFillExtent() const { return getEndFrame(); }
 
-    virtual bool shouldUseLogValueScale() const {
-        return true; // Although obviously it's up to the user...
-    }
+    // FFTModel methods:
+    //
+    int getChannel() const { return m_channel; }
+    WindowType getWindowType() const { return m_windowType; }
+    int getWindowSize() const { return m_windowSize; }
+    int getWindowIncrement() const { return m_windowIncrement; }
+    int getFFTSize() const { return m_fftSize; }
+    
+    float getMagnitudeAt(int x, int y) const;
+    float getMaximumMagnitudeAt(int x) const;
+    float getPhaseAt(int x, int y) const;
+    void getValuesAt(int x, int y, float &real, float &imaginary) const;
+    bool isColumnAvailable(int x) const;
+    bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
+    bool getNormalizedMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
+    bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
+    bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
 
     /**
      * Calculate an estimated frequency for a stable signal in this
@@ -176,13 +136,6 @@
     virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
                                        int ymin = 0, int ymax = 0);
 
-    virtual int getCompletion() const { return m_server->getFillCompletion(); }
-    virtual QString getError() const { return m_server->getError(); }
-
-    virtual void suspend() { m_server->suspend(); }
-    virtual void suspendWrites() { m_server->suspendWrites(); }
-    virtual void resume() { m_server->resume(); }
-
     QString getTypeName() const { return tr("FFT"); }
 
 public slots:
@@ -192,23 +145,44 @@
     FFTModel(const FFTModel &); // not implemented
     FFTModel &operator=(const FFTModel &); // not implemented
 
-    FFTDataServer *m_server;
-    int m_xshift;
-    int m_yshift;
-
-    FFTDataServer *getServer(const DenseTimeValueModel *,
-                             int, WindowType, int, int, int,
-                             bool, StorageAdviser::Criteria, sv_frame_t);
-
+    const DenseTimeValueModel *m_model;
+    int m_channel;
+    WindowType m_windowType;
+    int m_windowSize;
+    int m_windowIncrement;
+    int m_fftSize;
+    Window<float> m_windower;
+    FFTForward m_fft;
+    
     int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
                               int bin, float &percentile) const;
 
-    int getYRatio() {
-        int ys = m_yshift;
-        int r = 1;
-        while (ys) { --ys; r <<= 1; }
-        return r;
+    std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
+        sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
+        sv_frame_t endFrame = startFrame + m_windowSize;
+        // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
+        startFrame -= m_windowSize / 2;
+        endFrame -= m_windowSize / 2;
+        return { startFrame, endFrame };
     }
+
+    std::vector<std::complex<float> > getFFTColumn(int column) const;
+    std::vector<float> getSourceSamples(int column) const;
+    std::vector<float> getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
+    std::vector<float> getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
+
+    struct SavedSourceData {
+        std::pair<sv_frame_t, sv_frame_t> range;
+        std::vector<float> data;
+    };
+    mutable SavedSourceData m_savedData;
+    
+    struct SavedColumn {
+        int n;
+        std::vector<std::complex<float> > col;
+    };
+    mutable std::deque<SavedColumn> m_cached;
+    size_t m_cacheSize;
 };
 
 #endif