annotate data/model/FFTModel.h @ 1188:d9698ee93659 spectrogram-minor-refactor

Extend column logic to peak frequency display as well, and correct some scopes according to whether values are per source column or per target pixel
author Chris Cannam
date Mon, 20 Jun 2016 12:00:32 +0100
parents 12a8daa89970
children 6d09ad2ab21f
rev   line source
Chris@152 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@152 2
Chris@152 3 /*
Chris@152 4 Sonic Visualiser
Chris@152 5 An audio file viewer and annotation editor.
Chris@152 6 Centre for Digital Music, Queen Mary, University of London.
Chris@152 7 This file copyright 2006 Chris Cannam.
Chris@152 8
Chris@152 9 This program is free software; you can redistribute it and/or
Chris@152 10 modify it under the terms of the GNU General Public License as
Chris@152 11 published by the Free Software Foundation; either version 2 of the
Chris@152 12 License, or (at your option) any later version. See the file
Chris@152 13 COPYING included with this distribution for more information.
Chris@152 14 */
Chris@152 15
Chris@1086 16 #ifndef FFT_MODEL_H
Chris@1086 17 #define FFT_MODEL_H
Chris@152 18
Chris@152 19 #include "DenseThreeDimensionalModel.h"
Chris@1090 20 #include "DenseTimeValueModel.h"
Chris@1090 21
Chris@1090 22 #include "base/Window.h"
Chris@152 23
Chris@1091 24 #include "data/fft/FFTapi.h"
Chris@1091 25
Chris@275 26 #include <set>
Chris@1091 27 #include <vector>
Chris@1091 28 #include <complex>
Chris@1093 29 #include <deque>
Chris@275 30
Chris@254 31 /**
Chris@254 32 * An implementation of DenseThreeDimensionalModel that makes FFT data
Chris@387 33 * derived from a DenseTimeValueModel available as a generic data
Chris@1090 34 * grid.
Chris@254 35 */
Chris@152 36 class FFTModel : public DenseThreeDimensionalModel
Chris@152 37 {
Chris@247 38 Q_OBJECT
Chris@247 39
Chris@1092 40 //!!! threading requirements?
Chris@1092 41 //!!! doubles? since we're not caching much
Chris@1092 42
Chris@152 43 public:
Chris@254 44 /**
Chris@254 45 * Construct an FFT model derived from the given
Chris@254 46 * DenseTimeValueModel, with the given window parameters and FFT
Chris@254 47 * size (which may exceed the window size, for zero-padded FFTs).
Chris@254 48 *
Chris@254 49 * If the model has multiple channels use only the given channel,
Chris@254 50 * unless the channel is -1 in which case merge all available
Chris@254 51 * channels.
Chris@254 52 */
Chris@152 53 FFTModel(const DenseTimeValueModel *model,
Chris@152 54 int channel,
Chris@152 55 WindowType windowType,
Chris@929 56 int windowSize,
Chris@929 57 int windowIncrement,
Chris@1090 58 int fftSize);
Chris@152 59 ~FFTModel();
Chris@152 60
Chris@152 61 // DenseThreeDimensionalModel and Model methods:
Chris@152 62 //
Chris@1090 63 virtual int getWidth() const;
Chris@1090 64 virtual int getHeight() const;
Chris@1090 65 virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); }
Chris@1090 66 virtual bool isOK() const { return m_model && m_model->isOK(); }
Chris@1090 67 virtual sv_frame_t getStartFrame() const { return 0; }
Chris@1038 68 virtual sv_frame_t getEndFrame() const {
Chris@1038 69 return sv_frame_t(getWidth()) * getResolution() + getResolution();
Chris@152 70 }
Chris@1090 71 virtual sv_samplerate_t getSampleRate() const {
Chris@1090 72 return isOK() ? m_model->getSampleRate() : 0;
Chris@152 73 }
Chris@1090 74 virtual int getResolution() const { return m_windowIncrement; }
Chris@1090 75 virtual int getYBinCount() const { return getHeight(); }
Chris@1090 76 virtual float getMinimumLevel() const { return 0.f; } // Can't provide
Chris@1090 77 virtual float getMaximumLevel() const { return 1.f; } // Can't provide
Chris@1090 78 virtual Column getColumn(int x) const; // magnitudes
Chris@1090 79 virtual QString getBinName(int n) const;
Chris@1090 80 virtual bool shouldUseLogValueScale() const { return true; }
Chris@1090 81 virtual int getCompletion() const {
Chris@1090 82 int c = 100;
Chris@1093 83 if (m_model) {
Chris@1093 84 if (m_model->isReady(&c)) return 100;
Chris@1093 85 }
Chris@1090 86 return c;
Chris@152 87 }
Chris@1090 88 virtual QString getError() const { return ""; } //!!!???
Chris@1090 89 virtual sv_frame_t getFillExtent() const { return getEndFrame(); }
Chris@152 90
Chris@1090 91 // FFTModel methods:
Chris@1090 92 //
Chris@1090 93 int getChannel() const { return m_channel; }
Chris@1090 94 WindowType getWindowType() const { return m_windowType; }
Chris@1090 95 int getWindowSize() const { return m_windowSize; }
Chris@1090 96 int getWindowIncrement() const { return m_windowIncrement; }
Chris@1090 97 int getFFTSize() const { return m_fftSize; }
Chris@1090 98
Chris@1090 99 float getMagnitudeAt(int x, int y) const;
Chris@1090 100 float getMaximumMagnitudeAt(int x) const;
Chris@1090 101 float getPhaseAt(int x, int y) const;
Chris@1090 102 void getValuesAt(int x, int y, float &real, float &imaginary) const;
Chris@1090 103 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 104 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 105 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
Chris@478 106
Chris@275 107 /**
Chris@275 108 * Calculate an estimated frequency for a stable signal in this
Chris@275 109 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 110 * the signal is not stable here.
Chris@275 111 */
Chris@1045 112 virtual bool estimateStableFrequency(int x, int y, double &frequency);
Chris@275 113
Chris@275 114 enum PeakPickType
Chris@275 115 {
Chris@275 116 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 117 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 118 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 119 };
Chris@275 120
Chris@929 121 typedef std::set<int> PeakLocationSet; // bin
Chris@1045 122 typedef std::map<int, double> PeakSet; // bin -> freq
Chris@275 123
Chris@275 124 /**
Chris@275 125 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 126 * ymax is zero, getHeight()-1 will be used.
Chris@275 127 */
Chris@929 128 virtual PeakLocationSet getPeaks(PeakPickType type, int x,
Chris@929 129 int ymin = 0, int ymax = 0);
Chris@275 130
Chris@275 131 /**
Chris@275 132 * Return locations and estimated stable frequencies of peak bins.
Chris@275 133 */
Chris@929 134 virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
Chris@929 135 int ymin = 0, int ymax = 0);
Chris@273 136
Chris@345 137 QString getTypeName() const { return tr("FFT"); }
Chris@345 138
Chris@360 139 public slots:
Chris@360 140 void sourceModelAboutToBeDeleted();
Chris@360 141
Chris@152 142 private:
Chris@297 143 FFTModel(const FFTModel &); // not implemented
Chris@152 144 FFTModel &operator=(const FFTModel &); // not implemented
Chris@152 145
Chris@1090 146 const DenseTimeValueModel *m_model;
Chris@1090 147 int m_channel;
Chris@1090 148 WindowType m_windowType;
Chris@1090 149 int m_windowSize;
Chris@1090 150 int m_windowIncrement;
Chris@1090 151 int m_fftSize;
Chris@1090 152 Window<float> m_windower;
Chris@1091 153 FFTForward m_fft;
Chris@1090 154
Chris@1040 155 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
Chris@1040 156 int bin, float &percentile) const;
Chris@1091 157
Chris@1091 158 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
Chris@1091 159 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
Chris@1091 160 sv_frame_t endFrame = startFrame + m_windowSize;
Chris@1091 161 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
Chris@1091 162 startFrame -= m_windowSize / 2;
Chris@1091 163 endFrame -= m_windowSize / 2;
Chris@1091 164 return { startFrame, endFrame };
Chris@1091 165 }
Chris@1091 166
Chris@1091 167 std::vector<std::complex<float> > getFFTColumn(int column) const;
Chris@1091 168 std::vector<float> getSourceSamples(int column) const;
Chris@1094 169 std::vector<float> getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1095 170 std::vector<float> getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1093 171
Chris@1094 172 struct SavedSourceData {
Chris@1094 173 std::pair<sv_frame_t, sv_frame_t> range;
Chris@1094 174 std::vector<float> data;
Chris@1094 175 };
Chris@1094 176 mutable SavedSourceData m_savedData;
Chris@1094 177
Chris@1093 178 struct SavedColumn {
Chris@1093 179 int n;
Chris@1093 180 std::vector<std::complex<float> > col;
Chris@1093 181 };
Chris@1093 182 mutable std::deque<SavedColumn> m_cached;
Chris@1093 183 size_t m_cacheSize;
Chris@152 184 };
Chris@152 185
Chris@152 186 #endif