annotate data/model/FFTModel.h @ 497:b6dc6c7f402c

Various fixes: * Fix handling of HTTP redirects (avoiding crashes... I hope) * Fix failure to delete FFT models when a feature extraction model transformer was abandoned (also a cause of crashes in the past) * Fix deadlock when said transform was abandoned before its source model was ready because the session was being cleared (and so the source model would never be ready)
author Chris Cannam
date Fri, 28 Nov 2008 13:36:13 +0000
parents 1405f4a2caf3
children 55ad231c9db7
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@152 16 #ifndef _FFT_MODEL_H_
Chris@152 17 #define _FFT_MODEL_H_
Chris@152 18
Chris@152 19 #include "data/fft/FFTDataServer.h"
Chris@152 20 #include "DenseThreeDimensionalModel.h"
Chris@152 21
Chris@275 22 #include <set>
Chris@275 23 #include <map>
Chris@275 24
Chris@254 25 /**
Chris@254 26 * An implementation of DenseThreeDimensionalModel that makes FFT data
Chris@387 27 * derived from a DenseTimeValueModel available as a generic data
Chris@387 28 * grid. The FFT data is acquired using FFTDataServer. Note that any
Chris@387 29 * of the accessor functions may throw AllocationFailed if a cache
Chris@387 30 * resize fails.
Chris@254 31 */
Chris@254 32
Chris@152 33 class FFTModel : public DenseThreeDimensionalModel
Chris@152 34 {
Chris@247 35 Q_OBJECT
Chris@247 36
Chris@152 37 public:
Chris@254 38 /**
Chris@254 39 * Construct an FFT model derived from the given
Chris@254 40 * DenseTimeValueModel, with the given window parameters and FFT
Chris@254 41 * size (which may exceed the window size, for zero-padded FFTs).
Chris@254 42 *
Chris@254 43 * If the model has multiple channels use only the given channel,
Chris@254 44 * unless the channel is -1 in which case merge all available
Chris@254 45 * channels.
Chris@254 46 *
Chris@254 47 * If polar is true, the data will normally be retrieved from the
Chris@254 48 * FFT model in magnitude/phase form; otherwise it will normally
Chris@254 49 * be retrieved in "cartesian" real/imaginary form. The results
Chris@254 50 * should be the same either way, but a "polar" model addressed in
Chris@254 51 * "cartesian" form or vice versa may suffer a performance
Chris@254 52 * penalty.
Chris@254 53 *
Chris@254 54 * The fillFromColumn argument gives a hint that the FFT data
Chris@254 55 * server should aim to start calculating FFT data at that column
Chris@254 56 * number if possible, as that is likely to be requested first.
Chris@254 57 */
Chris@152 58 FFTModel(const DenseTimeValueModel *model,
Chris@152 59 int channel,
Chris@152 60 WindowType windowType,
Chris@152 61 size_t windowSize,
Chris@152 62 size_t windowIncrement,
Chris@152 63 size_t fftSize,
Chris@152 64 bool polar,
Chris@334 65 StorageAdviser::Criteria criteria = StorageAdviser::NoCriteria,
Chris@152 66 size_t fillFromColumn = 0);
Chris@152 67 ~FFTModel();
Chris@152 68
Chris@497 69 inline float getMagnitudeAt(size_t x, size_t y) {
Chris@152 70 return m_server->getMagnitudeAt(x << m_xshift, y << m_yshift);
Chris@152 71 }
Chris@497 72 inline float getNormalizedMagnitudeAt(size_t x, size_t y) {
Chris@152 73 return m_server->getNormalizedMagnitudeAt(x << m_xshift, y << m_yshift);
Chris@152 74 }
Chris@497 75 inline float getMaximumMagnitudeAt(size_t x) {
Chris@152 76 return m_server->getMaximumMagnitudeAt(x << m_xshift);
Chris@152 77 }
Chris@497 78 inline float getPhaseAt(size_t x, size_t y) {
Chris@152 79 return m_server->getPhaseAt(x << m_xshift, y << m_yshift);
Chris@152 80 }
Chris@497 81 inline void getValuesAt(size_t x, size_t y, float &real, float &imaginary) {
Chris@152 82 m_server->getValuesAt(x << m_xshift, y << m_yshift, real, imaginary);
Chris@152 83 }
Chris@497 84 inline bool isColumnAvailable(size_t x) const {
Chris@152 85 return m_server->isColumnReady(x << m_xshift);
Chris@152 86 }
Chris@152 87
Chris@497 88 inline float getMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
Chris@408 89 return m_server->getMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
Chris@408 90 }
Chris@497 91 inline float getNormalizedMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
Chris@408 92 return m_server->getNormalizedMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
Chris@408 93 }
Chris@497 94 inline float getPhasesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
Chris@408 95 return m_server->getPhasesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
Chris@408 96 }
Chris@408 97
Chris@497 98 inline size_t getFillExtent() const { return m_server->getFillExtent(); }
Chris@152 99
Chris@152 100 // DenseThreeDimensionalModel and Model methods:
Chris@152 101 //
Chris@497 102 inline virtual size_t getWidth() const {
Chris@182 103 return m_server->getWidth() >> m_xshift;
Chris@182 104 }
Chris@497 105 inline virtual size_t getHeight() const {
Chris@212 106 // If there is no y-shift, the server's height (based on its
Chris@212 107 // fftsize/2 + 1) is correct. If there is a shift, then the
Chris@212 108 // server is using a larger fft size than we want, so we shift
Chris@212 109 // it right as many times as necessary, but then we need to
Chris@212 110 // re-add the "+1" part (because ((fftsize*2)/2 + 1) / 2 !=
Chris@212 111 // fftsize/2 + 1).
Chris@212 112 return (m_server->getHeight() >> m_yshift) + (m_yshift > 0 ? 1 : 0);
Chris@182 113 }
Chris@182 114 virtual float getValueAt(size_t x, size_t y) const {
Chris@182 115 return const_cast<FFTModel *>(this)->getMagnitudeAt(x, y);
Chris@182 116 }
Chris@152 117 virtual bool isOK() const {
Chris@152 118 return m_server && m_server->getModel();
Chris@152 119 }
Chris@152 120 virtual size_t getStartFrame() const {
Chris@152 121 return 0;
Chris@152 122 }
Chris@152 123 virtual size_t getEndFrame() const {
Chris@152 124 return getWidth() * getResolution() + getResolution();
Chris@152 125 }
Chris@152 126 virtual size_t getSampleRate() const;
Chris@152 127 virtual size_t getResolution() const {
Chris@152 128 return m_server->getWindowIncrement() << m_xshift;
Chris@152 129 }
Chris@152 130 virtual size_t getYBinCount() const {
Chris@152 131 return getHeight();
Chris@152 132 }
Chris@152 133 virtual float getMinimumLevel() const {
Chris@152 134 return 0.f; // Can't provide
Chris@152 135 }
Chris@152 136 virtual float getMaximumLevel() const {
Chris@152 137 return 1.f; // Can't provide
Chris@152 138 }
Chris@182 139 virtual void getColumn(size_t x, Column &result) const;
Chris@152 140 virtual QString getBinName(size_t n) const;
Chris@152 141
Chris@478 142 virtual bool shouldUseLogValueScale() const {
Chris@478 143 return true; // Although obviously it's up to the user...
Chris@478 144 }
Chris@478 145
Chris@275 146 /**
Chris@275 147 * Calculate an estimated frequency for a stable signal in this
Chris@275 148 * bin, using phase unwrapping. This will be completely wrong if
Chris@275 149 * the signal is not stable here.
Chris@275 150 */
Chris@275 151 virtual bool estimateStableFrequency(size_t x, size_t y, float &frequency);
Chris@275 152
Chris@275 153 enum PeakPickType
Chris@275 154 {
Chris@275 155 AllPeaks, /// Any bin exceeding its immediate neighbours
Chris@275 156 MajorPeaks, /// Peaks picked using sliding median window
Chris@275 157 MajorPitchAdaptivePeaks /// Bigger window for higher frequencies
Chris@275 158 };
Chris@275 159
Chris@275 160 typedef std::set<size_t> PeakLocationSet;
Chris@275 161 typedef std::map<size_t, float> PeakSet;
Chris@275 162
Chris@275 163 /**
Chris@275 164 * Return locations of peak bins in the range [ymin,ymax]. If
Chris@275 165 * ymax is zero, getHeight()-1 will be used.
Chris@275 166 */
Chris@275 167 virtual PeakLocationSet getPeaks(PeakPickType type, size_t x,
Chris@275 168 size_t ymin = 0, size_t ymax = 0);
Chris@275 169
Chris@275 170 /**
Chris@275 171 * Return locations and estimated stable frequencies of peak bins.
Chris@275 172 */
Chris@275 173 virtual PeakSet getPeakFrequencies(PeakPickType type, size_t x,
Chris@275 174 size_t ymin = 0, size_t ymax = 0);
Chris@273 175
Chris@152 176 virtual int getCompletion() const { return m_server->getFillCompletion(); }
Chris@152 177
Chris@152 178 virtual Model *clone() const;
Chris@152 179
Chris@154 180 virtual void suspend() { m_server->suspend(); }
Chris@155 181 virtual void suspendWrites() { m_server->suspendWrites(); }
Chris@154 182 virtual void resume() { m_server->resume(); }
Chris@154 183
Chris@345 184 QString getTypeName() const { return tr("FFT"); }
Chris@345 185
Chris@360 186 public slots:
Chris@360 187 void sourceModelAboutToBeDeleted();
Chris@360 188
Chris@152 189 private:
Chris@297 190 FFTModel(const FFTModel &); // not implemented
Chris@152 191 FFTModel &operator=(const FFTModel &); // not implemented
Chris@152 192
Chris@152 193 FFTDataServer *m_server;
Chris@152 194 int m_xshift;
Chris@152 195 int m_yshift;
Chris@275 196
Chris@297 197 FFTDataServer *getServer(const DenseTimeValueModel *,
Chris@297 198 int, WindowType, size_t, size_t, size_t,
Chris@334 199 bool, StorageAdviser::Criteria, size_t);
Chris@297 200
Chris@280 201 size_t getPeakPickWindowSize(PeakPickType type, size_t sampleRate,
Chris@280 202 size_t bin, float &percentile) const;
Chris@408 203
Chris@408 204 size_t getYRatio() {
Chris@408 205 size_t ys = m_yshift;
Chris@408 206 size_t r = 1;
Chris@408 207 while (ys) { --ys; r <<= 1; }
Chris@408 208 return r;
Chris@408 209 }
Chris@152 210 };
Chris@152 211
Chris@152 212 #endif