changeset 110:f262aa8973e3

* Update SpectrogramLayer to use new FFTDataServer
author Chris Cannam
date Tue, 27 Jun 2006 19:18:42 +0000
parents 12340cb6e6cb
children ab55c427e068
files layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h
diffstat 2 files changed, 116 insertions(+), 543 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Mon Jun 26 16:12:11 2006 +0000
+++ b/layer/SpectrogramLayer.cpp	Tue Jun 27 19:18:42 2006 +0000
@@ -20,7 +20,7 @@
 #include "base/AudioLevel.h"
 #include "base/Window.h"
 #include "base/Pitch.h"
-#include "fileio/FFTFileCache.h"
+#include "fileio/FFTDataServer.h"
 
 #include <QPainter>
 #include <QImage>
@@ -55,10 +55,8 @@
     m_frequencyScale(LinearFrequencyScale),
     m_binDisplay(AllBins),
     m_normalizeColumns(false),
-    m_cache(0),
-    m_writeCache(0),
-    m_cacheInvalid(true),
-    m_fillThread(0),
+    m_fftServer(0),
+//    m_fftServerChanged(true),
     m_updateTimer(0),
     m_candidateFillStartFrame(0),
     m_lastFillExtent(0),
@@ -81,20 +79,19 @@
 	setBinDisplay(PeakFrequencies);
 	setNormalizeColumns(true);
     }
+
+    setColourmap();
 }
 
 SpectrogramLayer::~SpectrogramLayer()
 {
     delete m_updateTimer;
     m_updateTimer = 0;
-
-    m_exiting = true;
-    m_condition.wakeAll();
-    if (m_fillThread) m_fillThread->wait();
-    delete m_fillThread;
     
-    delete m_writeCache;
-    delete m_cache;
+    if (m_fftServer) {
+        FFTDataServer::releaseInstance(m_fftServer);
+        m_fftServer = 0;
+    }
 }
 
 void
@@ -102,10 +99,10 @@
 {
 //    std::cerr << "SpectrogramLayer(" << this << "): setModel(" << model << ")" << std::endl;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
+    if (model == m_model) return;
+
     m_model = model;
-    m_mutex.unlock();
+    getFFTServer();
 
     if (!m_model || !m_model->isOK()) return;
 
@@ -121,7 +118,35 @@
 	    this, SLOT(cacheInvalid(size_t, size_t)));
 
     emit modelReplaced();
-    fillCache();
+}
+
+void
+SpectrogramLayer::getFFTServer()
+{
+    //!!! really want to check that params differ from previous ones
+
+    if (m_fftServer) {
+        FFTDataServer::releaseInstance(m_fftServer);
+        m_fftServer = 0;
+    }
+
+    if (m_model) {
+        m_fftServer = FFTDataServer::getInstance(m_model,
+                                                 m_channel,
+                                                 m_windowType,
+                                                 m_windowSize,
+                                                 getWindowIncrement(),
+                                                 m_fftSize,
+                                                 true,
+                                                 m_candidateFillStartFrame);
+
+        m_lastFillExtent = 0;
+
+        delete m_updateTimer;
+        m_updateTimer = new QTimer(this);
+        connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
+        m_updateTimer->start(200);
+    }
 }
 
 Layer::PropertyList
