annotate data/model/FFTModel.h @ 1784:4eac4bf35b45

More graceful handling of failure to construct FFT models in the case where the source model has already been deleted before this occurs
author Chris Cannam
date Tue, 17 Sep 2019 11:21:33 +0100
parents 6d6740b075c3
children dd51797e528e
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@1744 53 FFTModel(ModelId model, // a DenseTimeValueModel
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@1580 63 int getWidth() const override;
Chris@1580 64 int getHeight() const override;
Chris@1580 65 float getValueAt(int x, int y) const override { return getMagnitudeAt(x, y); }
Chris@1744 66 bool isOK() const override;
Chris@1580 67 sv_frame_t getStartFrame() const override { return 0; }
Chris@1725 68 sv_frame_t getTrueEndFrame() const override {
Chris@1038 69 return sv_frame_t(getWidth()) * getResolution() + getResolution();
Chris@152 70 }
Chris@1744 71 sv_samplerate_t getSampleRate() const override;
Chris@1580 72 int getResolution() const override { return m_windowIncrement; }
Chris@1090 73 virtual int getYBinCount() const { return getHeight(); }
Chris@1580 74 float getMinimumLevel() const override { return 0.f; } // Can't provide
Chris@1580 75 float getMaximumLevel() const override { return 1.f; } // Can't provide
Chris@1580 76 Column getColumn(int x) const override; // magnitudes
Chris@1200 77 virtual Column getPhases(int x) const;
Chris@1580 78 QString getBinName(int n) const override;
Chris@1580 79 bool shouldUseLogValueScale() const override { return true; }
Chris@1744 80 int getCompletion() const override;
Chris@1784 81 virtual QString getError() const { return m_error; }
Chris@1090 82 virtual sv_frame_t getFillExtent() const { return getEndFrame(); }
Chris@1679 83 QString toDelimitedDataString(QString, DataExportOptions,
Chris@1679 84 sv_frame_t, sv_frame_t) const override {
Chris@1679 85 return "";
Chris@1679 86 }
Chris@152 87
Chris@1090 88 // FFTModel methods:
Chris@1090 89 //
Chris@1090 90 int getChannel() const { return m_channel; }
Chris@1090 91 WindowType getWindowType() const { return m_windowType; }
Chris@1090 92 int getWindowSize() const { return m_windowSize; }
Chris@1090 93 int getWindowIncrement() const { return m_windowIncrement; }
Chris@1090 94 int getFFTSize() const { return m_fftSize; }
Chris@1200 95
Chris@1780 96 void setMaximumFrequency(double freq);
Chris@1780 97 double getMaximumFrequency() const { return m_maximumFrequency; }
Chris@1780 98
Chris@1200 99 //!!! review which of these are ever actually called
Chris@1090 100
Chris@1090 101 float getMagnitudeAt(int x, int y) const;
Chris@1090 102 float getMaximumMagnitudeAt(int x) const;
Chris@1090 103 float getPhaseAt(int x, int y) const;
Chris@1090 104 void getValuesAt(int x, int y, float &real, float &imaginary) const;
Chris@1090 105 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 106 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 107 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
Chris@478 108
Chris@275 109 /**
Chris@275 110 * Calculate an estimated frequency for a stable signal in this
Chris@275 111 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 112 * the signal is not stable here.
Chris@275 113 */
Chris@1045 114 virtual bool estimateStableFrequency(int x, int y, double &frequency);
Chris@275 115
Chris@275 116 enum PeakPickType
Chris@275 117 {
Chris@275 118 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 119 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 120 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 121 };
Chris@275 122
Chris@929 123 typedef std::set<int> PeakLocationSet; // bin
Chris@1045 124 typedef std::map<int, double> PeakSet; // bin -> freq
Chris@275 125
Chris@275 126 /**
Chris@275 127 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 128 * ymax is zero, getHeight()-1 will be used.
Chris@275 129 */
Chris@929 130 virtual PeakLocationSet getPeaks(PeakPickType type, int x,
Chris@1191 131 int ymin = 0, int ymax = 0) const;
Chris@275 132
Chris@275 133 /**
Chris@275 134 * Return locations and estimated stable frequencies of peak bins.
Chris@275 135 */
Chris@929 136 virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
Chris@1191 137 int ymin = 0, int ymax = 0) const;
Chris@273 138
Chris@1580 139 QString getTypeName() const override { return tr("FFT"); }
Chris@345 140
Chris@1744 141 private:
Chris@1744 142 FFTModel(const FFTModel &) =delete;
Chris@1744 143 FFTModel &operator=(const FFTModel &) =delete;
Chris@360 144
Chris@1744 145 const ModelId m_model; // a DenseTimeValueModel
Chris@1780 146 sv_samplerate_t m_sampleRate;
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@1270 153 mutable breakfastquay::FFT m_fft;
Chris@1780 154 double m_maximumFrequency;
Chris@1784 155 mutable QString m_error;
Chris@1090 156
Chris@1040 157 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
Chris@1576 158 int bin, double &dist) const;
Chris@1091 159
Chris@1091 160 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
Chris@1091 161 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
Chris@1091 162 sv_frame_t endFrame = startFrame + m_windowSize;
Chris@1091 163 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
Chris@1091 164 startFrame -= m_windowSize / 2;
Chris@1091 165 endFrame -= m_windowSize / 2;
Chris@1091 166 return { startFrame, endFrame };
Chris@1091 167 }
Chris@1091 168
Chris@1326 169 typedef std::vector<float, breakfastquay::StlAllocator<float>> fvec;
Chris@1326 170 typedef std::vector<std::complex<float>,
Chris@1326 171 breakfastquay::StlAllocator<std::complex<float>>> cvec;
Chris@1780 172
Chris@1780 173 cvec getFFTColumn(int column) const;
Chris@1326 174 fvec getSourceSamples(int column) const;
Chris@1326 175 fvec getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1326 176 fvec getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1093 177
Chris@1094 178 struct SavedSourceData {
Chris@1094 179 std::pair<sv_frame_t, sv_frame_t> range;
Chris@1326 180 fvec data;
Chris@1094 181 };
Chris@1094 182 mutable SavedSourceData m_savedData;
Chris@1371 183
Chris@1093 184 struct SavedColumn {
Chris@1093 185 int n;
Chris@1326 186 cvec col;
Chris@1093 187 };
Chris@1371 188 mutable std::vector<SavedColumn> m_cached;
Chris@1371 189 mutable size_t m_cacheWriteIndex;
Chris@1093 190 size_t m_cacheSize;
Chris@152 191 };
Chris@152 192
Chris@152 193 #endif