Mercurial > hg > svcore
changeset 201:d892237cf790
* Remove some obsolete files
author | Chris Cannam |
---|---|
date | Wed, 15 Nov 2006 20:00:48 +0000 |
parents | 2f2d282d45d0 |
children | 91fdc752e540 |
files | data/fileio/FFTDataServer.cpp data/fileio/FFTDataServer.h data/fileio/FFTFileCache.cpp data/fileio/FFTFileCache.h |
diffstat | 4 files changed, 0 insertions(+), 1365 deletions(-) [+] |
line wrap: on
line diff
--- a/data/fileio/FFTDataServer.cpp Mon Nov 13 14:48:57 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,751 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FFTDataServer.h" - -#include "FFTFileCache.h" - -#include "model/DenseTimeValueModel.h" - -#include "base/System.h" - -//#define DEBUG_FFT_SERVER 1 -//#define DEBUG_FFT_SERVER_FILL 1 - -#ifdef DEBUG_FFT_SERVER_FILL -#define DEBUG_FFT_SERVER -#endif - -FFTDataServer::ServerMap FFTDataServer::m_servers; -QMutex FFTDataServer::m_serverMapMutex; - -FFTDataServer * -FFTDataServer::getInstance(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn) -{ - QString n = generateFileBasename(model, - channel, - windowType, - windowSize, - windowIncrement, - fftSize, - polar); - - FFTDataServer *server = 0; - - QMutexLocker locker(&m_serverMapMutex); - - if ((server = findServer(n))) { - return server; - } - - QString npn = generateFileBasename(model, - channel, - windowType, - windowSize, - windowIncrement, - fftSize, - !polar); - - if ((server = findServer(npn))) { - return server; - } - - m_servers[n] = ServerCountPair - (new FFTDataServer(n, - model, - channel, - windowType, - windowSize, - windowIncrement, - fftSize, - polar, - fillFromColumn), - 1); - - return m_servers[n].first; -} - -FFTDataServer * -FFTDataServer::getFuzzyInstance(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn) -{ - // Fuzzy matching: - // - // -- if we're asked for polar and have non-polar, use it (and - // vice versa). This one is vital, and we do it for non-fuzzy as - // well (above). - // - // -- if we're asked for an instance with a given fft size and we - // have one already with a multiple of that fft size but the same - // window size and type (and model), we can draw the results from - // it (e.g. the 1st, 2nd, 3rd etc bins of a 512-sample FFT are the - // same as the the 1st, 5th, 9th etc of a 2048-sample FFT of the - // same window plus zero padding). - // - // -- if we're asked for an instance with a given window type and - // size and fft size and we have one already the same but with a - // smaller increment, we can draw the results from it (provided - // our increment is a multiple of its) - // - // The FFTFuzzyAdapter knows how to interpret these things. In - // both cases we require that the larger one is a power-of-two - // multiple of the smaller (e.g. even though in principle you can - // draw the results at increment 256 from those at increment 768 - // or 1536, the fuzzy adapter doesn't support this). - - { - QMutexLocker locker(&m_serverMapMutex); - - ServerMap::iterator best = m_servers.end(); - int bestdist = -1; - - for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { - - FFTDataServer *server = i->second.first; - - if (server->getModel() == model && - (server->getChannel() == channel || model->getChannelCount() == 1) && - server->getWindowType() == windowType && - server->getWindowSize() == windowSize && - server->getWindowIncrement() <= windowIncrement && - server->getFFTSize() >= fftSize) { - - if ((windowIncrement % server->getWindowIncrement()) != 0) continue; - int ratio = windowIncrement / server->getWindowIncrement(); - bool poweroftwo = true; - while (ratio > 1) { - if (ratio & 0x1) { - poweroftwo = false; - break; - } - ratio >>= 1; - } - if (!poweroftwo) continue; - - if ((server->getFFTSize() % fftSize) != 0) continue; - ratio = server->getFFTSize() / fftSize; - while (ratio > 1) { - if (ratio & 0x1) { - poweroftwo = false; - break; - } - ratio >>= 1; - } - if (!poweroftwo) continue; - - int distance = 0; - - if (server->getPolar() != polar) distance += 1; - - distance += ((windowIncrement / server->getWindowIncrement()) - 1) * 15; - distance += ((server->getFFTSize() / fftSize) - 1) * 10; - - if (server->getFillCompletion() < 50) distance += 100; - -#ifdef DEBUG_FFT_SERVER - std::cerr << "Distance " << distance << ", best is " << bestdist << std::endl; -#endif - - if (bestdist == -1 || distance < bestdist) { - bestdist = distance; - best = i; - } - } - } - - if (bestdist >= 0) { - ++best->second.second; - return best->second.first; - } - } - - // Nothing found, make a new one - - return getInstance(model, - channel, - windowType, - windowSize, - windowIncrement, - fftSize, - polar, - fillFromColumn); -} - -FFTDataServer * -FFTDataServer::findServer(QString n) -{ - if (m_servers.find(n) != m_servers.end()) { - ++m_servers[n].second; - return m_servers[n].first; - } - - return 0; -} - -void -FFTDataServer::releaseInstance(FFTDataServer *server) -{ -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer::releaseInstance(" << server << ")" << std::endl; -#endif - - QMutexLocker locker(&m_serverMapMutex); - - //!!! not a good strategy. Want something like: - - // -- if ref count > 0, decrement and return - // -- if the instance hasn't been used at all, delete it immediately - // -- if fewer than N instances (N = e.g. 3) remain with zero refcounts, - // leave them hanging around - // -- if N instances with zero refcounts remain, delete the one that - // was last released first - // -- if we run out of disk space when allocating an instance, go back - // and delete the spare N instances before trying again - // -- have an additional method to indicate that a model has been - // destroyed, so that we can delete all of its fft server instances - - // also: - // - - for (ServerMap::iterator i = m_servers.begin(); i != m_servers.end(); ++i) { - if (i->second.first == server) { - if (i->second.second == 0) { - std::cerr << "ERROR: FFTDataServer::releaseInstance(" - << server << "): instance not allocated" << std::endl; - } else if (--i->second.second == 0) { - if (server->m_lastUsedCache == -1) { // never used - delete server; - m_servers.erase(i); - } else { - server->suspend(); - purgeLimbo(); - } - } - return; - } - } - - std::cerr << "ERROR: FFTDataServer::releaseInstance(" << server << "): " - << "instance not found" << std::endl; -} - -void -FFTDataServer::purgeLimbo(int maxSize) -{ - ServerMap::iterator i = m_servers.end(); - - int count = 0; - - while (i != m_servers.begin()) { - --i; - if (i->second.second == 0) { - if (++count > maxSize) { - delete i->second.first; - m_servers.erase(i); - return; - } - } - } -} - -FFTDataServer::FFTDataServer(QString fileBaseName, - const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn) : - m_fileBaseName(fileBaseName), - m_model(model), - m_channel(channel), - m_windower(windowType, windowSize), - m_windowSize(windowSize), - m_windowIncrement(windowIncrement), - m_fftSize(fftSize), - m_polar(polar), - m_lastUsedCache(-1), - m_fftInput(0), - m_exiting(false), - m_fillThread(0) -{ - size_t start = m_model->getStartFrame(); - size_t end = m_model->getEndFrame(); - - m_width = (end - start) / m_windowIncrement + 1; - m_height = m_fftSize / 2; - - size_t maxCacheSize = 20 * 1024 * 1024; - size_t columnSize = m_height * sizeof(fftsample) * 2 + sizeof(fftsample); - if (m_width * columnSize < maxCacheSize * 2) m_cacheWidth = m_width; - else m_cacheWidth = maxCacheSize / columnSize; - - int bits = 0; - while (m_cacheWidth) { m_cacheWidth >>= 1; ++bits; } - m_cacheWidth = 2; - while (bits) { m_cacheWidth <<= 1; --bits; } - -#ifdef DEBUG_FFT_SERVER - std::cerr << "Width " << m_width << ", cache width " << m_cacheWidth << " (size " << m_cacheWidth * columnSize << ")" << std::endl; -#endif - - for (size_t i = 0; i <= m_width / m_cacheWidth; ++i) { - m_caches.push_back(0); - } - - m_fftInput = (fftsample *) - fftwf_malloc(fftSize * sizeof(fftsample)); - - m_fftOutput = (fftwf_complex *) - fftwf_malloc(fftSize * sizeof(fftwf_complex)); - - m_workbuffer = (float *) - fftwf_malloc(fftSize * sizeof(float)); - - m_fftPlan = fftwf_plan_dft_r2c_1d(m_fftSize, - m_fftInput, - m_fftOutput, - FFTW_ESTIMATE); - - if (!m_fftPlan) { - std::cerr << "ERROR: fftwf_plan_dft_r2c_1d(" << m_windowSize << ") failed!" << std::endl; - throw(0); - } - - m_fillThread = new FillThread(*this, fillFromColumn); - - //!!! respond appropriately when thread exits (deleteProcessingData etc) -} - -FFTDataServer::~FFTDataServer() -{ -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer(" << this << ")::~FFTDataServer()" << std::endl; -#endif - - m_exiting = true; - m_condition.wakeAll(); - if (m_fillThread) { - m_fillThread->wait(); - delete m_fillThread; - } - - QMutexLocker locker(&m_writeMutex); - - for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { - delete *i; - } - - deleteProcessingData(); -} - -void -FFTDataServer::deleteProcessingData() -{ - if (m_fftInput) { - fftwf_destroy_plan(m_fftPlan); - fftwf_free(m_fftInput); - fftwf_free(m_fftOutput); - fftwf_free(m_workbuffer); - } - m_fftInput = 0; -} - -void -FFTDataServer::suspend() -{ -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer(" << this << "): suspend" << std::endl; -#endif - QMutexLocker locker(&m_writeMutex); - m_suspended = true; - for (CacheVector::iterator i = m_caches.begin(); i != m_caches.end(); ++i) { - if (*i) (*i)->suspend(); - } -} - -void -FFTDataServer::resume() -{ - m_suspended = false; - m_condition.wakeAll(); -} - -FFTCache * -FFTDataServer::getCacheAux(size_t c) -{ - QMutexLocker locker(&m_writeMutex); - - if (m_lastUsedCache == -1) { - m_fillThread->start(); - } - - if (int(c) != m_lastUsedCache) { - -// std::cerr << "switch from " << m_lastUsedCache << " to " << c << std::endl; - - for (IntQueue::iterator i = m_dormantCaches.begin(); - i != m_dormantCaches.end(); ++i) { - if (*i == c) { - m_dormantCaches.erase(i); - break; - } - } - - if (m_lastUsedCache >= 0) { - bool inDormant = false; - for (size_t i = 0; i < m_dormantCaches.size(); ++i) { - if (m_dormantCaches[i] == m_lastUsedCache) { - inDormant = true; - break; - } - } - if (!inDormant) { - m_dormantCaches.push_back(m_lastUsedCache); - } - while (m_dormantCaches.size() > 4) { - int dc = m_dormantCaches.front(); - m_dormantCaches.pop_front(); - m_caches[dc]->suspend(); - } - } - } - - if (m_caches[c]) { - m_lastUsedCache = c; - return m_caches[c]; - } - - QString name = QString("%1-%2").arg(m_fileBaseName).arg(c); - - FFTCache *cache = new FFTFileCache(name, MatrixFile::ReadWrite, - m_polar ? FFTFileCache::Polar : - FFTFileCache::Rectangular); - - size_t width = m_cacheWidth; - if (c * m_cacheWidth + width > m_width) { - width = m_width - c * m_cacheWidth; - } - - cache->resize(width, m_height); - cache->reset(); - - m_caches[c] = cache; - m_lastUsedCache = c; - - return cache; -} - -float -FFTDataServer::getMagnitudeAt(size_t x, size_t y) -{ - size_t col; - FFTCache *cache = getCache(x, col); - - if (!cache->haveSetColumnAt(col)) { - fillColumn(x); - } - return cache->getMagnitudeAt(col, y); -} - -float -FFTDataServer::getNormalizedMagnitudeAt(size_t x, size_t y) -{ - size_t col; - FFTCache *cache = getCache(x, col); - - if (!cache->haveSetColumnAt(col)) { - fillColumn(x); - } - return cache->getNormalizedMagnitudeAt(col, y); -} - -float -FFTDataServer::getMaximumMagnitudeAt(size_t x) -{ - size_t col; - FFTCache *cache = getCache(x, col); - - if (!cache->haveSetColumnAt(col)) { - fillColumn(x); - } - return cache->getMaximumMagnitudeAt(col); -} - -float -FFTDataServer::getPhaseAt(size_t x, size_t y) -{ - size_t col; - FFTCache *cache = getCache(x, col); - - if (!cache->haveSetColumnAt(col)) { - fillColumn(x); - } - return cache->getPhaseAt(col, y); -} - -void -FFTDataServer::getValuesAt(size_t x, size_t y, float &real, float &imaginary) -{ - size_t col; - FFTCache *cache = getCache(x, col); - - if (!cache->haveSetColumnAt(col)) { -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer::getValuesAt(" << x << ", " << y << "): filling" << std::endl; -#endif - fillColumn(x); - } - float magnitude = cache->getMagnitudeAt(col, y); - float phase = cache->getPhaseAt(col, y); - real = magnitude * cosf(phase); - imaginary = magnitude * sinf(phase); -} - -bool -FFTDataServer::isColumnReady(size_t x) -{ - if (!haveCache(x)) { - if (m_lastUsedCache == -1) { - m_fillThread->start(); - } - return false; - } - - size_t col; - FFTCache *cache = getCache(x, col); - - return cache->haveSetColumnAt(col); -} - -void -FFTDataServer::fillColumn(size_t x) -{ - size_t col; -#ifdef DEBUG_FFT_SERVER_FILL - std::cout << "FFTDataServer::fillColumn(" << x << ")" << std::endl; -#endif - FFTCache *cache = getCache(x, col); - - QMutexLocker locker(&m_writeMutex); - - if (cache->haveSetColumnAt(col)) return; - - int startFrame = m_windowIncrement * x; - int endFrame = startFrame + m_windowSize; - - startFrame -= int(m_windowSize - m_windowIncrement) / 2; - endFrame -= int(m_windowSize - m_windowIncrement) / 2; - size_t pfx = 0; - - size_t off = (m_fftSize - m_windowSize) / 2; - - for (size_t i = 0; i < off; ++i) { - m_fftInput[i] = 0.0; - m_fftInput[m_fftSize - i - 1] = 0.0; - } - - if (startFrame < 0) { - pfx = size_t(-startFrame); - for (size_t i = 0; i < pfx; ++i) { - m_fftInput[off + i] = 0.0; - } - } - - size_t got = m_model->getValues(m_channel, startFrame + pfx, - endFrame, m_fftInput + off + pfx); - - while (got + pfx < m_windowSize) { - m_fftInput[off + got + pfx] = 0.0; - ++got; - } - - if (m_channel == -1) { - int channels = m_model->getChannelCount(); - if (channels > 1) { - for (size_t i = 0; i < m_windowSize; ++i) { - m_fftInput[off + i] /= channels; - } - } - } - - m_windower.cut(m_fftInput + off); - - for (size_t i = 0; i < m_fftSize/2; ++i) { - fftsample temp = m_fftInput[i]; - m_fftInput[i] = m_fftInput[i + m_fftSize/2]; - m_fftInput[i + m_fftSize/2] = temp; - } - - fftwf_execute(m_fftPlan); - - fftsample factor = 0.0; - - for (size_t i = 0; i < m_fftSize/2; ++i) { - - fftsample mag = sqrtf(m_fftOutput[i][0] * m_fftOutput[i][0] + - m_fftOutput[i][1] * m_fftOutput[i][1]); - mag /= m_windowSize / 2; - - if (mag > factor) factor = mag; - - fftsample phase = atan2f(m_fftOutput[i][1], m_fftOutput[i][0]); - phase = princargf(phase); - - m_workbuffer[i] = mag; - m_workbuffer[i + m_fftSize/2] = phase; - } - - cache->setColumnAt(col, - m_workbuffer, - m_workbuffer + m_fftSize/2, - factor); -} - -size_t -FFTDataServer::getFillCompletion() const -{ - if (m_fillThread) return m_fillThread->getCompletion(); - else return 100; -} - -size_t -FFTDataServer::getFillExtent() const -{ - if (m_fillThread) return m_fillThread->getExtent(); - else return m_model->getEndFrame(); -} - -QString -FFTDataServer::generateFileBasename() const -{ - return generateFileBasename(m_model, m_channel, m_windower.getType(), - m_windowSize, m_windowIncrement, m_fftSize, - m_polar); -} - -QString -FFTDataServer::generateFileBasename(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar) -{ - char buffer[200]; - - sprintf(buffer, "%u-%u-%u-%u-%u-%u%s", - (unsigned int)XmlExportable::getObjectExportId(model), - (unsigned int)(channel + 1), - (unsigned int)windowType, - (unsigned int)windowSize, - (unsigned int)windowIncrement, - (unsigned int)fftSize, - polar ? "-p" : "-r"); - - return buffer; -} - -void -FFTDataServer::FillThread::run() -{ - m_extent = 0; - m_completion = 0; - - size_t start = m_server.m_model->getStartFrame(); - size_t end = m_server.m_model->getEndFrame(); - size_t remainingEnd = end; - - int counter = 0; - int updateAt = (end / m_server.m_windowIncrement) / 20; - if (updateAt < 100) updateAt = 100; - - if (m_fillFrom > start) { - - for (size_t f = m_fillFrom; f < end; f += m_server.m_windowIncrement) { - - m_server.fillColumn(int((f - start) / m_server.m_windowIncrement)); - - if (m_server.m_exiting) return; - - while (m_server.m_suspended) { -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer(" << this << "): suspended, waiting..." << std::endl; -#endif - m_server.m_writeMutex.lock(); - m_server.m_condition.wait(&m_server.m_writeMutex, 10000); - m_server.m_writeMutex.unlock(); - if (m_server.m_exiting) return; - } - - if (++counter == updateAt) { - m_extent = f; - m_completion = size_t(100 * fabsf(float(f - m_fillFrom) / - float(end - start))); - counter = 0; - } - } - - remainingEnd = m_fillFrom; - if (remainingEnd > start) --remainingEnd; - else remainingEnd = start; - } - - size_t baseCompletion = m_completion; - - for (size_t f = start; f < remainingEnd; f += m_server.m_windowIncrement) { - - m_server.fillColumn(int((f - start) / m_server.m_windowIncrement)); - - if (m_server.m_exiting) return; - - while (m_server.m_suspended) { -#ifdef DEBUG_FFT_SERVER - std::cerr << "FFTDataServer(" << this << "): suspended, waiting..." << std::endl; -#endif - m_server.m_writeMutex.lock(); - m_server.m_condition.wait(&m_server.m_writeMutex, 10000); - m_server.m_writeMutex.unlock(); - if (m_server.m_exiting) return; - } - - if (++counter == updateAt) { - m_extent = f; - m_completion = baseCompletion + - size_t(100 * fabsf(float(f - start) / - float(end - start))); - counter = 0; - } - } - - m_completion = 100; - m_extent = end; -} -
--- a/data/fileio/FFTDataServer.h Mon Nov 13 14:48:57 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FFT_DATA_SERVER_H_ -#define _FFT_DATA_SERVER_H_ - -#include "base/Window.h" -#include "base/Thread.h" - -#include <fftw3.h> - -#include <QMutex> -#include <QWaitCondition> -#include <QString> - -#include <vector> -#include <deque> - -class DenseTimeValueModel; -class FFTCache; - -class FFTDataServer -{ -public: - static FFTDataServer *getInstance(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn = 0); - - static FFTDataServer *getFuzzyInstance(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn = 0); - - static void releaseInstance(FFTDataServer *); - - const DenseTimeValueModel *getModel() const { return m_model; } - int getChannel() const { return m_channel; } - WindowType getWindowType() const { return m_windower.getType(); } - size_t getWindowSize() const { return m_windowSize; } - size_t getWindowIncrement() const { return m_windowIncrement; } - size_t getFFTSize() const { return m_fftSize; } - bool getPolar() const { return m_polar; } - - size_t getWidth() const { return m_width; } - size_t getHeight() const { return m_height; } - - float getMagnitudeAt(size_t x, size_t y); - float getNormalizedMagnitudeAt(size_t x, size_t y); - float getMaximumMagnitudeAt(size_t x); - float getPhaseAt(size_t x, size_t y); - void getValuesAt(size_t x, size_t y, float &real, float &imaginary); - bool isColumnReady(size_t x); - - void suspend(); - - // Convenience functions: - - bool isLocalPeak(size_t x, size_t y) { - float mag = getMagnitudeAt(x, y); - if (y > 0 && mag < getMagnitudeAt(x, y - 1)) return false; - if (y < getHeight()-1 && mag < getMagnitudeAt(x, y + 1)) return false; - return true; - } - bool isOverThreshold(size_t x, size_t y, float threshold) { - return getMagnitudeAt(x, y) > threshold; - } - - size_t getFillCompletion() const; - size_t getFillExtent() const; - -private: - FFTDataServer(QString fileBaseName, - const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar, - size_t fillFromColumn = 0); - - virtual ~FFTDataServer(); - - FFTDataServer(const FFTDataServer &); // not implemented - FFTDataServer &operator=(const FFTDataServer &); // not implemented - - typedef float fftsample; - - QString m_fileBaseName; - const DenseTimeValueModel *m_model; - int m_channel; - - Window<fftsample> m_windower; - - size_t m_windowSize; - size_t m_windowIncrement; - size_t m_fftSize; - bool m_polar; - - size_t m_width; - size_t m_height; - size_t m_cacheWidth; - - typedef std::vector<FFTCache *> CacheVector; - CacheVector m_caches; - - typedef std::deque<int> IntQueue; - IntQueue m_dormantCaches; - - int m_lastUsedCache; - FFTCache *getCache(size_t x, size_t &col) { - if (m_suspended) resume(); - col = x % m_cacheWidth; - int c = x / m_cacheWidth; - // The only use of m_lastUsedCache without a lock is to - // establish whether a cache has been created at all (they're - // created on demand, but not destroyed until the server is). - if (c == m_lastUsedCache) return m_caches[c]; - else return getCacheAux(c); - } - bool haveCache(size_t x) { - int c = x / m_cacheWidth; - if (c == m_lastUsedCache) return true; - else return (m_caches[c] != 0); - } - - FFTCache *getCacheAux(size_t c); - QMutex m_writeMutex; - QWaitCondition m_condition; - - fftsample *m_fftInput; - fftwf_complex *m_fftOutput; - float *m_workbuffer; - fftwf_plan m_fftPlan; - - class FillThread : public Thread - { - public: - FillThread(FFTDataServer &server, size_t fillFromColumn) : - m_server(server), m_extent(0), m_completion(0), - m_fillFrom(fillFromColumn) { } - - size_t getExtent() const { return m_extent; } - size_t getCompletion() const { return m_completion ? m_completion : 1; } - virtual void run(); - - protected: - FFTDataServer &m_server; - size_t m_extent; - size_t m_completion; - size_t m_fillFrom; - }; - - bool m_exiting; - bool m_suspended; - FillThread *m_fillThread; - - void deleteProcessingData(); - void fillColumn(size_t x); - void resume(); - - QString generateFileBasename() const; - static QString generateFileBasename(const DenseTimeValueModel *model, - int channel, - WindowType windowType, - size_t windowSize, - size_t windowIncrement, - size_t fftSize, - bool polar); - - typedef std::pair<FFTDataServer *, int> ServerCountPair; - typedef std::map<QString, ServerCountPair> ServerMap; - - static ServerMap m_servers; - static QMutex m_serverMapMutex; - static FFTDataServer *findServer(QString); // call with serverMapMutex held - static void purgeLimbo(int maxSize = 3); // call with serverMapMutex held -}; - -#endif
--- a/data/fileio/FFTFileCache.cpp Mon Nov 13 14:48:57 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,288 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#include "FFTFileCache.h" - -#include "MatrixFile.h" - -#include "base/Profiler.h" - -#include <iostream> - -#include <QMutexLocker> - -// The underlying matrix has height (m_height * 2 + 1). In each -// column we store magnitude at [0], [2] etc and phase at [1], [3] -// etc, and then store the normalization factor (maximum magnitude) at -// [m_height * 2]. - -FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode, - StorageType storageType) : - m_writebuf(0), - m_readbuf(0), - m_readbufCol(0), - m_readbufWidth(0), - m_mfc(new MatrixFile - (fileBase, mode, - storageType == Compact ? sizeof(uint16_t) : sizeof(float), - mode == MatrixFile::ReadOnly)), - m_storageType(storageType) -{ - std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl; -} - -FFTFileCache::~FFTFileCache() -{ - if (m_readbuf) delete[] m_readbuf; - if (m_writebuf) delete[] m_writebuf; - delete m_mfc; -} - -size_t -FFTFileCache::getWidth() const -{ - return m_mfc->getWidth(); -} - -size_t -FFTFileCache::getHeight() const -{ - size_t mh = m_mfc->getHeight(); - if (mh > 0) return (mh - 1) / 2; - else return 0; -} - -void -FFTFileCache::resize(size_t width, size_t height) -{ - QMutexLocker locker(&m_writeMutex); - - m_mfc->resize(width, height * 2 + 1); - if (m_readbuf) { - delete[] m_readbuf; - m_readbuf = 0; - } - if (m_writebuf) { - delete[] m_writebuf; - } - m_writebuf = new char[(height * 2 + 1) * m_mfc->getCellSize()]; -} - -void -FFTFileCache::reset() -{ - m_mfc->reset(); -} - -float -FFTFileCache::getMagnitudeAt(size_t x, size_t y) const -{ - float value = 0.f; - - switch (m_storageType) { - - case Compact: - value = (getFromReadBufCompactUnsigned(x, y * 2) / 65535.0) - * getNormalizationFactor(x); - break; - - case Rectangular: - { - float real, imag; - getValuesAt(x, y, real, imag); - value = sqrtf(real * real + imag * imag); - break; - } - - case Polar: - value = getFromReadBufStandard(x, y * 2); - break; - } - - return value; -} - -float -FFTFileCache::getNormalizedMagnitudeAt(size_t x, size_t y) const -{ - float value = 0.f; - - switch (m_storageType) { - - case Compact: - value = getFromReadBufCompactUnsigned(x, y * 2) / 65535.0; - break; - - default: - { - float mag = getMagnitudeAt(x, y); - float factor = getNormalizationFactor(x); - if (factor != 0) value = mag / factor; - else value = 0.f; - break; - } - } - - return value; -} - -float -FFTFileCache::getMaximumMagnitudeAt(size_t x) const -{ - return getNormalizationFactor(x); -} - -float -FFTFileCache::getPhaseAt(size_t x, size_t y) const -{ - float value = 0.f; - - switch (m_storageType) { - - case Compact: - value = (getFromReadBufCompactSigned(x, y * 2 + 1) / 32767.0) * M_PI; - break; - - case Rectangular: - { - float real, imag; - getValuesAt(x, y, real, imag); - value = princargf(atan2f(imag, real)); - break; - } - - case Polar: - value = getFromReadBufStandard(x, y * 2 + 1); - break; - } - - return value; -} - -void -FFTFileCache::getValuesAt(size_t x, size_t y, float &real, float &imag) const -{ - switch (m_storageType) { - - case Rectangular: - real = getFromReadBufStandard(x, y * 2); - imag = getFromReadBufStandard(x, y * 2 + 1); - return; - - default: - float mag = getMagnitudeAt(x, y); - float phase = getPhaseAt(x, y); - real = mag * cosf(phase); - imag = mag * sinf(phase); - return; - } -} - -bool -FFTFileCache::haveSetColumnAt(size_t x) const -{ - return m_mfc->haveSetColumnAt(x); -} - -void -FFTFileCache::setColumnAt(size_t x, float *mags, float *phases, float factor) -{ - QMutexLocker locker(&m_writeMutex); - - size_t h = getHeight(); - - switch (m_storageType) { - - case Compact: - for (size_t y = 0; y < h; ++y) { - ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mags[y] / factor) * 65535.0); - ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phases[y] * 32767) / M_PI)); - } - break; - - case Rectangular: - for (size_t y = 0; y < h; ++y) { - ((float *)m_writebuf)[y * 2] = mags[y] * cosf(phases[y]); - ((float *)m_writebuf)[y * 2 + 1] = mags[y] * sinf(phases[y]); - } - break; - - case Polar: - for (size_t y = 0; y < h; ++y) { - ((float *)m_writebuf)[y * 2] = mags[y]; - ((float *)m_writebuf)[y * 2 + 1] = phases[y]; - } - break; - } - - static float maxFactor = 0; - if (factor > maxFactor) maxFactor = factor; -// std::cerr << "Normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl; - - if (m_storageType == Compact) { - ((uint16_t *)m_writebuf)[h * 2] = factor * 65535.0; - } else { - ((float *)m_writebuf)[h * 2] = factor; - } - m_mfc->setColumnAt(x, m_writebuf); -} - -void -FFTFileCache::setColumnAt(size_t x, float *real, float *imag) -{ - QMutexLocker locker(&m_writeMutex); - - size_t h = getHeight(); - - float max = 0.0f; - - switch (m_storageType) { - - case Compact: - for (size_t y = 0; y < h; ++y) { - float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); - if (mag > max) max = mag; - } - for (size_t y = 0; y < h; ++y) { - float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); - float phase = princargf(atan2f(imag[y], real[y])); - ((uint16_t *)m_writebuf)[y * 2] = uint16_t((mag / max) * 65535.0); - ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI)); - } - break; - - case Rectangular: - for (size_t y = 0; y < h; ++y) { - ((float *)m_writebuf)[y * 2] = real[y]; - ((float *)m_writebuf)[y * 2 + 1] = imag[y]; - float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); - if (mag > max) max = mag; - } - break; - - case Polar: - for (size_t y = 0; y < h; ++y) { - float mag = sqrtf(real[y] * real[y] + imag[y] * imag[y]); - if (mag > max) max = mag; - ((float *)m_writebuf)[y * 2] = mag; - ((float *)m_writebuf)[y * 2 + 1] = princargf(atan2f(imag[y], real[y])); - } - break; - } - - ((float *)m_writebuf)[h * 2] = max; - m_mfc->setColumnAt(x, m_writebuf); -} -
--- a/data/fileio/FFTFileCache.h Mon Nov 13 14:48:57 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef _FFT_FILE_CACHE_H_ -#define _FFT_FILE_CACHE_H_ - -#include "FFTCache.h" -#include "MatrixFile.h" - -#include <QMutex> - -class FFTFileCache : public FFTCache -{ -public: - enum StorageType { - Compact, // 16 bits normalized polar - Rectangular, // floating point real+imag - Polar, // floating point mag+phase - }; - - FFTFileCache(QString fileBase, MatrixFile::Mode mode, - StorageType storageType); - virtual ~FFTFileCache(); - - MatrixFile::Mode getMode() const { return m_mfc->getMode(); } - - virtual size_t getWidth() const; - virtual size_t getHeight() const; - - virtual void resize(size_t width, size_t height); - virtual void reset(); // zero-fill or 1-fill as appropriate without changing size - - virtual float getMagnitudeAt(size_t x, size_t y) const; - virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const; - virtual float getMaximumMagnitudeAt(size_t x) const; - virtual float getPhaseAt(size_t x, size_t y) const; - - virtual void getValuesAt(size_t x, size_t y, float &real, float &imag) const; - - virtual bool haveSetColumnAt(size_t x) const; - - virtual void setColumnAt(size_t x, float *mags, float *phases, float factor); - virtual void setColumnAt(size_t x, float *reals, float *imags); - - virtual void suspend() { m_mfc->suspend(); } - -protected: - char *m_writebuf; - mutable char *m_readbuf; - mutable size_t m_readbufCol; - mutable size_t m_readbufWidth; - - float getFromReadBufStandard(size_t x, size_t y) const { - if (m_readbuf && - (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) { - return ((float *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y]; - } else { - populateReadBuf(x); - return getFromReadBufStandard(x, y); - } - } - - float getFromReadBufCompactUnsigned(size_t x, size_t y) const { - if (m_readbuf && - (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) { - return ((uint16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y]; - } else { - populateReadBuf(x); - return getFromReadBufCompactUnsigned(x, y); - } - } - - float getFromReadBufCompactSigned(size_t x, size_t y) const { - if (m_readbuf && - (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) { - return ((int16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y]; - } else { - populateReadBuf(x); - return getFromReadBufCompactSigned(x, y); - } - } - - void populateReadBuf(size_t x) const { - if (!m_readbuf) { - m_readbuf = new char[m_mfc->getHeight() * 2 * m_mfc->getCellSize()]; - } - m_mfc->getColumnAt(x, m_readbuf); - if (m_mfc->haveSetColumnAt(x + 1)) { - m_mfc->getColumnAt - (x + 1, m_readbuf + m_mfc->getCellSize() * m_mfc->getHeight()); - m_readbufWidth = 2; - } else { - m_readbufWidth = 1; - } - m_readbufCol = x; - } - - float getNormalizationFactor(size_t col) const { - if (m_storageType != Compact) { - return getFromReadBufStandard(col, m_mfc->getHeight() - 1); - } else { - float factor; - factor = getFromReadBufCompactUnsigned(col, m_mfc->getHeight() - 1); - return factor / 65535.0; - } - } - - MatrixFile *m_mfc; - QMutex m_writeMutex; - StorageType m_storageType; -}; - -#endif