annotate data/model/FFTModel.h @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents c546429d4c2f
children 1b688ab5f1b3
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@1790 63 bool isOK() const override;
Chris@1790 64 int getCompletion() const override;
Chris@1790 65
Chris@1580 66 int getWidth() const override;
Chris@1580 67 int getHeight() const override;
Chris@1790 68
Chris@1790 69 float getValueAt(int x, int y) const override {
Chris@1790 70 return getMagnitudeAt(x, y);
Chris@1790 71 }
Chris@1790 72 sv_frame_t getStartFrame() const override {
Chris@1790 73 return 0;
Chris@1790 74 }
Chris@1725 75 sv_frame_t getTrueEndFrame() const override {
Chris@1038 76 return sv_frame_t(getWidth()) * getResolution() + getResolution();
Chris@152 77 }
Chris@1790 78 sv_samplerate_t getSampleRate() const override {
Chris@1790 79 return m_sampleRate;
Chris@1790 80 }
Chris@1790 81 int getResolution() const override {
Chris@1790 82 return m_windowIncrement;
Chris@1790 83 }
Chris@1790 84
Chris@1580 85 float getMinimumLevel() const override { return 0.f; } // Can't provide
Chris@1580 86 float getMaximumLevel() const override { return 1.f; } // Can't provide
Chris@1790 87
Chris@1580 88 Column getColumn(int x) const override; // magnitudes
Chris@1790 89
Chris@1790 90 bool hasBinValues() const override {
Chris@1790 91 return true;
Chris@1790 92 }
Chris@1790 93 QString getBinValueUnit() const override {
Chris@1790 94 return "Hz";
Chris@1790 95 }
Chris@1790 96 bool shouldUseLogValueScale() const override {
Chris@1790 97 return true;
Chris@1790 98 }
Chris@1790 99 float getBinValue(int n) const override;
Chris@1580 100 QString getBinName(int n) const override;
Chris@1790 101
Chris@1833 102 QVector<QString>
Chris@1833 103 getStringExportHeaders(DataExportOptions) const override {
Chris@1833 104 return {};
Chris@1815 105 }
Chris@1833 106
Chris@1833 107 QVector<QVector<QString>>
Chris@1833 108 toStringExportRows(DataExportOptions, sv_frame_t, sv_frame_t) const override {
Chris@1833 109 return {};
Chris@1679 110 }
Chris@152 111
Chris@1090 112 // FFTModel methods:
Chris@1090 113 //
Chris@1790 114 QString getError() const { return m_error; }
Chris@1790 115
Chris@1090 116 int getChannel() const { return m_channel; }
Chris@1090 117 WindowType getWindowType() const { return m_windowType; }
Chris@1090 118 int getWindowSize() const { return m_windowSize; }
Chris@1090 119 int getWindowIncrement() const { return m_windowIncrement; }
Chris@1090 120 int getFFTSize() const { return m_fftSize; }
Chris@1200 121
Chris@1780 122 void setMaximumFrequency(double freq);
Chris@1780 123 double getMaximumFrequency() const { return m_maximumFrequency; }
Chris@1780 124
Chris@1200 125 //!!! review which of these are ever actually called
Chris@1090 126
Chris@1090 127 float getMagnitudeAt(int x, int y) const;
Chris@1090 128 float getMaximumMagnitudeAt(int x) const;
Chris@1790 129 Column getPhases(int x) const;
Chris@1090 130 float getPhaseAt(int x, int y) const;
Chris@1090 131 void getValuesAt(int x, int y, float &real, float &imaginary) const;
Chris@1090 132 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 133 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 134 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
Chris@478 135
Chris@275 136 /**
Chris@275 137 * Calculate an estimated frequency for a stable signal in this
Chris@275 138 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 139 * the signal is not stable here.
Chris@275 140 */
Chris@1045 141 virtual bool estimateStableFrequency(int x, int y, double &frequency);
Chris@275 142
Chris@275 143 enum PeakPickType
Chris@275 144 {
Chris@275 145 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 146 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 147 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 148 };
Chris@275 149
Chris@929 150 typedef std::set<int> PeakLocationSet; // bin
Chris@1045 151 typedef std::map<int, double> PeakSet; // bin -> freq
Chris@275 152
Chris@275 153 /**
Chris@275 154 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 155 * ymax is zero, getHeight()-1 will be used.
Chris@275 156 */
Chris@929 157 virtual PeakLocationSet getPeaks(PeakPickType type, int x,
Chris@1191 158 int ymin = 0, int ymax = 0) const;
Chris@275 159
Chris@275 160 /**
Chris@275 161 * Return locations and estimated stable frequencies of peak bins.
Chris@275 162 */
Chris@929 163 virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
Chris@1191 164 int ymin = 0, int ymax = 0) const;
Chris@273 165
Chris@1580 166 QString getTypeName() const override { return tr("FFT"); }
Chris@345 167
Chris@1744 168 private:
Chris@1744 169 FFTModel(const FFTModel &) =delete;
Chris@1744 170 FFTModel &operator=(const FFTModel &) =delete;
Chris@360 171
Chris@1744 172 const ModelId m_model; // a DenseTimeValueModel
Chris@1780 173 sv_samplerate_t m_sampleRate;
Chris@1090 174 int m_channel;
Chris@1090 175 WindowType m_windowType;
Chris@1090 176 int m_windowSize;
Chris@1090 177 int m_windowIncrement;
Chris@1090 178 int m_fftSize;
Chris@1090 179 Window<float> m_windower;
Chris@1270 180 mutable breakfastquay::FFT m_fft;
Chris@1780 181 double m_maximumFrequency;
Chris@1784 182 mutable QString m_error;
Chris@1090 183
Chris@1040 184 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
Chris@1576 185 int bin, double &dist) const;
Chris@1091 186
Chris@1091 187 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
Chris@1091 188 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
Chris@1091 189 sv_frame_t endFrame = startFrame + m_windowSize;
Chris@1091 190 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
Chris@1091 191 startFrame -= m_windowSize / 2;
Chris@1091 192 endFrame -= m_windowSize / 2;
Chris@1091 193 return { startFrame, endFrame };
Chris@1091 194 }
Chris@1091 195
Chris@1326 196 typedef std::vector<float, breakfastquay::StlAllocator<float>> fvec;
Chris@1326 197 typedef std::vector<std::complex<float>,
Chris@1326 198 breakfastquay::StlAllocator<std::complex<float>>> cvec;
Chris@1780 199
Chris@1780 200 cvec getFFTColumn(int column) const;
Chris@1326 201 fvec getSourceSamples(int column) const;
Chris@1326 202 fvec getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1326 203 fvec getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1093 204
Chris@1094 205 struct SavedSourceData {
Chris@1094 206 std::pair<sv_frame_t, sv_frame_t> range;
Chris@1326 207 fvec data;
Chris@1094 208 };
Chris@1094 209 mutable SavedSourceData m_savedData;
Chris@1371 210
Chris@1093 211 struct SavedColumn {
Chris@1093 212 int n;
Chris@1326 213 cvec col;
Chris@1093 214 };
Chris@1371 215 mutable std::vector<SavedColumn> m_cached;
Chris@1371 216 mutable size_t m_cacheWriteIndex;
Chris@1093 217 size_t m_cacheSize;
Chris@152 218 };
Chris@152 219
Chris@152 220 #endif