annotate data/fileio/FFTDataServer.h @ 167:665342c6ec57

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 1a42221a1522
children
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@148 55 static void releaseInstance(FFTDataServer *);
Chris@148 56
Chris@148 57 const DenseTimeValueModel *getModel() const { return m_model; }
Chris@148 58 int getChannel() const { return m_channel; }
Chris@148 59 WindowType getWindowType() const { return m_windower.getType(); }
Chris@148 60 size_t getWindowSize() const { return m_windowSize; }
Chris@148 61 size_t getWindowIncrement() const { return m_windowIncrement; }
Chris@148 62 size_t getFFTSize() const { return m_fftSize; }
Chris@148 63 bool getPolar() const { return m_polar; }
Chris@148 64
Chris@148 65 size_t getWidth() const { return m_width; }
Chris@148 66 size_t getHeight() const { return m_height; }
Chris@148 67
Chris@148 68 float getMagnitudeAt(size_t x, size_t y);
Chris@148 69 float getNormalizedMagnitudeAt(size_t x, size_t y);
Chris@148 70 float getMaximumMagnitudeAt(size_t x);
Chris@148 71 float getPhaseAt(size_t x, size_t y);
Chris@148 72 void getValuesAt(size_t x, size_t y, float &real, float &imaginary);
Chris@148 73 bool isColumnReady(size_t x);
Chris@148 74
Chris@148 75 void suspend();
Chris@148 76
Chris@148 77 // Convenience functions:
Chris@148 78
Chris@148 79 bool isLocalPeak(size_t x, size_t y) {
Chris@148 80 float mag = getMagnitudeAt(x, y);
Chris@148 81 if (y > 0 && mag < getMagnitudeAt(x, y - 1)) return false;
Chris@148 82 if (y < getHeight()-1 && mag < getMagnitudeAt(x, y + 1)) return false;
Chris@148 83 return true;
Chris@148 84 }
Chris@148 85 bool isOverThreshold(size_t x, size_t y, float threshold) {
Chris@148 86 return getMagnitudeAt(x, y) > threshold;
Chris@148 87 }
Chris@148 88
Chris@148 89 size_t getFillCompletion() const;
Chris@148 90 size_t getFillExtent() const;
Chris@148 91
Chris@148 92 private:
Chris@148 93 FFTDataServer(QString fileBaseName,
Chris@148 94 const DenseTimeValueModel *model,
Chris@148 95 int channel,
Chris@148 96 WindowType windowType,
Chris@148 97 size_t windowSize,
Chris@148 98 size_t windowIncrement,
Chris@148 99 size_t fftSize,
Chris@148 100 bool polar,
Chris@148 101 size_t fillFromColumn = 0);
Chris@148 102
Chris@148 103 virtual ~FFTDataServer();
Chris@148 104
Chris@148 105 FFTDataServer(const FFTDataServer &); // not implemented
Chris@148 106 FFTDataServer &operator=(const FFTDataServer &); // not implemented
Chris@148 107
Chris@148 108 typedef float fftsample;
Chris@148 109
Chris@148 110 QString m_fileBaseName;
Chris@148 111 const DenseTimeValueModel *m_model;
Chris@148 112 int m_channel;
Chris@148 113
Chris@148 114 Window<fftsample> m_windower;
Chris@148 115
Chris@148 116 size_t m_windowSize;
Chris@148 117 size_t m_windowIncrement;
Chris@148 118 size_t m_fftSize;
Chris@148 119 bool m_polar;
Chris@148 120
Chris@148 121 size_t m_width;
Chris@148 122 size_t m_height;
Chris@148 123 size_t m_cacheWidth;
Chris@148 124
Chris@148 125 typedef std::vector<FFTCache *> CacheVector;
Chris@148 126 CacheVector m_caches;
Chris@148 127
Chris@148 128 typedef std::deque<int> IntQueue;
Chris@148 129 IntQueue m_dormantCaches;
Chris@148 130
Chris@148 131 int m_lastUsedCache;
Chris@148 132 FFTCache *getCache(size_t x, size_t &col) {
Chris@148 133 if (m_suspended) resume();
Chris@148 134 col = x % m_cacheWidth;
Chris@148 135 int c = x / m_cacheWidth;
Chris@148 136 // The only use of m_lastUsedCache without a lock is to
Chris@148 137 // establish whether a cache has been created at all (they're
Chris@148 138 // created on demand, but not destroyed until the server is).
Chris@148 139 if (c == m_lastUsedCache) return m_caches[c];
Chris@148 140 else return getCacheAux(c);
Chris@148 141 }
Chris@148 142 bool haveCache(size_t x) {
Chris@148 143 int c = x / m_cacheWidth;
Chris@148 144 if (c == m_lastUsedCache) return true;
Chris@148 145 else return (m_caches[c] != 0);
Chris@148 146 }
Chris@148 147
Chris@148 148 FFTCache *getCacheAux(size_t c);
Chris@148 149 QMutex m_writeMutex;
Chris@148 150 QWaitCondition m_condition;
Chris@148 151
Chris@148 152 fftsample *m_fftInput;
Chris@148 153 fftwf_complex *m_fftOutput;
Chris@148 154 float *m_workbuffer;
Chris@148 155 fftwf_plan m_fftPlan;
Chris@148 156
Chris@148 157 class FillThread : public Thread
Chris@148 158 {
Chris@148 159 public:
Chris@148 160 FillThread(FFTDataServer &server, size_t fillFromColumn) :
Chris@148 161 m_server(server), m_extent(0), m_completion(0),
Chris@148 162 m_fillFrom(fillFromColumn) { }
Chris@148 163
Chris@148 164 size_t getExtent() const { return m_extent; }
Chris@148 165 size_t getCompletion() const { return m_completion ? m_completion : 1; }
Chris@148 166 virtual void run();
Chris@148 167
Chris@148 168 protected:
Chris@148 169 FFTDataServer &m_server;
Chris@148 170 size_t m_extent;
Chris@148 171 size_t m_completion;
Chris@148 172 size_t m_fillFrom;
Chris@148 173 };
Chris@148 174
Chris@148 175 bool m_exiting;
Chris@148 176 bool m_suspended;
Chris@148 177 FillThread *m_fillThread;
Chris@148 178
Chris@148 179 void deleteProcessingData();
Chris@148 180 void fillColumn(size_t x);
Chris@148 181 void resume();
Chris@148 182
Chris@148 183 QString generateFileBasename() const;
Chris@148 184 static QString generateFileBasename(const DenseTimeValueModel *model,
Chris@148 185 int channel,
Chris@148 186 WindowType windowType,
Chris@148 187 size_t windowSize,
Chris@148 188 size_t windowIncrement,
Chris@148 189 size_t fftSize,
Chris@148 190 bool polar);
Chris@148 191
Chris@148 192 typedef std::pair<FFTDataServer *, int> ServerCountPair;
Chris@148 193 typedef std::map<QString, ServerCountPair> ServerMap;
Chris@148 194
Chris@148 195 static ServerMap m_servers;
Chris@148 196 static QMutex m_serverMapMutex;
Chris@148 197 static FFTDataServer *findServer(QString); // call with serverMapMutex held
Chris@148 198 static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held
Chris@148 199 };
Chris@148 200
Chris@148 201 #endif