annotate data/fft/FFTDataServer.h @ 335:02d2ad95ea52 spectrogram-cache-rejig

* Get storage advice for each cache in an FFT data server. Allows us to be more confident about the actual memory situation and cut over from memory to disc part way through an FFT calculation if necessary. StorageAdviser is now a bit too optimistic though (it's too keen to allocate large numbers of small blocks in memory).
author Chris Cannam
date Tue, 13 Nov 2007 13:54:10 +0000
parents aa8dbac62024
children 115f60df1e4d
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@334 21 #include "base/StorageAdviser.h"
Chris@148 22
Chris@226 23 #include "FFTapi.h"
Chris@148 24
Chris@148 25 #include <QMutex>
Chris@148 26 #include <QWaitCondition>
Chris@148 27 #include <QString>
Chris@148 28
Chris@148 29 #include <vector>
Chris@148 30 #include <deque>
Chris@148 31
Chris@148 32 class DenseTimeValueModel;
Chris@215 33 class Model;
Chris@148 34 class FFTCache;
Chris@148 35
Chris@148 36 class FFTDataServer
Chris@148 37 {
Chris@148 38 public:
Chris@148 39 static FFTDataServer *getInstance(const DenseTimeValueModel *model,
Chris@148 40 int channel,
Chris@148 41 WindowType windowType,
Chris@148 42 size_t windowSize,
Chris@148 43 size_t windowIncrement,
Chris@148 44 size_t fftSize,
Chris@148 45 bool polar,
Chris@334 46 StorageAdviser::Criteria criteria =
Chris@334 47 StorageAdviser::NoCriteria,
Chris@148 48 size_t fillFromColumn = 0);
Chris@148 49
Chris@148 50 static FFTDataServer *getFuzzyInstance(const DenseTimeValueModel *model,
Chris@148 51 int channel,
Chris@148 52 WindowType windowType,
Chris@148 53 size_t windowSize,
Chris@148 54 size_t windowIncrement,
Chris@148 55 size_t fftSize,
Chris@148 56 bool polar,
Chris@334 57 StorageAdviser::Criteria criteria =
Chris@334 58 StorageAdviser::NoCriteria,
Chris@148 59 size_t fillFromColumn = 0);
Chris@148 60
Chris@152 61 static void claimInstance(FFTDataServer *);
Chris@148 62 static void releaseInstance(FFTDataServer *);
Chris@148 63
Chris@215 64 static void modelAboutToBeDeleted(Model *);
Chris@215 65
Chris@148 66 const DenseTimeValueModel *getModel() const { return m_model; }
Chris@148 67 int getChannel() const { return m_channel; }
Chris@148 68 WindowType getWindowType() const { return m_windower.getType(); }
Chris@148 69 size_t getWindowSize() const { return m_windowSize; }
Chris@148 70 size_t getWindowIncrement() const { return m_windowIncrement; }
Chris@148 71 size_t getFFTSize() const { return m_fftSize; }
Chris@148 72 bool getPolar() const { return m_polar; }
Chris@148 73
Chris@148 74 size_t getWidth() const { return m_width; }
Chris@148 75 size_t getHeight() const { return m_height; }
Chris@148 76
Chris@148 77 float getMagnitudeAt(size_t x, size_t y);
Chris@148 78 float getNormalizedMagnitudeAt(size_t x, size_t y);
Chris@148 79 float getMaximumMagnitudeAt(size_t x);
Chris@148 80 float getPhaseAt(size_t x, size_t y);
Chris@148 81 void getValuesAt(size_t x, size_t y, float &real, float &imaginary);
Chris@148 82 bool isColumnReady(size_t x);
Chris@148 83
Chris@148 84 void suspend();
Chris@155 85 void suspendWrites();
Chris@154 86 void resume(); // also happens automatically if new data needed
Chris@148 87
Chris@148 88 // Convenience functions:
Chris@148 89
Chris@148 90 bool isLocalPeak(size_t x, size_t y) {
Chris@148 91 float mag = getMagnitudeAt(x, y);
Chris@148 92 if (y > 0 && mag < getMagnitudeAt(x, y - 1)) return false;
Chris@148 93 if (y < getHeight()-1 && mag < getMagnitudeAt(x, y + 1)) return false;
Chris@148 94 return true;
Chris@148 95 }
Chris@148 96 bool isOverThreshold(size_t x, size_t y, float threshold) {
Chris@148 97 return getMagnitudeAt(x, y) > threshold;
Chris@148 98 }
Chris@148 99
Chris@148 100 size_t getFillCompletion() const;
Chris@148 101 size_t getFillExtent() const;
Chris@148 102
Chris@148 103 private:
Chris@148 104 FFTDataServer(QString fileBaseName,
Chris@148 105 const DenseTimeValueModel *model,
Chris@148 106 int channel,
Chris@148 107 WindowType windowType,
Chris@148 108 size_t windowSize,
Chris@148 109 size_t windowIncrement,
Chris@148 110 size_t fftSize,
Chris@148 111 bool polar,
Chris@334 112 StorageAdviser::Criteria criteria,
Chris@148 113 size_t fillFromColumn = 0);
Chris@148 114
Chris@148 115 virtual ~FFTDataServer();
Chris@148 116
Chris@148 117 FFTDataServer(const FFTDataServer &); // not implemented
Chris@148 118 FFTDataServer &operator=(const FFTDataServer &); // not implemented
Chris@148 119
Chris@148 120 typedef float fftsample;
Chris@148 121
Chris@148 122 QString m_fileBaseName;
Chris@148 123 const DenseTimeValueModel *m_model;
Chris@148 124 int m_channel;
Chris@148 125
Chris@148 126 Window<fftsample> m_windower;
Chris@148 127
Chris@148 128 size_t m_windowSize;
Chris@148 129 size_t m_windowIncrement;
Chris@148 130 size_t m_fftSize;
Chris@148 131 bool m_polar;
Chris@148 132
Chris@148 133 size_t m_width;
Chris@148 134 size_t m_height;
Chris@148 135 size_t m_cacheWidth;
Chris@183 136 size_t m_cacheWidthPower;
Chris@183 137 size_t m_cacheWidthMask;
Chris@335 138
Chris@335 139 int m_lastUsedCache;
Chris@335 140 FFTCache *getCache(size_t x, size_t &col) {
Chris@335 141 col = x & m_cacheWidthMask;
Chris@335 142 int c = x >> m_cacheWidthPower;
Chris@335 143 // The only use of m_lastUsedCache without a lock is to
Chris@335 144 // establish whether a cache has been created at all (they're
Chris@335 145 // created on demand, but not destroyed until the server is).
Chris@335 146 if (c == m_lastUsedCache) return m_caches[c];
Chris@335 147 else return getCacheAux(c);
Chris@335 148 }
Chris@335 149 bool haveCache(size_t x) {
Chris@335 150 int c = x >> m_cacheWidthPower;
Chris@335 151 if (c == m_lastUsedCache) return true;
Chris@335 152 else return (m_caches[c] != 0);
Chris@335 153 }
Chris@148 154
Chris@148 155 typedef std::vector<FFTCache *> CacheVector;
Chris@148 156 CacheVector m_caches;
Chris@148 157
Chris@148 158 typedef std::deque<int> IntQueue;
Chris@148 159 IntQueue m_dormantCaches;
Chris@148 160
Chris@335 161 StorageAdviser::Criteria m_criteria;
Chris@335 162
Chris@335 163 void getStorageAdvice(size_t w, size_t h, bool &memory, bool &compact);
Chris@148 164
Chris@148 165 FFTCache *getCacheAux(size_t c);
Chris@148 166 QMutex m_writeMutex;
Chris@148 167 QWaitCondition m_condition;
Chris@148 168
Chris@148 169 fftsample *m_fftInput;
Chris@226 170 fftf_complex *m_fftOutput;
Chris@148 171 float *m_workbuffer;
Chris@226 172 fftf_plan m_fftPlan;
Chris@148 173
Chris@148 174 class FillThread : public Thread
Chris@148 175 {
Chris@148 176 public:
Chris@148 177 FillThread(FFTDataServer &server, size_t fillFromColumn) :
Chris@148 178 m_server(server), m_extent(0), m_completion(0),
Chris@148 179 m_fillFrom(fillFromColumn) { }
Chris@148 180
Chris@148 181 size_t getExtent() const { return m_extent; }
Chris@148 182 size_t getCompletion() const { return m_completion ? m_completion : 1; }
Chris@148 183 virtual void run();
Chris@148 184
Chris@148 185 protected:
Chris@148 186 FFTDataServer &m_server;
Chris@148 187 size_t m_extent;
Chris@148 188 size_t m_completion;
Chris@148 189 size_t m_fillFrom;
Chris@148 190 };
Chris@148 191
Chris@148 192 bool m_exiting;
Chris@148 193 bool m_suspended;
Chris@148 194 FillThread *m_fillThread;
Chris@148 195
Chris@148 196 void deleteProcessingData();
Chris@148 197 void fillColumn(size_t x);
Chris@148 198
Chris@148 199 QString generateFileBasename() const;
Chris@148 200 static QString generateFileBasename(const DenseTimeValueModel *model,
Chris@148 201 int channel,
Chris@148 202 WindowType windowType,
Chris@148 203 size_t windowSize,
Chris@148 204 size_t windowIncrement,
Chris@148 205 size_t fftSize,
Chris@148 206 bool polar);
Chris@148 207
Chris@148 208 typedef std::pair<FFTDataServer *, int> ServerCountPair;
Chris@148 209 typedef std::map<QString, ServerCountPair> ServerMap;
Chris@215 210 typedef std::deque<FFTDataServer *> ServerQueue;
Chris@148 211
Chris@148 212 static ServerMap m_servers;
Chris@215 213 static ServerQueue m_releasedServers; // these are still in m_servers as well, with zero refcount
Chris@148 214 static QMutex m_serverMapMutex;
Chris@148 215 static FFTDataServer *findServer(QString); // call with serverMapMutex held
Chris@148 216 static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held
Chris@216 217
Chris@216 218 static void claimInstance(FFTDataServer *, bool needLock);
Chris@216 219 static void releaseInstance(FFTDataServer *, bool needLock);
Chris@216 220
Chris@148 221 };
Chris@148 222
Chris@148 223 #endif