Mercurial > hg > svcore
comparison 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 |
comparison
equal
deleted
inserted
replaced
1119:e22bfe8ca248 | 1126:39019ce29178 |
---|---|
11 published by the Free Software Foundation; either version 2 of the | 11 published by the Free Software Foundation; either version 2 of the |
12 License, or (at your option) any later version. See the file | 12 License, or (at your option) any later version. See the file |
13 COPYING included with this distribution for more information. | 13 COPYING included with this distribution for more information. |
14 */ | 14 */ |
15 | 15 |
16 #ifndef _FFT_MODEL_H_ | 16 #ifndef FFT_MODEL_H |
17 #define _FFT_MODEL_H_ | 17 #define FFT_MODEL_H |
18 | 18 |
19 #include "data/fft/FFTDataServer.h" | |
20 #include "DenseThreeDimensionalModel.h" | 19 #include "DenseThreeDimensionalModel.h" |
20 #include "DenseTimeValueModel.h" | |
21 | |
22 #include "base/Window.h" | |
23 | |
24 #include "data/fft/FFTapi.h" | |
21 | 25 |
22 #include <set> | 26 #include <set> |
23 #include <map> | 27 #include <vector> |
28 #include <complex> | |
29 #include <deque> | |
24 | 30 |
25 /** | 31 /** |
26 * An implementation of DenseThreeDimensionalModel that makes FFT data | 32 * An implementation of DenseThreeDimensionalModel that makes FFT data |
27 * derived from a DenseTimeValueModel available as a generic data | 33 * derived from a DenseTimeValueModel available as a generic data |
28 * grid. The FFT data is acquired using FFTDataServer. Note that any | 34 * grid. |
29 * of the accessor functions may throw AllocationFailed if a cache | |
30 * resize fails. | |
31 */ | 35 */ |
32 | |
33 class FFTModel : public DenseThreeDimensionalModel | 36 class FFTModel : public DenseThreeDimensionalModel |
34 { | 37 { |
35 Q_OBJECT | 38 Q_OBJECT |
39 | |
40 //!!! threading requirements? | |
41 //!!! doubles? since we're not caching much | |
36 | 42 |
37 public: | 43 public: |
38 /** | 44 /** |
39 * Construct an FFT model derived from the given | 45 * Construct an FFT model derived from the given |
40 * DenseTimeValueModel, with the given window parameters and FFT | 46 * DenseTimeValueModel, with the given window parameters and FFT |
41 * size (which may exceed the window size, for zero-padded FFTs). | 47 * size (which may exceed the window size, for zero-padded FFTs). |
42 * | 48 * |
43 * If the model has multiple channels use only the given channel, | 49 * If the model has multiple channels use only the given channel, |
44 * unless the channel is -1 in which case merge all available | 50 * unless the channel is -1 in which case merge all available |
45 * channels. | 51 * channels. |
46 * | |
47 * If polar is true, the data will normally be retrieved from the | |
48 * FFT model in magnitude/phase form; otherwise it will normally | |
49 * be retrieved in "cartesian" real/imaginary form. The results | |
50 * should be the same either way, but a "polar" model addressed in | |
51 * "cartesian" form or vice versa may suffer a performance | |
52 * penalty. | |
53 * | |
54 * The fillFromColumn argument gives a hint that the FFT data | |
55 * server should aim to start calculating FFT data at that column | |
56 * number if possible, as that is likely to be requested first. | |
57 */ | 52 */ |
58 FFTModel(const DenseTimeValueModel *model, | 53 FFTModel(const DenseTimeValueModel *model, |
59 int channel, | 54 int channel, |
60 WindowType windowType, | 55 WindowType windowType, |
61 int windowSize, | 56 int windowSize, |
62 int windowIncrement, | 57 int windowIncrement, |
63 int fftSize, | 58 int fftSize); |
64 bool polar, | |
65 StorageAdviser::Criteria criteria = StorageAdviser::NoCriteria, | |
66 sv_frame_t fillFromFrame = 0); | |
67 ~FFTModel(); | 59 ~FFTModel(); |
68 | |
69 inline float getMagnitudeAt(int x, int y) { | |
70 return m_server->getMagnitudeAt(x << m_xshift, y << m_yshift); | |
71 } | |
72 inline float getNormalizedMagnitudeAt(int x, int y) { | |
73 return m_server->getNormalizedMagnitudeAt(x << m_xshift, y << m_yshift); | |
74 } | |
75 inline float getMaximumMagnitudeAt(int x) { | |
76 return m_server->getMaximumMagnitudeAt(x << m_xshift); | |
77 } | |
78 inline float getPhaseAt(int x, int y) { | |
79 return m_server->getPhaseAt(x << m_xshift, y << m_yshift); | |
80 } | |
81 inline void getValuesAt(int x, int y, float &real, float &imaginary) { | |
82 m_server->getValuesAt(x << m_xshift, y << m_yshift, real, imaginary); | |
83 } | |
84 inline bool isColumnAvailable(int x) const { | |
85 return m_server->isColumnReady(x << m_xshift); | |
86 } | |
87 | |
88 inline bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) { | |
89 return m_server->getMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio()); | |
90 } | |
91 inline bool getNormalizedMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) { | |
92 return m_server->getNormalizedMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio()); | |
93 } | |
94 inline bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) { | |
95 return m_server->getPhasesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio()); | |
96 } | |
97 inline bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) { | |
98 return m_server->getValuesAt(x << m_xshift, reals, imaginaries, minbin << m_yshift, count, getYRatio()); | |
99 } | |
100 | |
101 inline sv_frame_t getFillExtent() const { return m_server->getFillExtent(); } | |
102 | 60 |
103 // DenseThreeDimensionalModel and Model methods: | 61 // DenseThreeDimensionalModel and Model methods: |
104 // | 62 // |
105 inline virtual int getWidth() const { | 63 virtual int getWidth() const; |
106 return m_server->getWidth() >> m_xshift; | 64 virtual int getHeight() const; |
107 } | 65 virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); } |
108 inline virtual int getHeight() const { | 66 virtual bool isOK() const { return m_model && m_model->isOK(); } |
109 // If there is no y-shift, the server's height (based on its | 67 virtual sv_frame_t getStartFrame() const { return 0; } |
110 // fftsize/2 + 1) is correct. If there is a shift, then the | |
111 // server is using a larger fft size than we want, so we shift | |
112 // it right as many times as necessary, but then we need to | |
113 // re-add the "+1" part (because ((fftsize*2)/2 + 1) / 2 != | |
114 // fftsize/2 + 1). | |
115 return (m_server->getHeight() >> m_yshift) + (m_yshift > 0 ? 1 : 0); | |
116 } | |
117 virtual float getValueAt(int x, int y) const { | |
118 return const_cast<FFTModel *>(this)->getMagnitudeAt(x, y); | |
119 } | |
120 virtual bool isOK() const { | |
121 return m_server && m_server->getModel(); | |
122 } | |
123 virtual sv_frame_t getStartFrame() const { | |
124 return 0; | |
125 } | |
126 virtual sv_frame_t getEndFrame() const { | 68 virtual sv_frame_t getEndFrame() const { |
127 return sv_frame_t(getWidth()) * getResolution() + getResolution(); | 69 return sv_frame_t(getWidth()) * getResolution() + getResolution(); |
128 } | 70 } |
129 virtual sv_samplerate_t getSampleRate() const; | 71 virtual sv_samplerate_t getSampleRate() const { |
130 virtual int getResolution() const { | 72 return isOK() ? m_model->getSampleRate() : 0; |
131 return m_server->getWindowIncrement() << m_xshift; | |
132 } | 73 } |
133 virtual int getYBinCount() const { | 74 virtual int getResolution() const { return m_windowIncrement; } |
134 return getHeight(); | 75 virtual int getYBinCount() const { return getHeight(); } |
76 virtual float getMinimumLevel() const { return 0.f; } // Can't provide | |
77 virtual float getMaximumLevel() const { return 1.f; } // Can't provide | |
78 virtual Column getColumn(int x) const; // magnitudes | |
79 virtual QString getBinName(int n) const; | |
80 virtual bool shouldUseLogValueScale() const { return true; } | |
81 virtual int getCompletion() const { | |
82 int c = 100; | |
83 if (m_model) { | |
84 if (m_model->isReady(&c)) return 100; | |
85 } | |
86 return c; | |
135 } | 87 } |
136 virtual float getMinimumLevel() const { | 88 virtual QString getError() const { return ""; } //!!!??? |
137 return 0.f; // Can't provide | 89 virtual sv_frame_t getFillExtent() const { return getEndFrame(); } |
138 } | |
139 virtual float getMaximumLevel() const { | |
140 return 1.f; // Can't provide | |
141 } | |
142 virtual Column getColumn(int x) const; | |
143 virtual QString getBinName(int n) const; | |
144 | 90 |
145 virtual bool shouldUseLogValueScale() const { | 91 // FFTModel methods: |
146 return true; // Although obviously it's up to the user... | 92 // |
147 } | 93 int getChannel() const { return m_channel; } |
94 WindowType getWindowType() const { return m_windowType; } | |
95 int getWindowSize() const { return m_windowSize; } | |
96 int getWindowIncrement() const { return m_windowIncrement; } | |
97 int getFFTSize() const { return m_fftSize; } | |
98 | |
99 float getMagnitudeAt(int x, int y) const; | |
100 float getMaximumMagnitudeAt(int x) const; | |
101 float getPhaseAt(int x, int y) const; | |
102 void getValuesAt(int x, int y, float &real, float &imaginary) const; | |
103 bool isColumnAvailable(int x) const; | |
104 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const; | |
105 bool getNormalizedMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const; | |
106 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const; | |
107 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const; | |
148 | 108 |
149 /** | 109 /** |
150 * Calculate an estimated frequency for a stable signal in this | 110 * Calculate an estimated frequency for a stable signal in this |
151 * bin, using phase unwrapping. This will be completely wrong if | 111 * bin, using phase unwrapping. This will be completely wrong if |
152 * the signal is not stable here. | 112 * the signal is not stable here. |
174 * Return locations and estimated stable frequencies of peak bins. | 134 * Return locations and estimated stable frequencies of peak bins. |
175 */ | 135 */ |
176 virtual PeakSet getPeakFrequencies(PeakPickType type, int x, | 136 virtual PeakSet getPeakFrequencies(PeakPickType type, int x, |
177 int ymin = 0, int ymax = 0); | 137 int ymin = 0, int ymax = 0); |
178 | 138 |
179 virtual int getCompletion() const { return m_server->getFillCompletion(); } | |
180 virtual QString getError() const { return m_server->getError(); } | |
181 | |
182 virtual void suspend() { m_server->suspend(); } | |
183 virtual void suspendWrites() { m_server->suspendWrites(); } | |
184 virtual void resume() { m_server->resume(); } | |
185 | |
186 QString getTypeName() const { return tr("FFT"); } | 139 QString getTypeName() const { return tr("FFT"); } |
187 | 140 |
188 public slots: | 141 public slots: |
189 void sourceModelAboutToBeDeleted(); | 142 void sourceModelAboutToBeDeleted(); |
190 | 143 |
191 private: | 144 private: |
192 FFTModel(const FFTModel &); // not implemented | 145 FFTModel(const FFTModel &); // not implemented |
193 FFTModel &operator=(const FFTModel &); // not implemented | 146 FFTModel &operator=(const FFTModel &); // not implemented |
194 | 147 |
195 FFTDataServer *m_server; | 148 const DenseTimeValueModel *m_model; |
196 int m_xshift; | 149 int m_channel; |
197 int m_yshift; | 150 WindowType m_windowType; |
198 | 151 int m_windowSize; |
199 FFTDataServer *getServer(const DenseTimeValueModel *, | 152 int m_windowIncrement; |
200 int, WindowType, int, int, int, | 153 int m_fftSize; |
201 bool, StorageAdviser::Criteria, sv_frame_t); | 154 Window<float> m_windower; |
202 | 155 FFTForward m_fft; |
156 | |
203 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate, | 157 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate, |
204 int bin, float &percentile) const; | 158 int bin, float &percentile) const; |
205 | 159 |
206 int getYRatio() { | 160 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const { |
207 int ys = m_yshift; | 161 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column); |
208 int r = 1; | 162 sv_frame_t endFrame = startFrame + m_windowSize; |
209 while (ys) { --ys; r <<= 1; } | 163 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0) |
210 return r; | 164 startFrame -= m_windowSize / 2; |
165 endFrame -= m_windowSize / 2; | |
166 return { startFrame, endFrame }; | |
211 } | 167 } |
168 | |
169 std::vector<std::complex<float> > getFFTColumn(int column) const; | |
170 std::vector<float> getSourceSamples(int column) const; | |
171 std::vector<float> getSourceData(std::pair<sv_frame_t, sv_frame_t>) const; | |
172 std::vector<float> getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const; | |
173 | |
174 struct SavedSourceData { | |
175 std::pair<sv_frame_t, sv_frame_t> range; | |
176 std::vector<float> data; | |
177 }; | |
178 mutable SavedSourceData m_savedData; | |
179 | |
180 struct SavedColumn { | |
181 int n; | |
182 std::vector<std::complex<float> > col; | |
183 }; | |
184 mutable std::deque<SavedColumn> m_cached; | |
185 size_t m_cacheSize; | |
212 }; | 186 }; |
213 | 187 |
214 #endif | 188 #endif |