annotate data/fft/FFTDataServer.h @ 299:576be0d0d218

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents 522f82311e4e
children aa8dbac62024
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@202 7 This file copyright 2006 Chris Cannam and QMUL.
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@226 22 #include "FFTapi.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@215 32 class Model;
Chris@148 33 class FFTCache;
Chris@148 34
Chris@148 35 class FFTDataServer
Chris@148 36 {
Chris@148 37 public:
Chris@148 38 static FFTDataServer *getInstance(const DenseTimeValueModel *model,
Chris@148 39 int channel,
Chris@148 40 WindowType windowType,
Chris@148 41 size_t windowSize,
Chris@148 42 size_t windowIncrement,
Chris@148 43 size_t fftSize,
Chris@148 44 bool polar,
Chris@148 45 size_t fillFromColumn = 0);
Chris@148 46
Chris@148 47 static FFTDataServer *getFuzzyInstance(const DenseTimeValueModel *model,
Chris@148 48 int channel,
Chris@148 49 WindowType windowType,
Chris@148 50 size_t windowSize,
Chris@148 51 size_t windowIncrement,
Chris@148 52 size_t fftSize,
Chris@148 53 bool polar,
Chris@148 54 size_t fillFromColumn = 0);
Chris@148 55
Chris@152 56 static void claimInstance(FFTDataServer *);
Chris@148 57 static void releaseInstance(FFTDataServer *);
Chris@148 58
Chris@215 59 static void modelAboutToBeDeleted(Model *);
Chris@215 60
Chris@148 61 const DenseTimeValueModel *getModel() const { return m_model; }
Chris@148 62 int getChannel() const { return m_channel; }
Chris@148 63 WindowType getWindowType() const { return m_windower.getType(); }
Chris@148 64 size_t getWindowSize() const { return m_windowSize; }
Chris@148 65 size_t getWindowIncrement() const { return m_windowIncrement; }
Chris@148 66 size_t getFFTSize() const { return m_fftSize; }
Chris@148 67 bool getPolar() const { return m_polar; }
Chris@148 68
Chris@148 69 size_t getWidth() const { return m_width; }
Chris@148 70 size_t getHeight() const { return m_height; }
Chris@148 71
Chris@148 72 float getMagnitudeAt(size_t x, size_t y);
Chris@148 73 float getNormalizedMagnitudeAt(size_t x, size_t y);
Chris@148 74 float getMaximumMagnitudeAt(size_t x);
Chris@148 75 float getPhaseAt(size_t x, size_t y);
Chris@148 76 void getValuesAt(size_t x, size_t y, float &real, float &imaginary);
Chris@148 77 bool isColumnReady(size_t x);
Chris@148 78
Chris@148 79 void suspend();
Chris@155 80 void suspendWrites();
Chris@154 81 void resume(); // also happens automatically if new data needed
Chris@148 82
Chris@148 83 // Convenience functions:
Chris@148 84
Chris@148 85 bool isLocalPeak(size_t x, size_t y) {
Chris@148 86 float mag = getMagnitudeAt(x, y);
Chris@148 87 if (y > 0 && mag < getMagnitudeAt(x, y - 1)) return false;
Chris@148 88 if (y < getHeight()-1 && mag < getMagnitudeAt(x, y + 1)) return false;
Chris@148 89 return true;
Chris@148 90 }
Chris@148 91 bool isOverThreshold(size_t x, size_t y, float threshold) {
Chris@148 92 return getMagnitudeAt(x, y) > threshold;
Chris@148 93 }
Chris@148 94
Chris@148 95 size_t getFillCompletion() const;
Chris@148 96 size_t getFillExtent() const;
Chris@148 97
Chris@148 98 private:
Chris@148 99 FFTDataServer(QString fileBaseName,
Chris@148 100 const DenseTimeValueModel *model,
Chris@148 101 int channel,
Chris@148 102 WindowType windowType,
Chris@148 103 size_t windowSize,
Chris@148 104 size_t windowIncrement,
Chris@148 105 size_t fftSize,
Chris@148 106 bool polar,
Chris@148 107 size_t fillFromColumn = 0);
Chris@148 108
Chris@148 109 virtual ~FFTDataServer();
Chris@148 110
Chris@148 111 FFTDataServer(const FFTDataServer &); // not implemented
Chris@148 112 FFTDataServer &operator=(const FFTDataServer &); // not implemented
Chris@148 113
Chris@148 114 typedef float fftsample;
Chris@148 115
Chris@148 116 QString m_fileBaseName;
Chris@148 117 const DenseTimeValueModel *m_model;
Chris@148 118 int m_channel;
Chris@148 119
Chris@148 120 Window<fftsample> m_windower;
Chris@148 121
Chris@148 122 size_t m_windowSize;
Chris@148 123 size_t m_windowIncrement;
Chris@148 124 size_t m_fftSize;
Chris@148 125 bool m_polar;
Chris@148 126
Chris@148 127 size_t m_width;
Chris@148 128 size_t m_height;
Chris@148 129 size_t m_cacheWidth;
Chris@183 130 size_t m_cacheWidthPower;
Chris@183 131 size_t m_cacheWidthMask;
Chris@172 132 bool m_memoryCache;
Chris@172 133 bool m_compactCache;
Chris@148 134
Chris@148 135 typedef std::vector<FFTCache *> CacheVector;
Chris@148 136 CacheVector m_caches;
Chris@148 137
Chris@148 138 typedef std::deque<int> IntQueue;
Chris@148 139 IntQueue m_dormantCaches;
Chris@148 140
Chris@148 141 int m_lastUsedCache;
Chris@148 142 FFTCache *getCache(size_t x, size_t &col) {
Chris@148 143 col = x % m_cacheWidth;
Chris@148 144 int c = x / m_cacheWidth;
Chris@148 145 // The only use of m_lastUsedCache without a lock is to
Chris@148 146 // establish whether a cache has been created at all (they're
Chris@148 147 // created on demand, but not destroyed until the server is).
Chris@148 148 if (c == m_lastUsedCache) return m_caches[c];
Chris@148 149 else return getCacheAux(c);
Chris@148 150 }
Chris@148 151 bool haveCache(size_t x) {
Chris@148 152 int c = x / m_cacheWidth;
Chris@148 153 if (c == m_lastUsedCache) return true;
Chris@148 154 else return (m_caches[c] != 0);
Chris@148 155 }
Chris@148 156
Chris@148 157 FFTCache *getCacheAux(size_t c);
Chris@148 158 QMutex m_writeMutex;
Chris@148 159 QWaitCondition m_condition;
Chris@148 160
Chris@148 161 fftsample *m_fftInput;
Chris@226 162 fftf_complex *m_fftOutput;
Chris@148 163 float *m_workbuffer;
Chris@226 164 fftf_plan m_fftPlan;
Chris@148 165
Chris@148 166 class FillThread : public Thread
Chris@148 167 {
Chris@148 168 public:
Chris@148 169 FillThread(FFTDataServer &server, size_t fillFromColumn) :
Chris@148 170 m_server(server), m_extent(0), m_completion(0),
Chris@148 171 m_fillFrom(fillFromColumn) { }
Chris@148 172
Chris@148 173 size_t getExtent() const { return m_extent; }
Chris@148 174 size_t getCompletion() const { return m_completion ? m_completion : 1; }
Chris@148 175 virtual void run();
Chris@148 176
Chris@148 177 protected:
Chris@148 178 FFTDataServer &m_server;
Chris@148 179 size_t m_extent;
Chris@148 180 size_t m_completion;
Chris@148 181 size_t m_fillFrom;
Chris@148 182 };
Chris@148 183
Chris@148 184 bool m_exiting;
Chris@148 185 bool m_suspended;
Chris@148 186 FillThread *m_fillThread;
Chris@148 187
Chris@148 188 void deleteProcessingData();
Chris@148 189 void fillColumn(size_t x);
Chris@148 190
Chris@148 191 QString generateFileBasename() const;
Chris@148 192 static QString generateFileBasename(const DenseTimeValueModel *model,
Chris@148 193 int channel,
Chris@148 194 WindowType windowType,
Chris@148 195 size_t windowSize,
Chris@148 196 size_t windowIncrement,
Chris@148 197 size_t fftSize,
Chris@148 198 bool polar);
Chris@148 199
Chris@148 200 typedef std::pair<FFTDataServer *, int> ServerCountPair;
Chris@148 201 typedef std::map<QString, ServerCountPair> ServerMap;
Chris@215 202 typedef std::deque<FFTDataServer *> ServerQueue;
Chris@148 203
Chris@148 204 static ServerMap m_servers;
Chris@215 205 static ServerQueue m_releasedServers; // these are still in m_servers as well, with zero refcount
Chris@148 206 static QMutex m_serverMapMutex;
Chris@148 207 static FFTDataServer *findServer(QString); // call with serverMapMutex held
Chris@148 208 static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held
Chris@216 209
Chris@216 210 static void claimInstance(FFTDataServer *, bool needLock);
Chris@216 211 static void releaseInstance(FFTDataServer *, bool needLock);
Chris@216 212
Chris@148 213 };
Chris@148 214
Chris@148 215 #endif