annotate data/fft/FFTDataServer.h @ 184:5a916fee6d2d

* Handle generator transforms (plugins whose channel count isn't dependent on number of audio inputs, as they have none) * Be less keen to suspend writing FFT data in spectrogram repaint -- only do it if we find we actually need to query the FFT data (i.e. we aren't repainting an area that hasn't been generated at all yet)
author Chris Cannam
date Tue, 10 Oct 2006 19:04:57 +0000
parents 146eb9e35baa
children 91fdc752e540
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@148 7 This file copyright 2006 Chris Cannam.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #ifndef _FFT_DATA_SERVER_H_
Chris@148 17 #define _FFT_DATA_SERVER_H_
Chris@148 18
Chris@148 19 #include "base/Window.h"
Chris@148 20 #include "base/Thread.h"
Chris@148 21
Chris@148 22 #include <fftw3.h>
Chris@148 23
Chris@148 24 #include <QMutex>
Chris@148 25 #include <QWaitCondition>
Chris@148 26 #include <QString>
Chris@148 27
Chris@148 28 #include <vector>
Chris@148 29 #include <deque>
Chris@148 30
Chris@148 31 class DenseTimeValueModel;
Chris@148 32 class FFTCache;
Chris@148 33
Chris@148 34 class FFTDataServer
Chris@148 35 {
Chris@148 36 public:
Chris@148 37 static FFTDataServer *getInstance(const DenseTimeValueModel *model,
Chris@148 38 int channel,
Chris@148 39 WindowType windowType,
Chris@148 40 size_t windowSize,
Chris@148 41 size_t windowIncrement,
Chris@148 42 size_t fftSize,
Chris@148 43 bool polar,
Chris@148 44 size_t fillFromColumn = 0);
Chris@148 45
Chris@148 46 static FFTDataServer *getFuzzyInstance(const DenseTimeValueModel *model,
Chris@148 47 int channel,
Chris@148 48 WindowType windowType,
Chris@148 49 size_t windowSize,
Chris@148 50 size_t windowIncrement,
Chris@148 51 size_t fftSize,
Chris@148 52 bool polar,
Chris@148 53 size_t fillFromColumn = 0);
Chris@148 54
Chris@152 55 static void claimInstance(FFTDataServer *);
Chris@148 56 static void releaseInstance(FFTDataServer *);
Chris@148 57
Chris@148 58 const DenseTimeValueModel *getModel() const { return m_model; }
Chris@148 59 int getChannel() const { return m_channel; }
Chris@148 60 WindowType getWindowType() const { return m_windower.getType(); }
Chris@148 61 size_t getWindowSize() const { return m_windowSize; }
Chris@148 62 size_t getWindowIncrement() const { return m_windowIncrement; }
Chris@148 63 size_t getFFTSize() const { return m_fftSize; }
Chris@148 64 bool getPolar() const { return m_polar; }
Chris@148 65
Chris@148 66 size_t getWidth() const { return m_width; }
Chris@148 67 size_t getHeight() const { return m_height; }
Chris@148 68
Chris@148 69 float getMagnitudeAt(size_t x, size_t y);
Chris@148 70 float getNormalizedMagnitudeAt(size_t x, size_t y);
Chris@148 71 float getMaximumMagnitudeAt(size_t x);
Chris@148 72 float getPhaseAt(size_t x, size_t y);
Chris@148 73 void getValuesAt(size_t x, size_t y, float &real, float &imaginary);
Chris@148 74 bool isColumnReady(size_t x);
Chris@148 75
Chris@148 76 void suspend();
Chris@155 77 void suspendWrites();
Chris@154 78 void resume(); // also happens automatically if new data needed
Chris@148 79
Chris@148 80 // Convenience functions:
Chris@148 81
Chris@148 82 bool isLocalPeak(size_t x, size_t y) {
Chris@148 83 float mag = getMagnitudeAt(x, y);
Chris@148 84 if (y > 0 && mag < getMagnitudeAt(x, y - 1)) return false;
Chris@148 85 if (y < getHeight()-1 && mag < getMagnitudeAt(x, y + 1)) return false;
Chris@148 86 return true;
Chris@148 87 }
Chris@148 88 bool isOverThreshold(size_t x, size_t y, float threshold) {
Chris@148 89 return getMagnitudeAt(x, y) > threshold;
Chris@148 90 }
Chris@148 91
Chris@148 92 size_t getFillCompletion() const;
Chris@148 93 size_t getFillExtent() const;
Chris@148 94
Chris@148 95 private:
Chris@148 96 FFTDataServer(QString fileBaseName,
Chris@148 97 const DenseTimeValueModel *model,
Chris@148 98 int channel,
Chris@148 99 WindowType windowType,
Chris@148 100 size_t windowSize,
Chris@148 101 size_t windowIncrement,
Chris@148 102 size_t fftSize,
Chris@148 103 bool polar,
Chris@148 104 size_t fillFromColumn = 0);
Chris@148 105
Chris@148 106 virtual ~FFTDataServer();
Chris@148 107
Chris@148 108 FFTDataServer(const FFTDataServer &); // not implemented
Chris@148 109 FFTDataServer &operator=(const FFTDataServer &); // not implemented
Chris@148 110
Chris@148 111 typedef float fftsample;
Chris@148 112
Chris@148 113 QString m_fileBaseName;
Chris@148 114 const DenseTimeValueModel *m_model;
Chris@148 115 int m_channel;
Chris@148 116
Chris@148 117 Window<fftsample> m_windower;
Chris@148 118
Chris@148 119 size_t m_windowSize;
Chris@148 120 size_t m_windowIncrement;
Chris@148 121 size_t m_fftSize;
Chris@148 122 bool m_polar;
Chris@148 123
Chris@148 124 size_t m_width;
Chris@148 125 size_t m_height;
Chris@148 126 size_t m_cacheWidth;
Chris@183 127 size_t m_cacheWidthPower;
Chris@183 128 size_t m_cacheWidthMask;
Chris@172 129 bool m_memoryCache;
Chris@172 130 bool m_compactCache;
Chris@148 131
Chris@148 132 typedef std::vector<FFTCache *> CacheVector;
Chris@148 133 CacheVector m_caches;
Chris@148 134
Chris@148 135 typedef std::deque<int> IntQueue;
Chris@148 136 IntQueue m_dormantCaches;
Chris@148 137
Chris@148 138 int m_lastUsedCache;
Chris@148 139 FFTCache *getCache(size_t x, size_t &col) {
Chris@148 140 col = x % m_cacheWidth;
Chris@148 141 int c = x / m_cacheWidth;
Chris@148 142 // The only use of m_lastUsedCache without a lock is to
Chris@148 143 // establish whether a cache has been created at all (they're
Chris@148 144 // created on demand, but not destroyed until the server is).
Chris@148 145 if (c == m_lastUsedCache) return m_caches[c];
Chris@148 146 else return getCacheAux(c);
Chris@148 147 }
Chris@148 148 bool haveCache(size_t x) {
Chris@148 149 int c = x / m_cacheWidth;
Chris@148 150 if (c == m_lastUsedCache) return true;
Chris@148 151 else return (m_caches[c] != 0);
Chris@148 152 }
Chris@148 153
Chris@148 154 FFTCache *getCacheAux(size_t c);
Chris@148 155 QMutex m_writeMutex;
Chris@148 156 QWaitCondition m_condition;
Chris@148 157
Chris@148 158 fftsample *m_fftInput;
Chris@148 159 fftwf_complex *m_fftOutput;
Chris@148 160 float *m_workbuffer;
Chris@148 161 fftwf_plan m_fftPlan;
Chris@148 162
Chris@148 163 class FillThread : public Thread
Chris@148 164 {
Chris@148 165 public:
Chris@148 166 FillThread(FFTDataServer &server, size_t fillFromColumn) :
Chris@148 167 m_server(server), m_extent(0), m_completion(0),
Chris@148 168 m_fillFrom(fillFromColumn) { }
Chris@148 169
Chris@148 170 size_t getExtent() const { return m_extent; }
Chris@148 171 size_t getCompletion() const { return m_completion ? m_completion : 1; }
Chris@148 172 virtual void run();
Chris@148 173
Chris@148 174 protected:
Chris@148 175 FFTDataServer &m_server;
Chris@148 176 size_t m_extent;
Chris@148 177 size_t m_completion;
Chris@148 178 size_t m_fillFrom;
Chris@148 179 };
Chris@148 180
Chris@148 181 bool m_exiting;
Chris@148 182 bool m_suspended;
Chris@148 183 FillThread *m_fillThread;
Chris@148 184
Chris@148 185 void deleteProcessingData();
Chris@148 186 void fillColumn(size_t x);
Chris@148 187
Chris@148 188 QString generateFileBasename() const;
Chris@148 189 static QString generateFileBasename(const DenseTimeValueModel *model,
Chris@148 190 int channel,
Chris@148 191 WindowType windowType,
Chris@148 192 size_t windowSize,
Chris@148 193 size_t windowIncrement,
Chris@148 194 size_t fftSize,
Chris@148 195 bool polar);
Chris@148 196
Chris@148 197 typedef std::pair<FFTDataServer *, int> ServerCountPair;
Chris@148 198 typedef std::map<QString, ServerCountPair> ServerMap;
Chris@148 199
Chris@148 200 static ServerMap m_servers;
Chris@148 201 static QMutex m_serverMapMutex;
Chris@148 202 static FFTDataServer *findServer(QString); // call with serverMapMutex held
Chris@148 203 static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held
Chris@148 204 };
Chris@148 205
Chris@148 206 #endif