Chris@152: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@152: Chris@152: /* Chris@152: Sonic Visualiser Chris@152: An audio file viewer and annotation editor. Chris@152: Centre for Digital Music, Queen Mary, University of London. Chris@152: This file copyright 2006 Chris Cannam. Chris@152: Chris@152: This program is free software; you can redistribute it and/or Chris@152: modify it under the terms of the GNU General Public License as Chris@152: published by the Free Software Foundation; either version 2 of the Chris@152: License, or (at your option) any later version. See the file Chris@152: COPYING included with this distribution for more information. Chris@152: */ Chris@152: Chris@1086: #ifndef FFT_MODEL_H Chris@1086: #define FFT_MODEL_H Chris@152: Chris@152: #include "DenseThreeDimensionalModel.h" Chris@1090: #include "DenseTimeValueModel.h" Chris@1090: Chris@1090: #include "base/Window.h" Chris@152: Chris@1091: #include "data/fft/FFTapi.h" Chris@1091: Chris@275: #include Chris@1091: #include Chris@1091: #include Chris@1093: #include Chris@275: Chris@254: /** Chris@254: * An implementation of DenseThreeDimensionalModel that makes FFT data Chris@387: * derived from a DenseTimeValueModel available as a generic data Chris@1090: * grid. Chris@254: */ Chris@152: class FFTModel : public DenseThreeDimensionalModel Chris@152: { Chris@247: Q_OBJECT Chris@247: Chris@1092: //!!! threading requirements? Chris@1092: //!!! doubles? since we're not caching much Chris@1092: Chris@152: public: Chris@254: /** Chris@254: * Construct an FFT model derived from the given Chris@254: * DenseTimeValueModel, with the given window parameters and FFT Chris@254: * size (which may exceed the window size, for zero-padded FFTs). Chris@254: * Chris@254: * If the model has multiple channels use only the given channel, Chris@254: * unless the channel is -1 in which case merge all available Chris@254: * channels. Chris@254: */ Chris@152: FFTModel(const DenseTimeValueModel *model, Chris@152: int channel, Chris@152: WindowType windowType, Chris@929: int windowSize, Chris@929: int windowIncrement, Chris@1090: int fftSize); Chris@152: ~FFTModel(); Chris@152: Chris@152: // DenseThreeDimensionalModel and Model methods: Chris@152: // Chris@1090: virtual int getWidth() const; Chris@1090: virtual int getHeight() const; Chris@1090: virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); } Chris@1090: virtual bool isOK() const { return m_model && m_model->isOK(); } Chris@1090: virtual sv_frame_t getStartFrame() const { return 0; } Chris@1038: virtual sv_frame_t getEndFrame() const { Chris@1038: return sv_frame_t(getWidth()) * getResolution() + getResolution(); Chris@152: } Chris@1090: virtual sv_samplerate_t getSampleRate() const { Chris@1090: return isOK() ? m_model->getSampleRate() : 0; Chris@152: } Chris@1090: virtual int getResolution() const { return m_windowIncrement; } Chris@1090: virtual int getYBinCount() const { return getHeight(); } Chris@1090: virtual float getMinimumLevel() const { return 0.f; } // Can't provide Chris@1090: virtual float getMaximumLevel() const { return 1.f; } // Can't provide Chris@1090: virtual Column getColumn(int x) const; // magnitudes Chris@1200: virtual Column getPhases(int x) const; Chris@1090: virtual QString getBinName(int n) const; Chris@1090: virtual bool shouldUseLogValueScale() const { return true; } Chris@1090: virtual int getCompletion() const { Chris@1090: int c = 100; Chris@1093: if (m_model) { Chris@1093: if (m_model->isReady(&c)) return 100; Chris@1093: } Chris@1090: return c; Chris@152: } Chris@1090: virtual QString getError() const { return ""; } //!!!??? Chris@1090: virtual sv_frame_t getFillExtent() const { return getEndFrame(); } Chris@152: Chris@1090: // FFTModel methods: Chris@1090: // Chris@1090: int getChannel() const { return m_channel; } Chris@1090: WindowType getWindowType() const { return m_windowType; } Chris@1090: int getWindowSize() const { return m_windowSize; } Chris@1090: int getWindowIncrement() const { return m_windowIncrement; } Chris@1090: int getFFTSize() const { return m_fftSize; } Chris@1200: Chris@1200: //!!! review which of these are ever actually called Chris@1090: Chris@1090: float getMagnitudeAt(int x, int y) const; Chris@1090: float getMaximumMagnitudeAt(int x) const; Chris@1090: float getPhaseAt(int x, int y) const; Chris@1090: void getValuesAt(int x, int y, float &real, float &imaginary) const; Chris@1090: bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const; Chris@1090: bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const; Chris@1090: bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const; Chris@478: Chris@275: /** Chris@275: * Calculate an estimated frequency for a stable signal in this Chris@275: * bin, using phase unwrapping. This will be completely wrong if Chris@275: * the signal is not stable here. Chris@275: */ Chris@1045: virtual bool estimateStableFrequency(int x, int y, double &frequency); Chris@275: Chris@275: enum PeakPickType Chris@275: { Chris@275: AllPeaks, /// Any bin exceeding its immediate neighbours Chris@275: MajorPeaks, /// Peaks picked using sliding median window Chris@275: MajorPitchAdaptivePeaks /// Bigger window for higher frequencies Chris@275: }; Chris@275: Chris@929: typedef std::set PeakLocationSet; // bin Chris@1045: typedef std::map PeakSet; // bin -> freq Chris@275: Chris@275: /** Chris@275: * Return locations of peak bins in the range [ymin,ymax]. If Chris@275: * ymax is zero, getHeight()-1 will be used. Chris@275: */ Chris@929: virtual PeakLocationSet getPeaks(PeakPickType type, int x, Chris@1191: int ymin = 0, int ymax = 0) const; Chris@275: Chris@275: /** Chris@275: * Return locations and estimated stable frequencies of peak bins. Chris@275: */ Chris@929: virtual PeakSet getPeakFrequencies(PeakPickType type, int x, Chris@1191: int ymin = 0, int ymax = 0) const; Chris@273: Chris@345: QString getTypeName() const { return tr("FFT"); } Chris@345: Chris@360: public slots: Chris@360: void sourceModelAboutToBeDeleted(); Chris@360: Chris@152: private: Chris@297: FFTModel(const FFTModel &); // not implemented Chris@152: FFTModel &operator=(const FFTModel &); // not implemented Chris@152: Chris@1090: const DenseTimeValueModel *m_model; Chris@1090: int m_channel; Chris@1090: WindowType m_windowType; Chris@1090: int m_windowSize; Chris@1090: int m_windowIncrement; Chris@1090: int m_fftSize; Chris@1090: Window m_windower; Chris@1091: FFTForward m_fft; Chris@1090: Chris@1040: int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate, Chris@1040: int bin, float &percentile) const; Chris@1091: Chris@1091: std::pair getSourceSampleRange(int column) const { Chris@1091: sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column); Chris@1091: sv_frame_t endFrame = startFrame + m_windowSize; Chris@1091: // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0) Chris@1091: startFrame -= m_windowSize / 2; Chris@1091: endFrame -= m_windowSize / 2; Chris@1091: return { startFrame, endFrame }; Chris@1091: } Chris@1091: Chris@1091: std::vector > getFFTColumn(int column) const; Chris@1091: std::vector getSourceSamples(int column) const; Chris@1094: std::vector getSourceData(std::pair) const; Chris@1095: std::vector getSourceDataUncached(std::pair) const; Chris@1093: Chris@1094: struct SavedSourceData { Chris@1094: std::pair range; Chris@1094: std::vector data; Chris@1094: }; Chris@1094: mutable SavedSourceData m_savedData; Chris@1094: Chris@1093: struct SavedColumn { Chris@1093: int n; Chris@1093: std::vector > col; Chris@1093: }; Chris@1093: mutable std::deque m_cached; Chris@1093: size_t m_cacheSize; Chris@152: }; Chris@152: Chris@152: #endif