# HG changeset patch # User Chris Cannam # Date 1151666770 0 # Node ID 991de8783cf57b280386b3ca7e958acf1ebdea7c # Parent 7a23edd831cb706006e47553a639abf70e5d4a6b * Add fuzzy-adapter class to pick out subset data from FFT data server, instead of having separate methods in data server class. Update spectrogram to use it. * Give spectrogram layer one fft adapter per view, in case the views need different zero-padding levels. * Reduce ridiculous memory consumption of MatrixFile for tall matrices. Still very much work in progress here. diff -r 7a23edd831cb -r 991de8783cf5 layer/SpectrogramLayer.cpp --- a/layer/SpectrogramLayer.cpp Thu Jun 29 16:16:49 2006 +0000 +++ b/layer/SpectrogramLayer.cpp Fri Jun 30 11:26:10 2006 +0000 @@ -55,7 +55,6 @@ m_frequencyScale(LinearFrequencyScale), m_binDisplay(AllBins), m_normalizeColumns(false), - m_fftServer(0), m_updateTimer(0), m_candidateFillStartFrame(0), m_lastFillExtent(0), @@ -87,10 +86,7 @@ delete m_updateTimer; m_updateTimer = 0; - if (m_fftServer) { - FFTDataServer::releaseInstance(m_fftServer); - m_fftServer = 0; - } + invalidateFFTAdapters(); } void @@ -101,7 +97,7 @@ if (model == m_model) return; m_model = model; - getFFTServer(); + invalidateFFTAdapters(); if (!m_model || !m_model->isOK()) return; @@ -118,17 +114,21 @@ emit modelReplaced(); } +/*!!! +void +SpectrogramLayer::invalidateFFTAdapters() +{ +// if (m_fftServer) { +// FFTDataServer::releaseInstance(m_fftServer); +// m_fftServer = 0; +// } -void -SpectrogramLayer::getFFTServer() -{ - if (m_fftServer) { - FFTDataServer::releaseInstance(m_fftServer); - m_fftServer = 0; - } + delete m_fftServer; + m_fftServer = 0; if (m_model) { - m_fftServer = FFTDataServer::getFuzzyInstance(m_model, +// m_fftServer = FFTDataServer::getFuzzyInstance(m_model, + m_fftServer = new FFTFuzzyAdapter(m_model, m_channel, m_windowType, m_windowSize, @@ -145,7 +145,7 @@ m_updateTimer->start(200); } } - +*/ Layer::PropertyList SpectrogramLayer::getProperties() const { @@ -573,7 +573,7 @@ invalidatePixmapCaches(); m_channel = ch; - getFFTServer(); + invalidateFFTAdapters(); emit layerParametersChanged(); } @@ -594,7 +594,7 @@ m_windowSize = ws; m_fftSize = ws * (m_zeroPadLevel + 1); - getFFTServer(); + invalidateFFTAdapters(); emit layerParametersChanged(); } @@ -614,7 +614,7 @@ m_windowHopLevel = v; - getFFTServer(); + invalidateFFTAdapters(); emit layerParametersChanged(); @@ -637,7 +637,7 @@ m_zeroPadLevel = v; m_fftSize = m_windowSize * (v + 1); - getFFTServer(); + invalidateFFTAdapters(); emit layerParametersChanged(); } @@ -657,7 +657,7 @@ m_windowType = w; - getFFTServer(); + invalidateFFTAdapters(); emit layerParametersChanged(); } @@ -859,6 +859,11 @@ invalidatePixmapCaches(); m_pixmapCaches.erase(v); + + if (m_fftAdapters.find(v) != m_fftAdapters.end()) { + delete m_fftAdapters[v]; + m_fftAdapters.erase(v); + } } else { @@ -882,6 +887,7 @@ void SpectrogramLayer::fillTimerTimedOut() { +/*!!! if (m_fftServer && m_model) { size_t fillExtent = m_fftServer->getFillExtent(); @@ -917,6 +923,7 @@ m_lastFillExtent = fillExtent; } } +*/ } void @@ -998,8 +1005,6 @@ void SpectrogramLayer::rotateColourmap(int distance) { - if (!m_fftServer) return; - QColor newPixels[256]; newPixels[NO_VALUE] = m_colourMap.getColour(NO_VALUE); @@ -1169,6 +1174,8 @@ bool logarithmic = (m_frequencyScale == LogFrequencyScale); + //!!! wrong for smoothing -- wrong fft size for fft adapter + q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); @@ -1242,6 +1249,8 @@ int sr = m_model->getSampleRate(); + //!!! wrong for smoothing -- wrong fft size for fft adapter + for (int q = q0i; q <= q1i; ++q) { int binfreq = (sr * q) / m_fftSize; if (q == q0i) freqMin = binfreq; @@ -1256,7 +1265,8 @@ float &adjFreqMin, float &adjFreqMax) const { - if (!m_fftServer) return false; + FFTFuzzyAdapter *fft = getFFTAdapter(v); + if (!fft) return false; float s0 = 0, s1 = 0; if (!getXBinRange(v, x, s0, s1)) return false; @@ -1288,21 +1298,21 @@ if (q == q0i) freqMin = binfreq; if (q == q1i) freqMax = binfreq; - if (peaksOnly && !isFFTLocalPeak(s, q)) continue; + if (peaksOnly && !fft->isLocalPeak(s, q)) continue; - if (!isFFTOverThreshold(s, q, m_threshold)) continue; + if (!fft->isOverThreshold(s, q, m_threshold)) continue; float freq = binfreq; bool steady = false; - if (s < int(getFFTWidth()) - 1) { + if (s < int(fft->getWidth()) - 1) { freq = calculateFrequency(q, windowSize, windowIncrement, sr, - getFFTPhaseAt(s, q), - getFFTPhaseAt(s+1, q), + fft->getPhaseAt(s, q), + fft->getPhaseAt(s+1, q), steady); if (!haveAdj || freq < adjFreqMin) adjFreqMin = freq; @@ -1339,10 +1349,12 @@ bool rv = false; - if (m_fftServer) { + FFTFuzzyAdapter *fft = getFFTAdapter(v); - int cw = getFFTWidth(); - int ch = getFFTHeight(); + if (fft) { + + int cw = fft->getWidth(); + int ch = fft->getHeight(); min = 0.0; max = 0.0; @@ -1356,11 +1368,11 @@ float value; - value = getFFTPhaseAt(s, q); + value = fft->getPhaseAt(s, q); if (!have || value < phaseMin) { phaseMin = value; } if (!have || value > phaseMax) { phaseMax = value; } - value = getFFTMagnitudeAt(s, q); + value = fft->getMagnitudeAt(s, q); if (!have || value < min) { min = value; } if (!have || value > max) { max = value; } @@ -1377,6 +1389,88 @@ return rv; } +size_t +SpectrogramLayer::getZeroPadLevel(const View *v) const +{ + //!!! tidy all this stuff + + if (m_binDisplay != AllBins) return 0; + if (m_frequencyScale == LogFrequencyScale) return 3; + + int sr = m_model->getSampleRate(); + + size_t bins = m_fftSize / 2; + if (m_maxFrequency > 0) { + bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); + if (bins > m_fftSize / 2) bins = m_fftSize / 2; + } + + size_t minbin = 1; + if (m_minFrequency > 0) { + minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); + if (minbin < 1) minbin = 1; + if (minbin >= bins) minbin = bins - 1; + } + + if (v->height() / 1.5 > (bins - minbin) / (m_zeroPadLevel + 1)) { + return 3; + } else { + return 0; + } +} + +size_t +SpectrogramLayer::getFFTSize(const View *v) const +{ + return m_fftSize * (getZeroPadLevel(v) + 1); +} + +FFTFuzzyAdapter * +SpectrogramLayer::getFFTAdapter(const View *v) const +{ + if (!m_model) return 0; + + size_t fftSize = getFFTSize(v); + + if (m_fftAdapters.find(v) != m_fftAdapters.end()) { + if (m_fftAdapters[v]->getHeight() != fftSize / 2) { + delete m_fftAdapters[v]; + m_fftAdapters.erase(v); + } + } + + if (m_fftAdapters.find(v) == m_fftAdapters.end()) { + m_fftAdapters[v] = new FFTFuzzyAdapter(m_model, + m_channel, + m_windowType, + m_windowSize, + getWindowIncrement(), + getFFTSize(v), + true, + m_candidateFillStartFrame); + m_lastFillExtent = 0; + + delete m_updateTimer; + m_updateTimer = new QTimer((SpectrogramLayer *)this); + connect(m_updateTimer, SIGNAL(timeout()), + this, SLOT(fillTimerTimedOut())); + m_updateTimer->start(200); + } + + return m_fftAdapters[v]; +} + +void +SpectrogramLayer::invalidateFFTAdapters() +{ + for (ViewFFTMap::iterator i = m_fftAdapters.begin(); + i != m_fftAdapters.end(); ++i) { + delete i->second; + } + + m_fftAdapters.clear(); +} + void SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const { @@ -1411,10 +1505,10 @@ // 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(): No FFT server, returning" << std::endl; -#endif + size_t fftSize = getFFTSize(v); + FFTFuzzyAdapter *fft = getFFTAdapter(v); + if (!fft) { + std::cerr << "ERROR: SpectrogramLayer::paint(): No FFT adapter, returning" << std::endl; return; } @@ -1623,35 +1717,21 @@ int sr = m_model->getSampleRate(); - size_t bins = m_fftSize / 2; + size_t bins = fftSize / 2; if (m_maxFrequency > 0) { - bins = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); - if (bins > m_fftSize / 2) bins = m_fftSize / 2; + bins = int((double(m_maxFrequency) * fftSize) / sr + 0.1); + if (bins > fftSize / 2) bins = fftSize / 2; } size_t minbin = 1; if (m_minFrequency > 0) { - minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); + minbin = int((double(m_minFrequency) * fftSize) / sr + 0.1); if (minbin < 1) minbin = 1; if (minbin >= bins) minbin = bins - 1; } - //!!! quite wrong and won't work for layers that may be in more than one view - if (v->height() / 1.5 > (bins - minbin) / (m_zeroPadLevel + 1)) { - if (m_zeroPadLevel != 3) { - std::cerr << v->height()/1.5 << " > " << ((bins - minbin) / (m_zeroPadLevel + 1)) << ": switching to smoothed display" << std::endl; - ((SpectrogramLayer *)this)->setZeroPadLevel(3); - return; - } - } else { - if (m_zeroPadLevel != 0) { - ((SpectrogramLayer *)this)->setZeroPadLevel(0); - return; - } - } - - float minFreq = (float(minbin) * sr) / m_fftSize; - float maxFreq = (float(bins) * sr) / m_fftSize; + float minFreq = (float(minbin) * sr) / fftSize; + float maxFreq = (float(bins) * sr) / fftSize; float ymag[h]; float ydiv[h]; @@ -1662,7 +1742,7 @@ bool logarithmic = (m_frequencyScale == LogFrequencyScale); for (size_t q = minbin; q <= bins; ++q) { - float f0 = (float(q) * sr) / m_fftSize; + float f0 = (float(q) * sr) / fftSize; yval[q] = v->getYForFrequency(f0, minFreq, maxFreq, logarithmic); } @@ -1683,8 +1763,8 @@ int s0i = int(s0 + 0.001); int s1i = int(s1); - if (s1i >= getFFTWidth()) { - if (s0i >= getFFTWidth()) { + if (s1i >= fft->getWidth()) { + if (s0i >= fft->getWidth()) { continue; } else { s1i = s0i; @@ -1693,7 +1773,7 @@ for (int s = s0i; s <= s1i; ++s) { - if (!isFFTColumnReady(s)) continue; + if (!fft->isColumnReady(s)) continue; for (size_t q = minbin; q < bins; ++q) { @@ -1702,25 +1782,28 @@ if (m_binDisplay == PeakBins || m_binDisplay == PeakFrequencies) { - if (!isFFTLocalPeak(s, q)) continue; + if (!fft->isLocalPeak(s, q)) continue; } - - if (!isFFTOverThreshold(s, q, m_threshold)) continue; + + if (m_threshold != 0.f && + !fft->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(getFFTWidth()) - 1) { + s < int(fft->getWidth()) - 1) { bool steady = false; float f = calculateFrequency(q, m_windowSize, increment, sr, - getFFTPhaseAt(s, q), - getFFTPhaseAt(s+1, q), + fft->getPhaseAt(s, q), + fft->getPhaseAt(s+1, q), steady); y0 = y1 = v->getYForFrequency @@ -1733,11 +1816,11 @@ float value; if (m_colourScale == PhaseColourScale) { - value = getFFTPhaseAt(s, q); + value = fft->getPhaseAt(s, q); } else if (m_normalizeColumns) { - value = getFFTNormalizedMagnitudeAt(s, q) * m_gain; + value = fft->getNormalizedMagnitudeAt(s, q) * m_gain; } else { - value = getFFTMagnitudeAt(s, q) * m_gain; + value = fft->getMagnitudeAt(s, q) * m_gain; } for (int y = y0i; y <= y1i; ++y) { @@ -1833,10 +1916,13 @@ int SpectrogramLayer::getCompletion() const { +/*!!! if (m_updateTimer == 0 || !m_fftServer) return 100; size_t completion = m_fftServer->getFillCompletion(); // std::cerr << "SpectrogramLayer::getCompletion: completion = " << completion << std::endl; return completion; +*/ + return 100; } bool @@ -2117,7 +2203,7 @@ int textHeight = paint.fontMetrics().height(); int toff = -textHeight + paint.fontMetrics().ascent() + 2; - if (m_fftServer && h > textHeight * 2 + 10) { + if (h > textHeight * 2 + 10) { int ch = h - textHeight * 2 - 8; paint.drawRect(4, textHeight + 4, cw - 1, ch + 1); diff -r 7a23edd831cb -r 991de8783cf5 layer/SpectrogramLayer.h --- a/layer/SpectrogramLayer.h Thu Jun 29 16:16:49 2006 +0000 +++ b/layer/SpectrogramLayer.h Fri Jun 30 11:26:10 2006 +0000 @@ -22,7 +22,8 @@ #include "base/Thread.h" #include "model/PowerOfSqrtTwoZoomConstraint.h" #include "model/DenseTimeValueModel.h" -#include "fileio/FFTDataServer.h" + +#include "fileio/FFTFuzzyAdapter.h" #include #include @@ -34,6 +35,8 @@ class QImage; class QPixmap; class QTimer; +class FFTFuzzyAdapter; + /** * SpectrogramLayer represents waveform data (obtained from a @@ -245,9 +248,6 @@ ColourMap m_colourMap; - FFTDataServer *m_fftServer; - void getFFTServer(); - struct PixmapCache { QPixmap pixmap; @@ -261,10 +261,10 @@ mutable ViewPixmapCache m_pixmapCaches; mutable QImage m_drawBuffer; - QTimer *m_updateTimer; + mutable QTimer *m_updateTimer; mutable size_t m_candidateFillStartFrame; - size_t m_lastFillExtent; + mutable size_t m_lastFillExtent; bool m_exiting; void setColourmap(); @@ -309,39 +309,12 @@ else return m_windowSize / (1 << (m_windowHopLevel - 1)); } - size_t getFFTWidth() const { - return m_fftServer->getWidth(getWindowIncrement(), m_fftSize); - } - size_t getFFTHeight() const { - return m_fftServer->getHeight(getWindowIncrement(), m_fftSize); - } - float getFFTMagnitudeAt(size_t x, size_t y) const { - return m_fftServer->getMagnitudeAt(getWindowIncrement(), m_fftSize, - x, y); - } - float getFFTNormalizedMagnitudeAt(size_t x, size_t y) const { - return m_fftServer->getNormalizedMagnitudeAt(getWindowIncrement(), m_fftSize, - x, y); - } - float getFFTPhaseAt(size_t x, size_t y) const { - return m_fftServer->getPhaseAt(getWindowIncrement(), m_fftSize, - x, y); - } - void getFFTValuesAt(size_t x, size_t y, float &real, float &imag) const { - m_fftServer->getValuesAt(getWindowIncrement(), m_fftSize, - x, y, real, imag); - } - bool isFFTLocalPeak(size_t x, size_t y) const { - return m_fftServer->isLocalPeak(getWindowIncrement(), m_fftSize, - x, y); - } - bool isFFTOverThreshold(size_t x, size_t y, float threshold) const { - return m_fftServer->isOverThreshold(getWindowIncrement(), m_fftSize, - x, y, threshold); - } - bool isFFTColumnReady(size_t x) const { - return m_fftServer->isColumnReady(getWindowIncrement(), m_fftSize, x); - } + size_t getZeroPadLevel(const View *v) const; + size_t getFFTSize(const View *v) const; + FFTFuzzyAdapter *getFFTAdapter(const View *v) const; + void invalidateFFTAdapters(); + typedef std::map ViewFFTMap; + mutable ViewFFTMap m_fftAdapters; }; #endif