annotate data/model/FFTModel.h @ 1336:dc56e8a13e44 3.0-integration

Close wave file writer when recording stops (instead of leaving record file unclosed until the model is deleted)
author Chris Cannam
date Wed, 04 Jan 2017 12:05:14 +0000
parents 54af1e21705c
children fad8f533ca13
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@1093 30 #include <deque>
Chris@275 31
Chris@254 32 /**
Chris@254 33 * An implementation of DenseThreeDimensionalModel that makes FFT data
Chris@387 34 * derived from a DenseTimeValueModel available as a generic data
Chris@1090 35 * grid.
Chris@254 36 */
Chris@152 37 class FFTModel : public DenseThreeDimensionalModel
Chris@152 38 {
Chris@247 39 Q_OBJECT
Chris@247 40
Chris@1092 41 //!!! threading requirements?
Chris@1092 42 //!!! doubles? since we're not caching much
Chris@1092 43
Chris@152 44 public:
Chris@254 45 /**
Chris@254 46 * Construct an FFT model derived from the given
Chris@254 47 * DenseTimeValueModel, with the given window parameters and FFT
Chris@254 48 * size (which may exceed the window size, for zero-padded FFTs).
Chris@254 49 *
Chris@254 50 * If the model has multiple channels use only the given channel,
Chris@254 51 * unless the channel is -1 in which case merge all available
Chris@254 52 * channels.
Chris@254 53 */
Chris@152 54 FFTModel(const DenseTimeValueModel *model,
Chris@152 55 int channel,
Chris@152 56 WindowType windowType,
Chris@929 57 int windowSize,
Chris@929 58 int windowIncrement,
Chris@1090 59 int fftSize);
Chris@152 60 ~FFTModel();
Chris@152 61
Chris@152 62 // DenseThreeDimensionalModel and Model methods:
Chris@152 63 //
Chris@1090 64 virtual int getWidth() const;
Chris@1090 65 virtual int getHeight() const;
Chris@1090 66 virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); }
Chris@1090 67 virtual bool isOK() const { return m_model && m_model->isOK(); }
Chris@1090 68 virtual sv_frame_t getStartFrame() const { return 0; }
Chris@1038 69 virtual sv_frame_t getEndFrame() const {
Chris@1038 70 return sv_frame_t(getWidth()) * getResolution() + getResolution();
Chris@152 71 }
Chris@1090 72 virtual sv_samplerate_t getSampleRate() const {
Chris@1090 73 return isOK() ? m_model->getSampleRate() : 0;
Chris@152 74 }
Chris@1090 75 virtual int getResolution() const { return m_windowIncrement; }
Chris@1090 76 virtual int getYBinCount() const { return getHeight(); }
Chris@1090 77 virtual float getMinimumLevel() const { return 0.f; } // Can't provide
Chris@1090 78 virtual float getMaximumLevel() const { return 1.f; } // Can't provide
Chris@1090 79 virtual Column getColumn(int x) const; // magnitudes
Chris@1200 80 virtual Column getPhases(int x) const;
Chris@1090 81 virtual QString getBinName(int n) const;
Chris@1090 82 virtual bool shouldUseLogValueScale() const { return true; }
Chris@1090 83 virtual int getCompletion() const {
Chris@1090 84 int c = 100;
Chris@1093 85 if (m_model) {
Chris@1093 86 if (m_model->isReady(&c)) return 100;
Chris@1093 87 }
Chris@1090 88 return c;
Chris@152 89 }
Chris@1090 90 virtual QString getError() const { return ""; } //!!!???
Chris@1090 91 virtual sv_frame_t getFillExtent() const { return getEndFrame(); }
Chris@152 92
Chris@1090 93 // FFTModel methods:
Chris@1090 94 //
Chris@1090 95 int getChannel() const { return m_channel; }
Chris@1090 96 WindowType getWindowType() const { return m_windowType; }
Chris@1090 97 int getWindowSize() const { return m_windowSize; }
Chris@1090 98 int getWindowIncrement() const { return m_windowIncrement; }
Chris@1090 99 int getFFTSize() const { return m_fftSize; }
Chris@1200 100
Chris@1200 101 //!!! review which of these are ever actually called
Chris@1090 102
Chris@1090 103 float getMagnitudeAt(int x, int y) const;
Chris@1090 104 float getMaximumMagnitudeAt(int x) const;
Chris@1090 105 float getPhaseAt(int x, int y) const;
Chris@1090 106 void getValuesAt(int x, int y, float &real, float &imaginary) const;
Chris@1090 107 bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 108 bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
Chris@1090 109 bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;
Chris@478 110
Chris@275 111 /**
Chris@275 112 * Calculate an estimated frequency for a stable signal in this
Chris@275 113 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 114 * the signal is not stable here.
Chris@275 115 */
Chris@1045 116 virtual bool estimateStableFrequency(int x, int y, double &frequency);
Chris@275 117
Chris@275 118 enum PeakPickType
Chris@275 119 {
Chris@275 120 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 121 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 122 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 123 };
Chris@275 124
Chris@929 125 typedef std::set<int> PeakLocationSet; // bin
Chris@1045 126 typedef std::map<int, double> PeakSet; // bin -> freq
Chris@275 127
Chris@275 128 /**
Chris@275 129 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 130 * ymax is zero, getHeight()-1 will be used.
Chris@275 131 */
Chris@929 132 virtual PeakLocationSet getPeaks(PeakPickType type, int x,
Chris@1191 133 int ymin = 0, int ymax = 0) const;
Chris@275 134
Chris@275 135 /**
Chris@275 136 * Return locations and estimated stable frequencies of peak bins.
Chris@275 137 */
Chris@929 138 virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
Chris@1191 139 int ymin = 0, int ymax = 0) const;
Chris@273 140
Chris@345 141 QString getTypeName() const { return tr("FFT"); }
Chris@345 142
Chris@360 143 public slots:
Chris@360 144 void sourceModelAboutToBeDeleted();
Chris@360 145
Chris@152 146 private:
Chris@297 147 FFTModel(const FFTModel &); // not implemented
Chris@152 148 FFTModel &operator=(const FFTModel &); // not implemented
Chris@152 149
Chris@1090 150 const DenseTimeValueModel *m_model;
Chris@1090 151 int m_channel;
Chris@1090 152 WindowType m_windowType;
Chris@1090 153 int m_windowSize;
Chris@1090 154 int m_windowIncrement;
Chris@1090 155 int m_fftSize;
Chris@1090 156 Window<float> m_windower;
Chris@1270 157 mutable breakfastquay::FFT m_fft;
Chris@1090 158
Chris@1040 159 int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
Chris@1040 160 int bin, float &percentile) const;
Chris@1091 161
Chris@1091 162 std::pair<sv_frame_t, sv_frame_t> getSourceSampleRange(int column) const {
Chris@1091 163 sv_frame_t startFrame = m_windowIncrement * sv_frame_t(column);
Chris@1091 164 sv_frame_t endFrame = startFrame + m_windowSize;
Chris@1091 165 // Cols are centred on the audio sample (e.g. col 0 is centred at sample 0)
Chris@1091 166 startFrame -= m_windowSize / 2;
Chris@1091 167 endFrame -= m_windowSize / 2;
Chris@1091 168 return { startFrame, endFrame };
Chris@1091 169 }
Chris@1091 170
Chris@1326 171 typedef std::vector<float, breakfastquay::StlAllocator<float>> fvec;
Chris@1326 172 typedef std::vector<std::complex<float>,
Chris@1326 173 breakfastquay::StlAllocator<std::complex<float>>> cvec;
Chris@1326 174
Chris@1326 175 cvec getFFTColumn(int column) const;
Chris@1326 176 fvec getSourceSamples(int column) const;
Chris@1326 177 fvec getSourceData(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1326 178 fvec getSourceDataUncached(std::pair<sv_frame_t, sv_frame_t>) const;
Chris@1093 179
Chris@1094 180 struct SavedSourceData {
Chris@1094 181 std::pair<sv_frame_t, sv_frame_t> range;
Chris@1326 182 fvec data;
Chris@1094 183 };
Chris@1094 184 mutable SavedSourceData m_savedData;
Chris@1094 185
Chris@1093 186 struct SavedColumn {
Chris@1093 187 int n;
Chris@1326 188 cvec col;
Chris@1093 189 };
Chris@1093 190 mutable std::deque<SavedColumn> m_cached;
Chris@1093 191 size_t m_cacheSize;
Chris@152 192 };
Chris@152 193
Chris@152 194 #endif