@@ -549,17 +574,11 @@
 {
     if (m_channel == ch) return;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
-    
     m_channel = ch;
-
-    m_mutex.unlock();
+    getFFTServer();
 
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 int
@@ -573,18 +592,14 @@
 {
     if (m_windowSize == ws) return;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
     
     m_windowSize = ws;
     m_fftSize = ws * (m_zeroPadLevel + 1);
     
-    m_mutex.unlock();
+    getFFTServer();
 
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 size_t
@@ -598,17 +613,15 @@
 {
     if (m_windowHopLevel == v) return;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
     
     m_windowHopLevel = v;
     
-    m_mutex.unlock();
+    getFFTServer();
 
     emit layerParametersChanged();
 
-    fillCache();
+//    fillCache();
 }
 
 size_t
@@ -622,18 +635,14 @@
 {
     if (m_zeroPadLevel == v) return;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
     
     m_zeroPadLevel = v;
     m_fftSize = m_windowSize * (v + 1);
-    
-    m_mutex.unlock();
+
+    getFFTServer();
 
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 size_t
@@ -647,17 +656,13 @@
 {
     if (m_windowType == w) return;
 
-    m_mutex.lock();
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
     
     m_windowType = w;
-    
-    m_mutex.unlock();
+
+    getFFTServer();
 
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 WindowType
@@ -674,16 +679,11 @@
 
     if (m_gain == gain) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_gain = gain;
     
-    m_mutex.unlock();
-
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 float
@@ -697,16 +697,11 @@
 {
     if (m_threshold == threshold) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_threshold = threshold;
-    
-    m_mutex.unlock();
 
     emit layerParametersChanged();
-
-    fillCache();
 }
 
 float
@@ -720,12 +715,9 @@
 {
     if (m_minFrequency == mf) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_minFrequency = mf;
-    
-    m_mutex.unlock();
 
     emit layerParametersChanged();
 }
@@ -741,13 +733,10 @@
 {
     if (m_maxFrequency == mf) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_maxFrequency = mf;
     
-    m_mutex.unlock();
-
     emit layerParametersChanged();
 }
 
@@ -760,7 +749,6 @@
 void
 SpectrogramLayer::setColourRotation(int r)
 {
-    m_mutex.lock();
     invalidatePixmapCaches();
 
     if (r < 0) r = 0;
@@ -772,8 +760,6 @@
 	m_colourRotation = r;
     }
     
-    m_mutex.unlock();
-
     emit layerParametersChanged();
 }
 
@@ -782,14 +768,10 @@
 {
     if (m_colourScale == colourScale) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_colourScale = colourScale;
     
-    m_mutex.unlock();
-    fillCache();
-
     emit layerParametersChanged();
 }
 
@@ -804,14 +786,11 @@
 {
     if (m_colourScheme == scheme) return;
 
-    m_mutex.lock();
     invalidatePixmapCaches();
     
     m_colourScheme = scheme;
     setColourmap();
 
-    m_mutex.unlock();
-
     emit layerParametersChanged();
 }
 
@@ -826,13 +805,8 @@
 {
     if (m_frequencyScale == frequencyScale) return;
 
-    m_mutex.lock();
-
     invalidatePixmapCaches();
-    
     m_frequencyScale = frequencyScale;
-    
-    m_mutex.unlock();
 
     emit layerParametersChanged();
 }
@@ -848,15 +822,8 @@
 {
     if (m_binDisplay == binDisplay) return;
 
-    m_mutex.lock();
-
     invalidatePixmapCaches();
-    
     m_binDisplay = binDisplay;
-    
-    m_mutex.unlock();
-
-    fillCache();
 
     emit layerParametersChanged();
 }
@@ -871,13 +838,10 @@
 SpectrogramLayer::setNormalizeColumns(bool n)
 {
     if (m_normalizeColumns == n) return;
-    m_mutex.lock();
 
     invalidatePixmapCaches();
     m_normalizeColumns = n;
-    m_mutex.unlock();
 
-    fillCache();
     emit layerParametersChanged();
 }
 
@@ -890,18 +854,12 @@
 void
 SpectrogramLayer::setLayerDormant(const View *v, bool dormant)
 {
-    QMutexLocker locker(&m_mutex);
-
     if (dormant == m_dormancy[v]) return;
 
     if (dormant) {
 
 	m_dormancy[v] = true;
 
-//	delete m_cache;
-//	m_cache = 0;
-	
-	m_cacheInvalid = true;
 	invalidatePixmapCaches();
         m_pixmapCaches.erase(v);
 	
@@ -914,9 +872,7 @@
 void
 SpectrogramLayer::cacheInvalid()
 {
-    m_cacheInvalid = true;
     invalidatePixmapCaches();
-    fillCache();
 }
 
 void
@@ -927,34 +883,11 @@
 }
 
 void
-SpectrogramLayer::fillCache()
-{
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-    std::cerr << "SpectrogramLayer::fillCache" << std::endl;
-#endif
-    QMutexLocker locker(&m_mutex);
-
-    m_lastFillExtent = 0;
-
-    delete m_updateTimer;
-    m_updateTimer = new QTimer(this);
-    connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(fillTimerTimedOut()));
-    m_updateTimer->start(200);
-
-    if (!m_fillThread) {
-	std::cerr << "SpectrogramLayer::fillCache creating thread" << std::endl;
-	m_fillThread = new CacheFillThread(*this);
-	m_fillThread->start();
-    }
-
-    m_condition.wakeAll();
-}   
-
-void
 SpectrogramLayer::fillTimerTimedOut()
 {
-    if (m_fillThread && m_model) {
-	size_t fillExtent = m_fillThread->getFillExtent();
+    if (m_fftServer && m_model) {
+
+	size_t fillExtent = m_fftServer->getFillExtent();
 #ifdef DEBUG_SPECTROGRAM_REPAINT
 	std::cerr << "SpectrogramLayer::fillTimerTimedOut: extent " << fillExtent << ", last " << m_lastFillExtent << ", total " << m_model->getEndFrame() << std::endl;
 #endif
@@ -978,16 +911,12 @@
 		m_lastFillExtent = fillExtent;
 	    }
 	} else {
-//	    if (v) {
-		size_t sf = 0;
-//!!!		if (v->getStartFrame() > 0) sf = v->getStartFrame();
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-		std::cerr << "SpectrogramLayer: going backwards, emitting modelChanged("
-			  << sf << "," << m_model->getEndFrame() << ")" << std::endl;
+            std::cerr << "SpectrogramLayer: going backwards, emitting modelChanged("
+                      << m_model->getStartFrame() << "," << m_model->getEndFrame() << ")" << std::endl;
 #endif
-		invalidatePixmapCaches();
-		emit modelChanged(sf, m_model->getEndFrame());
-//	    }
+            invalidatePixmapCaches();
+            emit modelChanged(m_model->getStartFrame(), m_model->getEndFrame());
 	    m_lastFillExtent = fillExtent;
 	}
     }
@@ -1072,7 +1001,7 @@
 void
 SpectrogramLayer::rotateColourmap(int distance)
 {
-    if (!m_cache) return;
+    if (!m_fftServer) return;
 
     QColor newPixels[256];
 
@@ -1132,89 +1061,6 @@
     return frequency;
 }
 
-void
-SpectrogramLayer::fillCacheColumn(int column,
-                                  fftsample *input,
-				  fftwf_complex *output,
-				  fftwf_plan plan, 
-				  size_t windowSize,
-                                  size_t fftSize,
-				  size_t increment,
-                                  float *workbuffer,
-				  const Window<fftsample> &windower) const
-{
-    //!!! we _do_ need a lock for these references to the model
-    // though, don't we?
-
-    int startFrame = increment * column;
-    int endFrame = startFrame + windowSize;
-
-    startFrame -= int(windowSize - increment) / 2;
-    endFrame   -= int(windowSize - increment) / 2;
-    size_t pfx = 0;
-
-    size_t off = (m_fftSize - m_windowSize) / 2;
-
-    for (size_t i = 0; i < off; ++i) {
-        input[i] = 0.0;
-        input[m_fftSize - i - 1] = 0.0;
-    }
-
-    if (startFrame < 0) {
-	pfx = size_t(-startFrame);
-	for (size_t i = 0; i < pfx; ++i) {
-	    input[off + i] = 0.0;
-	}
-    }
-
-    size_t got = m_model->getValues(m_channel, startFrame + pfx,
-				    endFrame, input + off + pfx);
-
-    while (got + pfx < windowSize) {
-	input[off + got + pfx] = 0.0;
-	++got;
-    }
-
-    if (m_channel == -1) {
-	int channels = m_model->getChannelCount();
-	if (channels > 1) {
-	    for (size_t i = 0; i < windowSize; ++i) {
-		input[off + i] /= channels;
-	    }
-	}
-    }
-
-    windower.cut(input + off);
-
-    for (size_t i = 0; i < fftSize/2; ++i) {
-	fftsample temp = input[i];
-	input[i] = input[i + fftSize/2];
-	input[i + fftSize/2] = temp;
-    }
-
-    fftwf_execute(plan);
-
-    fftsample factor = 0.0;
-
-    for (size_t i = 0; i < fftSize/2; ++i) {
-
-	fftsample mag = sqrtf(output[i][0] * output[i][0] +
-                              output[i][1] * output[i][1]);
-	mag /= windowSize / 2;
-
-	if (mag > factor) factor = mag;
-
-	fftsample phase = atan2f(output[i][1], output[i][0]);
-	phase = princargf(phase);
-
-        workbuffer[i] = mag;
-        workbuffer[i + fftSize/2] = phase;
-    }
-
-    m_writeCache->setColumnAt(column, workbuffer,
-                              workbuffer + fftSize/2, factor);
-}
-
 unsigned char
 SpectrogramLayer::getDisplayValue(float input) const
 {
@@ -1284,208 +1130,6 @@
     return input;
 }
 
-void
-SpectrogramLayer::CacheFillThread::run()
-{
-//    std::cerr << "SpectrogramLayer::CacheFillThread::run" << std::endl;
-
-    m_layer.m_mutex.lock();
-
-    while (!m_layer.m_exiting) {
-
-	bool interrupted = false;
-
-//	std::cerr << "SpectrogramLayer::CacheFillThread::run in loop" << std::endl;
-
-	bool haveUndormantViews = false;
-
-	for (std::map<const void *, bool>::iterator i =
-		 m_layer.m_dormancy.begin();
-	     i != m_layer.m_dormancy.end(); ++i) {
-
-	    if (!i->second) {
-		haveUndormantViews = true;
-		break;
-	    }
-	}
-
-	if (!haveUndormantViews) {
-
-	    if (m_layer.m_cacheInvalid && m_layer.m_cache) {
-		std::cerr << "All views dormant, freeing spectrogram cache"
-			  << std::endl;
-	
-		delete m_layer.m_cache;
-		m_layer.m_cache = 0;
-	    }
-
-	} else if (m_layer.m_model && m_layer.m_cacheInvalid) {
-
-//	    std::cerr << "SpectrogramLayer::CacheFillThread::run: something to do" << std::endl;
-
-	    while (!m_layer.m_model->isReady()) {
-		m_layer.m_condition.wait(&m_layer.m_mutex, 100);
-		if (m_layer.m_exiting) break;
-	    }
-
-	    if (m_layer.m_exiting) break;
-
-	    m_layer.m_cacheInvalid = false;
-	    m_fillExtent = 0;
-	    m_fillCompletion = 0;
-
-	//    std::cerr << "SpectrogramLayer::CacheFillThread::run: model is ready" << std::endl;
-
-	    size_t start = m_layer.m_model->getStartFrame();
-	    size_t end = m_layer.m_model->getEndFrame();
-
-	//    std::cerr << "start = " << start << ", end = " << end << std::endl;
-
-	    WindowType windowType = m_layer.m_windowType;
-	    size_t windowSize = m_layer.m_windowSize;
-	    size_t windowIncrement = m_layer.getWindowIncrement();
-            size_t fftSize = m_layer.m_fftSize;
-
-        //    std::cerr << "\nWINDOW INCREMENT: " << windowIncrement << " (for hop level " << m_layer.m_windowHopLevel << ")\n" << std::endl;
-
-	    size_t visibleStart = m_layer.m_candidateFillStartFrame;
-	    visibleStart = (visibleStart / windowIncrement) * windowIncrement;
-
-	    size_t width = (end - start) / windowIncrement + 1;
-	    size_t height = fftSize / 2;
-
-//!!!	    if (!m_layer.m_cache) {
-//		m_layer.m_cache = new FFTMemoryCache;
-//	    }
-            if (!m_layer.m_writeCache) {
-                m_layer.m_writeCache = new FFTFileCache
-                    (QString("%1").arg(getObjectExportId(&m_layer)),
-                     MatrixFile::ReadWrite, true);
-            }
-	    m_layer.m_writeCache->resize(width, height);
-            if (m_layer.m_cache) delete m_layer.m_cache;
-            m_layer.m_cache = new FFTFileCache
-                (QString("%1").arg(getObjectExportId(&m_layer)),
-                 MatrixFile::ReadOnly, true);
-
-	    m_layer.setColourmap();
-//!!!	    m_layer.m_writeCache->reset();
-
-	    fftsample *input = (fftsample *)
-		fftwf_malloc(fftSize * sizeof(fftsample));
-
-	    fftwf_complex *output = (fftwf_complex *)
-		fftwf_malloc(fftSize * sizeof(fftwf_complex));
-
-            float *workbuffer = (float *)
-                fftwf_malloc(fftSize * sizeof(float));
-
-	    fftwf_plan plan = fftwf_plan_dft_r2c_1d(fftSize, input,
-                                                    output, FFTW_ESTIMATE);
-
-	    if (!plan) {
-		std::cerr << "WARNING: fftwf_plan_dft_r2c_1d(" << windowSize << ") failed!" << std::endl;
-		fftwf_free(input);
-		fftwf_free(output);
-                fftwf_free(workbuffer);
-		continue;
-	    }
-
-	    // We don't need a lock when writing to or reading from
-	    // the pixels in the cache.  We do need to ensure we have
-	    // the width and height of the cache and the FFT
-	    // parameters known before we unlock, in case they change
-	    // in the model while we aren't holding a lock.  It's safe
-	    // for us to continue to use the "old" values if that
-	    // happens, because they will continue to match the
-	    // dimensions of the actual cache (which this thread
-	    // manages, not the layer's).
-	    m_layer.m_mutex.unlock();
-
-	    Window<fftsample> windower(windowType, windowSize);
-
-	    int counter = 0;
-	    int updateAt = (end / windowIncrement) / 20;
-	    if (updateAt < 100) updateAt = 100;
-
-	    bool doVisibleFirst = (visibleStart != start);
-
-	    if (doVisibleFirst) {
-
-		for (size_t f = visibleStart; f < end; f += windowIncrement) {
-	    
-		    m_layer.fillCacheColumn(int((f - start) / windowIncrement),
-					    input, output, plan,
-					    windowSize, fftSize,
-                                            windowIncrement,
-                                            workbuffer, windower);
-
-		    if (m_layer.m_cacheInvalid || m_layer.m_exiting) {
-			interrupted = true;
-			m_fillExtent = 0;
-			break;
-		    }
-
-		    if (++counter == updateAt) {
-			m_fillExtent = f;
-			m_fillCompletion = size_t(100 * fabsf(float(f - visibleStart) /
-							      float(end - start)));
-			counter = 0;
-		    }
-		}
-	    }
-
-	    if (!interrupted) {
-
-		size_t remainingEnd = end;
-		if (doVisibleFirst) {
-		    remainingEnd = visibleStart;
-		    if (remainingEnd > start) --remainingEnd;
-		    else remainingEnd = start;
-		}
-		size_t baseCompletion = m_fillCompletion;
-
-		for (size_t f = start; f < remainingEnd; f += windowIncrement) {
-
-		    m_layer.fillCacheColumn(int((f - start) / windowIncrement),
-					    input, output, plan,
-					    windowSize, fftSize,
-                                            windowIncrement,
-					    workbuffer, windower);
-
-		    if (m_layer.m_cacheInvalid || m_layer.m_exiting) {
-			interrupted = true;
-			m_fillExtent = 0;
-			break;
-		    }
-		    
-		    if (++counter == updateAt) {
-			m_fillExtent = f;
-			m_fillCompletion = baseCompletion +
-			    size_t(100 * fabsf(float(f - start) /
-					       float(end - start)));
-			counter = 0;
-		    }
-		}
-	    }
-
-	    fftwf_destroy_plan(plan);
-	    fftwf_free(output);
-	    fftwf_free(input);
-            fftwf_free(workbuffer);
-
-	    if (!interrupted) {
-		m_fillExtent = end;
-		m_fillCompletion = 100;
-	    }
-
-	    m_layer.m_mutex.lock();
-	}
-
-	if (!interrupted) m_layer.m_condition.wait(&m_layer.m_mutex, 2000);
-    }
-}
-
 float
 SpectrogramLayer::getEffectiveMinFrequency() const
 {
@@ -1615,6 +1259,8 @@
 					     float &adjFreqMin, float &adjFreqMax)
 const
 {
+    if (!m_fftServer) return false;
+
     float s0 = 0, s1 = 0;
     if (!getXBinRange(v, x, s0, s1)) return false;
 
@@ -1645,23 +1291,21 @@
 	    if (q == q0i) freqMin = binfreq;
 	    if (q == q1i) freqMax = binfreq;
 
-	    if (!m_cache || m_cacheInvalid) break; //!!! lock?
+	    if (peaksOnly && !m_fftServer->isLocalPeak(s, q)) continue;
 
-	    if (peaksOnly && !m_cache->isLocalPeak(s, q)) continue;
-
-	    if (!m_cache->isOverThreshold(s, q, m_threshold)) continue;
+	    if (!m_fftServer->isOverThreshold(s, q, m_threshold)) continue;
 
 	    float freq = binfreq;
 	    bool steady = false;
 	    
-	    if (s < int(m_cache->getWidth()) - 1) {
+	    if (s < int(m_fftServer->getWidth()) - 1) {
 
 		freq = calculateFrequency(q, 
 					  windowSize,
 					  windowIncrement,
 					  sr, 
-					  m_cache->getPhaseAt(s, q),
-					  m_cache->getPhaseAt(s+1, q),
+					  m_fftServer->getPhaseAt(s, q),
+					  m_fftServer->getPhaseAt(s+1, q),
 					  steady);
 	    
 		if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq;
@@ -1698,45 +1342,39 @@
 
     bool rv = false;
 
-    if (m_mutex.tryLock()) {
-	if (m_cache && !m_cacheInvalid) {
+    if (m_fftServer) {
 
-	    int cw = m_cache->getWidth();
-	    int ch = m_cache->getHeight();
+        int cw = m_fftServer->getWidth();
+        int ch = m_fftServer->getHeight();
 
-	    min = 0.0;
-	    max = 0.0;
-	    phaseMin = 0.0;
-	    phaseMax = 0.0;
-	    bool have = false;
+        min = 0.0;
+        max = 0.0;
+        phaseMin = 0.0;
+        phaseMax = 0.0;
+        bool have = false;
 
-	    for (int q = q0i; q <= q1i; ++q) {
-		for (int s = s0i; s <= s1i; ++s) {
-		    if (s >= 0 && q >= 0 && s < cw && q < ch) {
+        for (int q = q0i; q <= q1i; ++q) {
+            for (int s = s0i; s <= s1i; ++s) {
+                if (s >= 0 && q >= 0 && s < cw && q < ch) {
+                    
+                    float value;
 
-                        if (!m_cache->haveSetColumnAt(s)) continue;
+                    value = m_fftServer->getPhaseAt(s, q);
+                    if (!have || value < phaseMin) { phaseMin = value; }
+                    if (!have || value > phaseMax) { phaseMax = value; }
 
-			float value;
-
-			value = m_cache->getPhaseAt(s, q);
-			if (!have || value < phaseMin) { phaseMin = value; }
-			if (!have || value > phaseMax) { phaseMax = value; }
-
-			value = m_cache->getMagnitudeAt(s, q);
-			if (!have || value < min) { min = value; }
-			if (!have || value > max) { max = value; }
-
-			have = true;
-		    }	
-		}
-	    }
-
-	    if (have) {
-		rv = true;
-	    }
-	}
-
-	m_mutex.unlock();
+                    value = m_fftServer->getMagnitudeAt(s, q);
+                    if (!have || value < min) { min = value; }
+                    if (!have || value > max) { max = value; }
+                    
+                    have = true;
+                }	
+            }
+        }
+        
+        if (have) {
+            rv = true;
+        }
     }
 
     return rv;
@@ -1776,20 +1414,9 @@
     // in the cache-fill thread above.
     m_dormancy[v] = false;
 
+    if (!m_fftServer) { // lock the mutex before checking this
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-//    std::cerr << "SpectrogramLayer::paint(): About to lock" << std::endl;
-#endif
-
-    m_mutex.lock();
-
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-//    std::cerr << "SpectrogramLayer::paint(): locked" << std::endl;
-#endif
-
-    if (m_cacheInvalid) { // lock the mutex before checking this
-	m_mutex.unlock();
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-	std::cerr << "SpectrogramLayer::paint(): Cache invalid, returning" << std::endl;
+	std::cerr << "SpectrogramLayer::paint(): No FFT server, returning" << std::endl;
 #endif
 	return;
     }
@@ -1836,7 +1463,6 @@
 		std::cerr << "SpectrogramLayer: pixmap cache good" << std::endl;
 #endif
 
-		m_mutex.unlock();
 		paint.drawPixmap(rect, cache.pixmap, rect);
 		return;
 
@@ -2024,25 +1650,13 @@
     
     bool logarithmic = (m_frequencyScale == LogFrequencyScale);
 
-    m_mutex.unlock();
-
     for (size_t q = minbin; q <= bins; ++q) {
         float f0 = (float(q) * sr) / m_fftSize;
         yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic);
     }
 
-    m_mutex.lock();
-
     for (int x = 0; x < w; ++x) {
 
-        if (x % 10 == 0) {
-            m_mutex.unlock();
-            m_mutex.lock();
-            if (m_cacheInvalid) {
-                break;
-            }
-        }
-
 	for (int y = 0; y < h; ++y) {
 	    ymag[y] = 0.0;
 	    ydiv[y] = 0.0;
@@ -2058,8 +1672,8 @@
 	int s0i = int(s0 + 0.001);
 	int s1i = int(s1);
 
-	if (s1i >= m_cache->getWidth()) {
-	    if (s0i >= m_cache->getWidth()) {
+	if (s1i >= m_fftServer->getWidth()) {
+	    if (s0i >= m_fftServer->getWidth()) {
 		continue;
 	    } else {
 		s1i = s0i;
@@ -2068,7 +1682,7 @@
 
         for (int s = s0i; s <= s1i; ++s) {
 
-            if (!m_cache->haveSetColumnAt(s)) continue;
+//            if (!m_fftServer->haveSetColumnAt(s)) continue;
 
             for (size_t q = minbin; q < bins; ++q) {
 
@@ -2077,25 +1691,25 @@
 
 		if (m_binDisplay == PeakBins ||
 		    m_binDisplay == PeakFrequencies) {
-		    if (!m_cache->isLocalPeak(s, q)) continue;
+		    if (!m_fftServer->isLocalPeak(s, q)) continue;
 		}
 		
-		if (!m_cache->isOverThreshold(s, q, m_threshold)) continue;
+		if (!m_fftServer->isOverThreshold(s, q, m_threshold)) continue;
 
 		float sprop = 1.0;
 		if (s == s0i) sprop *= (s + 1) - s0;
 		if (s == s1i) sprop *= s1 - s;
  
 		if (m_binDisplay == PeakFrequencies &&
-		    s < int(m_cache->getWidth()) - 1) {
+		    s < int(m_fftServer->getWidth()) - 1) {
 
 		    bool steady = false;
                     float f = calculateFrequency(q,
 						 m_windowSize,
 						 increment,
 						 sr,
-						 m_cache->getPhaseAt(s, q),
-						 m_cache->getPhaseAt(s+1, q),
+						 m_fftServer->getPhaseAt(s, q),
+						 m_fftServer->getPhaseAt(s+1, q),
 						 steady);
 
 		    y0 = y1 = v->getYForFrequency
@@ -2108,11 +1722,11 @@
                 float value;
                 
                 if (m_colourScale == PhaseColourScale) {
-                    value = m_cache->getPhaseAt(s, q);
+                    value = m_fftServer->getPhaseAt(s, q);
                 } else if (m_normalizeColumns) {
-                    value = m_cache->getNormalizedMagnitudeAt(s, q) * m_gain;
+                    value = m_fftServer->getNormalizedMagnitudeAt(s, q) * m_gain;
                 } else {
-                    value = m_cache->getMagnitudeAt(s, q) * m_gain;
+                    value = m_fftServer->getMagnitudeAt(s, q) * m_gain;
                 }
 
 		for (int y = y0i; y <= y1i; ++y) {
@@ -2145,8 +1759,6 @@
 	}
     }
 
-    m_mutex.unlock();
-
     paint.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h);
 
     if (recreateWholePixmapCache) {
@@ -2157,7 +1769,6 @@
     cachePainter.drawImage(x0, y0, m_drawBuffer, 0, 0, w, h);
     cachePainter.end();
     
-//    m_pixmapCacheInvalid = false;
     cache.startFrame = startFrame;
     cache.zoomLevel = zoomLevel;
 
@@ -2211,8 +1822,8 @@
 int
 SpectrogramLayer::getCompletion() const
 {
-    if (m_updateTimer == 0) return 100;
-    size_t completion = m_fillThread->getFillCompletion();
+    if (m_updateTimer == 0 || !m_fftServer) return 100;
+    size_t completion = m_fftServer->getFillCompletion();
 //    std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl;
     return completion;
 }
@@ -2495,7 +2106,7 @@
     int textHeight = paint.fontMetrics().height();
     int toff = -textHeight + paint.fontMetrics().ascent() + 2;
 
-    if (m_cache && !m_cacheInvalid && h > textHeight * 2 + 10) { //!!! lock?
+    if (m_fftServer && h > textHeight * 2 + 10) {
 
 	int ch = h - textHeight * 2 - 8;
 	paint.drawRect(4, textHeight + 4, cw - 1, ch + 1);
@@ -2588,7 +2199,7 @@
 
 	paint.drawLine(w - pkw - 1, 0, w - pkw - 1, h);
 
-	int sr = m_model->getSampleRate();//!!! lock?
+	int sr = m_model->getSampleRate();
 	float minf = getEffectiveMinFrequency();
 	float maxf = getEffectiveMaxFrequency();
 
--- a/layer/SpectrogramLayer.h	Mon Jun 26 16:12:11 2006 +0000
+++ b/layer/SpectrogramLayer.h	Tue Jun 27 19:18:42 2006 +0000
@@ -28,14 +28,12 @@
 #include <QImage>
 #include <QPixmap>
 
-#include <fftw3.h>
-
 class View;
 class QPainter;
 class QImage;
 class QPixmap;
 class QTimer;
-class FFTCacheBase;
+class FFTDataServer;
 
 /**
  * SpectrogramLayer represents waveform data (obtained from a
@@ -103,17 +101,15 @@
     size_t getZeroPadLevel() const;
 
     /**
-     * Set the gain multiplier for sample values in this view prior to
-     * FFT calculation.
-     *
+     * Set the gain multiplier for sample values in this view.
      * The default is 1.0.
      */
     void setGain(float gain);
     float getGain() const;
 
     /**
-     * Set the threshold for sample values to be shown in the FFT,
-     * in voltage units.
+     * Set the threshold for sample values to qualify for being shown
+     * in the FFT, in voltage units.
      *
      * The default is 0.0.
      */
@@ -210,8 +206,6 @@
     void fillTimerTimedOut();
 
 protected:
-    typedef float fftsample;
-
     const DenseTimeValueModel *m_model; // I do not own this
     
     int                 m_channel;
@@ -250,27 +244,9 @@
     };
 
     ColourMap m_colourMap;
-    FFTCacheBase *m_cache;
-    FFTCacheBase *m_writeCache;
-    bool m_cacheInvalid;
 
-    class CacheFillThread : public Thread
-    {
-    public:
-	CacheFillThread(SpectrogramLayer &layer) :
-	    m_layer(layer), m_fillExtent(0) { }
-
-	size_t getFillExtent() const { return m_fillExtent; }
-	size_t getFillCompletion() const { return m_fillCompletion; }
-	virtual void run();
-
-    protected:
-	SpectrogramLayer &m_layer;
-	size_t m_fillExtent;
-	size_t m_fillCompletion;
-    };
-
-    void fillCache();
+    FFTDataServer *m_fftServer;
+    void getFFTServer();
 
     struct PixmapCache
     {
@@ -284,12 +260,9 @@
     void invalidatePixmapCaches(size_t startFrame, size_t endFrame);
     mutable ViewPixmapCache m_pixmapCaches;
     mutable QImage m_drawBuffer;
-    
-    QWaitCondition m_condition;
-    mutable QMutex m_mutex;
 
-    CacheFillThread *m_fillThread;
     QTimer *m_updateTimer;
+
     mutable size_t m_candidateFillStartFrame;
     size_t m_lastFillExtent;
     bool m_exiting;
@@ -297,17 +270,6 @@
     void setColourmap();
     void rotateColourmap(int distance);
 
-    void fillCacheColumn(int column,
-			 fftsample *inputBuffer,
-			 fftwf_complex *outputBuffer,
-			 fftwf_plan plan,
-			 size_t windowSize,
-                         size_t fftSize,
-			 size_t windowIncrement,
-                         float *workbuffer,
-			 const Window<fftsample> &windower)
-	const;
-
     static float calculateFrequency(size_t bin,
 				    size_t windowSize,
 				    size_t windowIncrement,