Mercurial > hg > svcore
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