lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _FFT_MODEL_H_ lbajardsilogic@0: #define _FFT_MODEL_H_ lbajardsilogic@0: lbajardsilogic@0: #include "data/fft/FFTDataServer.h" lbajardsilogic@0: #include "DenseThreeDimensionalModel.h" lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * An implementation of DenseThreeDimensionalModel that makes FFT data lbajardsilogic@0: * derived from a DenseTimeValueModel available as a generic data grid. lbajardsilogic@0: * The FFT data is acquired using FFTDataServer. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: class FFTModel : public DenseThreeDimensionalModel lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: /** lbajardsilogic@0: * Construct an FFT model derived from the given lbajardsilogic@0: * DenseTimeValueModel, with the given window parameters and FFT lbajardsilogic@0: * size (which may exceed the window size, for zero-padded FFTs). lbajardsilogic@0: * lbajardsilogic@0: * If the model has multiple channels use only the given channel, lbajardsilogic@0: * unless the channel is -1 in which case merge all available lbajardsilogic@0: * channels. lbajardsilogic@0: * lbajardsilogic@0: * If polar is true, the data will normally be retrieved from the lbajardsilogic@0: * FFT model in magnitude/phase form; otherwise it will normally lbajardsilogic@0: * be retrieved in "cartesian" real/imaginary form. The results lbajardsilogic@0: * should be the same either way, but a "polar" model addressed in lbajardsilogic@0: * "cartesian" form or vice versa may suffer a performance lbajardsilogic@0: * penalty. lbajardsilogic@0: * lbajardsilogic@0: * The fillFromColumn argument gives a hint that the FFT data lbajardsilogic@0: * server should aim to start calculating FFT data at that column lbajardsilogic@0: * number if possible, as that is likely to be requested first. lbajardsilogic@0: */ lbajardsilogic@0: FFTModel(const DenseTimeValueModel *model, lbajardsilogic@0: int channel, lbajardsilogic@0: WindowType windowType, lbajardsilogic@0: size_t windowSize, lbajardsilogic@0: size_t windowIncrement, lbajardsilogic@0: size_t fftSize, lbajardsilogic@0: bool polar, lbajardsilogic@0: size_t fillFromColumn = 0); lbajardsilogic@0: ~FFTModel(); lbajardsilogic@0: lbajardsilogic@0: float getMagnitudeAt(size_t x, size_t y) { lbajardsilogic@0: return m_server->getMagnitudeAt(x << m_xshift, y << m_yshift); lbajardsilogic@0: } lbajardsilogic@0: float getNormalizedMagnitudeAt(size_t x, size_t y) { lbajardsilogic@0: return m_server->getNormalizedMagnitudeAt(x << m_xshift, y << m_yshift); lbajardsilogic@0: } lbajardsilogic@0: float getMaximumMagnitudeAt(size_t x) { lbajardsilogic@0: return m_server->getMaximumMagnitudeAt(x << m_xshift); lbajardsilogic@0: } lbajardsilogic@0: float getPhaseAt(size_t x, size_t y) { lbajardsilogic@0: return m_server->getPhaseAt(x << m_xshift, y << m_yshift); lbajardsilogic@0: } lbajardsilogic@0: void getValuesAt(size_t x, size_t y, float &real, float &imaginary) { lbajardsilogic@0: m_server->getValuesAt(x << m_xshift, y << m_yshift, real, imaginary); lbajardsilogic@0: } lbajardsilogic@0: bool isColumnAvailable(size_t x) const { lbajardsilogic@0: return m_server->isColumnReady(x << m_xshift); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t getFillExtent() const { return m_server->getFillExtent(); } lbajardsilogic@0: lbajardsilogic@0: // DenseThreeDimensionalModel and Model methods: lbajardsilogic@0: // lbajardsilogic@0: virtual size_t getWidth() const { lbajardsilogic@0: return m_server->getWidth() >> m_xshift; lbajardsilogic@0: } lbajardsilogic@0: virtual size_t getHeight() const { lbajardsilogic@0: // If there is no y-shift, the server's height (based on its lbajardsilogic@0: // fftsize/2 + 1) is correct. If there is a shift, then the lbajardsilogic@0: // server is using a larger fft size than we want, so we shift lbajardsilogic@0: // it right as many times as necessary, but then we need to lbajardsilogic@0: // re-add the "+1" part (because ((fftsize*2)/2 + 1) / 2 != lbajardsilogic@0: // fftsize/2 + 1). lbajardsilogic@0: return (m_server->getHeight() >> m_yshift) + (m_yshift > 0 ? 1 : 0); lbajardsilogic@0: } lbajardsilogic@0: virtual float getValueAt(size_t x, size_t y) const { lbajardsilogic@0: return const_cast(this)->getMagnitudeAt(x, y); lbajardsilogic@0: } lbajardsilogic@0: virtual bool isOK() const { lbajardsilogic@0: return m_server && m_server->getModel(); lbajardsilogic@0: } lbajardsilogic@0: virtual size_t getStartFrame() const { lbajardsilogic@0: return 0; lbajardsilogic@0: } lbajardsilogic@0: virtual size_t getEndFrame() const { lbajardsilogic@0: return getWidth() * getResolution() + getResolution(); lbajardsilogic@0: } lbajardsilogic@0: virtual size_t getSampleRate() const; lbajardsilogic@0: virtual size_t getResolution() const { lbajardsilogic@0: return m_server->getWindowIncrement() << m_xshift; lbajardsilogic@0: } lbajardsilogic@0: virtual size_t getYBinCount() const { lbajardsilogic@0: return getHeight(); lbajardsilogic@0: } lbajardsilogic@0: virtual float getMinimumLevel() const { lbajardsilogic@0: return 0.f; // Can't provide lbajardsilogic@0: } lbajardsilogic@0: virtual float getMaximumLevel() const { lbajardsilogic@0: return 1.f; // Can't provide lbajardsilogic@0: } lbajardsilogic@0: virtual void getColumn(size_t x, Column &result) const; lbajardsilogic@0: virtual QString getBinName(size_t n) const; lbajardsilogic@0: lbajardsilogic@0: virtual int getCompletion() const { return m_server->getFillCompletion(); } lbajardsilogic@0: lbajardsilogic@0: virtual Model *clone() const; lbajardsilogic@0: lbajardsilogic@0: virtual void suspend() { m_server->suspend(); } lbajardsilogic@0: virtual void suspendWrites() { m_server->suspendWrites(); } lbajardsilogic@0: virtual void resume() { m_server->resume(); } lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: FFTModel(const FFTModel &); lbajardsilogic@0: FFTModel &operator=(const FFTModel &); // not implemented lbajardsilogic@0: lbajardsilogic@0: FFTDataServer *m_server; lbajardsilogic@0: int m_xshift; lbajardsilogic@0: int m_yshift; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: #endif