annotate data/model/FFTModel.h @ 1412:b7a9edee85e0 scale-ticks

Change loop to something that feels more correct, though it makes no difference to the tests here. More tests, one failing.
author Chris Cannam
date Thu, 04 May 2017 08:32:41 +0100
parents fad8f533ca13
children 0f62bce0f0be
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@1270 24 #include <bqfft/FFT.h>
Chris@1326 25 #include <bqvec/Allocators.h>
Chris@1091 26
Chris@275 27 #include <set>
Chris@1091 28 #include <vector>
Chris@1091 29 #include <complex>
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@1200 79 virtual Column getPhases(int x) const;
Chris@1090 80 virtual QString getBinName(int n) const;
Chris@1090 81 virtual bool shouldUseLogValueScale() const { return true; }
Chris@1090 82 virtual int getCompletion() const {
Chris@1090 83 int c = 100;
Chris@1093 84 if (m_model) {
Chris@1093 85 if (m_model->isReady(&c)) return 100;
Chris@1093 86 }
Chris@1090 87 return c;
Chris@152 88 }
Chris@1090 89 virtual QString getError() const { return ""; } //!!!???
Chris@1090 90 virtual sv_frame_t getFillExtent() const { return getEndFrame(); }
Chris@152 91
Chris@1090 92 // FFTModel methods:
Chris@1090 93 //
Chris@1090 94 int getChannel() const { return m_channel; }
Chris@1090 95 WindowType getWindowType() const { return m_windowType; }
Chris@1090 96 int getWindowSize() const { return m_windowSize; }
Chris@1090 97 int getWindowIncrement() const { return m_windowIncrement; }
Chris@1090 98 int getFFTSize() const { return m_fftSize; }
Chris@1200 99
Chris@1200 100 //!!! review which of these are ever actually called
Chris@1090 101
Chris@1090 102 float getMagnitudeAt(int x, int y) const;
Chris@1090 103 float getMaximumMagnitudeAt(int x) const;
Chris@1090 104 float getPhaseAt(int x, int y) const;
Chris@1090 105 void getValuesAt(int x, int y, float &real, float &imaginary) const;
Chris@1090 106 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 107 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 108 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
Chris@478 109
Chris@275 110 /**
Chris@275 111 * Calculate an estimated frequency for a stable signal in this
Chris@275 112 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 113 * the signal is not stable here.
Chris@275 114 */
Chris@1045 115 virtual bool estimateStableFrequency(int x, int y, double &frequency);
Chris@275 116
Chris@275 117 enum PeakPickType
Chris@275 118 {
Chris@275 119 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 120 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 121 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 122 };
Chris@275 123
Chris@929 124 typedef std::set<int> PeakLocationSet; // bin
Chris@1045 125 typedef std::map<int, double> PeakSet; // bin -> freq
Chris@275 126
Chris@275 127 /**
Chris@275 128 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 129 * ymax is zero, getHeight()-1 will be used.
Chris@275 130 */
Chris@929 131 virtual PeakLocationSet getPeaks(PeakPickType type, int x,
Chris@1191 132 int ymin = 0, int ymax = 0) const;
Chris@275 133
Chris@275 134 /**
Chris@275 135 * Return locations and estimated stable frequencies of peak bins.
Chris@275 136 */
Chris@929 137 virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
Chris@1191 138 int ymin = 0, int ymax = 0) const;
Chris@273 139
Chris@345 140 QString getTypeName() const { return tr("FFT"); }
Chris@345 141
Chris@360 142 public slots:
Chris@360 143 void sourceModelAboutToBeDeleted();
Chris@360 144
Chris@152 145 private:
Chris@297 146 FFTModel(const FFTModel &); // not implemented
Chris@152 147 FFTModel &operator=(const FFTModel &); // not implemented
Chris@152 148
Chris@1090 149 const DenseTimeValueModel *m_model;
Chris@1090 150 int m_channel;
Chris@1090 151 WindowType m_windowType;
Chris@1090 152 int m_windowSize;
Chris@1090 153 int m_windowIncrement;
Chris@1090 154 int m_fftSize;
Chris@1090 155 Window<float> m_windower;
Chris@1270 156 mutable breakfastquay::FFT m_fft;
Chris@1090 157
Chris@1040 158 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
Chris@1040 159 int bin, float &percentile) const;
Chris@1091 160
Chris@1091 161 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
Chris@1091 162 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
Chris@1091 163 sv_frame_t endFrame = startFrame + m_windowSize;
Chris@1091 164 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
Chris@1091 165 startFrame -= m_windowSize / 2;
Chris@1091 166 endFrame -= m_windowSize / 2;
Chris@1091 167 return { startFrame, endFrame };
Chris@1091 168 }
Chris@1091 169
Chris@1326 170 typedef std::vector<float, breakfastquay::StlAllocator<float>> fvec;
Chris@1326 171 typedef std::vector<std::complex<float>,
Chris@1326 172 breakfastquay::StlAllocator<std::complex<float>>> cvec;
Chris@1326 173
Chris@1371 174 const cvec &getFFTColumn(int column) const; // returns ref for immediate use only
Chris@1326 175 fvec getSourceSamples(int column) const;
Chris@1326 176 fvec getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1326 177 fvec getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1093 178
Chris@1094 179 struct SavedSourceData {
Chris@1094 180 std::pair<sv_frame_t, sv_frame_t> range;
Chris@1326 181 fvec data;
Chris@1094 182 };
Chris@1094 183 mutable SavedSourceData m_savedData;
Chris@1371 184
Chris@1093 185 struct SavedColumn {
Chris@1093 186 int n;
Chris@1326 187 cvec col;
Chris@1093 188 };
Chris@1371 189 mutable std::vector<SavedColumn> m_cached;
Chris@1371 190 mutable size_t m_cacheWriteIndex;
Chris@1093 191 size_t m_cacheSize;
Chris@152 192 };
Chris@152 193
Chris@152 194 #endif