# HG changeset patch # User Chris Cannam # Date 1155740349 0 # Node ID e5879045d22bb924a164fcce6e2e5b658403c711 # Parent 74abef65711bfd727362a1f2306d36d1605f4afb * Pull memory cache out into its own file diff -r 74abef65711b -r e5879045d22b data/data.pro --- a/data/data.pro Wed Aug 16 14:57:22 2006 +0000 +++ b/data/data.pro Wed Aug 16 14:59:09 2006 +0000 @@ -16,6 +16,7 @@ HEADERS += fft/FFTCache.h \ fft/FFTDataServer.h \ fft/FFTFileCache.h \ + fft/FFTMemoryCache.h \ fileio/AudioFileReader.h \ fileio/AudioFileReaderFactory.h \ fileio/BZipFileDevice.h \ @@ -46,9 +47,9 @@ model/SparseValueModel.h \ model/TextModel.h \ model/WaveFileModel.h -SOURCES += fft/FFTCache.cpp \ - fft/FFTDataServer.cpp \ +SOURCES += fft/FFTDataServer.cpp \ fft/FFTFileCache.cpp \ + fft/FFTMemoryCache.cpp \ fileio/AudioFileReaderFactory.cpp \ fileio/BZipFileDevice.cpp \ fileio/CodedAudioFileReader.cpp \ diff -r 74abef65711b -r e5879045d22b data/fft/FFTCache.cpp --- a/data/fft/FFTCache.cpp Wed Aug 16 14:57:22 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +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 "FFTCache.h" -#include "system/System.h" - -#include - -//!!! This class is a work in progress -- it does only as much as we -// need for the current SpectrogramLayer. Slated for substantial -// refactoring and extension. - -FFTMemoryCache::FFTMemoryCache() : - m_width(0), - m_height(0), - m_magnitude(0), - m_phase(0), - m_factor(0) -{ -} - -FFTMemoryCache::~FFTMemoryCache() -{ - std::cerr << "FFTMemoryCache[" << this << "]::~Cache" << std::endl; - - for (size_t i = 0; i < m_width; ++i) { - if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]); - if (m_phase && m_phase[i]) free(m_phase[i]); - } - - if (m_magnitude) free(m_magnitude); - if (m_phase) free(m_phase); - if (m_factor) free(m_factor); -} - -void -FFTMemoryCache::resize(size_t width, size_t height) -{ - std::cerr << "FFTMemoryCache[" << this << "]::resize(" << width << "x" << height << " = " << width*height << ")" << std::endl; - - if (m_width == width && m_height == height) return; - - resize(m_magnitude, width, height); - resize(m_phase, width, height); - - m_factor = (float *)realloc(m_factor, width * sizeof(float)); - - m_width = width; - m_height = height; - - std::cerr << "done, width = " << m_width << " height = " << m_height << std::endl; -} - -void -FFTMemoryCache::resize(uint16_t **&array, size_t width, size_t height) -{ - for (size_t i = width; i < m_width; ++i) { - free(array[i]); - } - - if (width != m_width) { - array = (uint16_t **)realloc(array, width * sizeof(uint16_t *)); - if (!array) throw std::bad_alloc(); - MUNLOCK(array, width * sizeof(uint16_t *)); - } - - for (size_t i = m_width; i < width; ++i) { - array[i] = 0; - } - - for (size_t i = 0; i < width; ++i) { - array[i] = (uint16_t *)realloc(array[i], height * sizeof(uint16_t)); - if (!array[i]) throw std::bad_alloc(); - MUNLOCK(array[i], height * sizeof(uint16_t)); - } -} - -void -FFTMemoryCache::reset() -{ - for (size_t x = 0; x < m_width; ++x) { - for (size_t y = 0; y < m_height; ++y) { - m_magnitude[x][y] = 0; - m_phase[x][y] = 0; - } - m_factor[x] = 1.0; - } -} - -void -FFTMemoryCache::setColumnAt(size_t x, float *reals, float *imags) -{ - float max = 0.0; - - for (size_t y = 0; y < m_height; ++y) { - float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]); - float phase = atan2f(imags[y], reals[y]); - phase = princargf(phase); - reals[y] = mag; - imags[y] = phase; - if (mag > max) max = mag; - } - - setColumnAt(x, reals, imags, max); -} - diff -r 74abef65711b -r e5879045d22b data/fft/FFTCache.h --- a/data/fft/FFTCache.h Wed Aug 16 14:57:22 2006 +0000 +++ b/data/fft/FFTCache.h Wed Aug 16 14:59:09 2006 +0000 @@ -54,105 +54,4 @@ }; -/** - * For the in-memory FFT cache, we would like to cache magnitude with - * enough resolution to have gain applied afterwards and determine - * whether something is a peak or not, and also cache phase rather - * than only phase-adjusted frequency so that we don't have to - * recalculate if switching between phase and magnitude displays. At - * the same time, we don't want to take up too much memory. It's not - * expected to be accurate enough to be used as input for DSP or - * resynthesis code. - * - * This implies probably 16 bits for a normalized magnitude and at - * most 16 bits for phase. - * - * Each column's magnitudes are expected to be stored normalized - * to [0,1] with respect to the column, so the normalization - * factor should be calculated before all values in a column, and - * set appropriately. - */ - -class FFTMemoryCache : public FFTCache -{ -public: - FFTMemoryCache(); // of size zero, call resize() before using - virtual ~FFTMemoryCache(); - - virtual size_t getWidth() const { return m_width; } - virtual size_t getHeight() const { return m_height; } - - 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 { - return getNormalizedMagnitudeAt(x, y) * m_factor[x]; - } - - virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const { - return float(m_magnitude[x][y]) / 65535.0; - } - - virtual float getMaximumMagnitudeAt(size_t x) const { - return m_factor[x]; - } - - virtual float getPhaseAt(size_t x, size_t y) const { - int16_t i = (int16_t)m_phase[x][y]; - return (float(i) / 32767.0) * M_PI; - } - - virtual void getValuesAt(size_t x, size_t y, float &real, float &imag) const { - float mag = getMagnitudeAt(x, y); - float phase = getPhaseAt(x, y); - real = mag * cosf(phase); - imag = mag * sinf(phase); - } - - virtual void setNormalizationFactor(size_t x, float factor) { - if (x < m_width) m_factor[x] = factor; - } - - virtual void setMagnitudeAt(size_t x, size_t y, float mag) { - // norm factor must already be set - setNormalizedMagnitudeAt(x, y, mag / m_factor[x]); - } - - virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) { - if (x < m_width && y < m_height) { - m_magnitude[x][y] = uint16_t(norm * 65535.0); - } - } - - virtual void setPhaseAt(size_t x, size_t y, float phase) { - // phase in range -pi -> pi - if (x < m_width && y < m_height) { - m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI)); - } - } - - virtual bool haveSetColumnAt(size_t) const { - return true; - } - - virtual void setColumnAt(size_t x, float *mags, float *phases, float factor) { - setNormalizationFactor(x, factor); - for (size_t y = 0; y < m_height; ++y) { - setMagnitudeAt(x, y, mags[y]); - setPhaseAt(x, y, phases[y]); - } - } - - virtual void setColumnAt(size_t x, float *reals, float *imags); - -private: - size_t m_width; - size_t m_height; - uint16_t **m_magnitude; - uint16_t **m_phase; - float *m_factor; - - void resize(uint16_t **&, size_t, size_t); -}; - #endif diff -r 74abef65711b -r e5879045d22b data/fft/FFTDataServer.cpp --- a/data/fft/FFTDataServer.cpp Wed Aug 16 14:57:22 2006 +0000 +++ b/data/fft/FFTDataServer.cpp Wed Aug 16 14:59:09 2006 +0000 @@ -16,6 +16,7 @@ #include "FFTDataServer.h" #include "FFTFileCache.h" +#include "FFTMemoryCache.h" #include "model/DenseTimeValueModel.h" @@ -487,6 +488,8 @@ m_polar ? FFTFileCache::Polar : FFTFileCache::Rectangular); +// FFTCache *cache = new FFTMemoryCache(); + size_t width = m_cacheWidth; if (c * m_cacheWidth + width > m_width) { width = m_width - c * m_cacheWidth; @@ -744,6 +747,9 @@ m_server.m_writeMutex.lock(); m_server.m_condition.wait(&m_server.m_writeMutex, 10000); m_server.m_writeMutex.unlock(); +#ifdef DEBUG_FFT_SERVER + std::cerr << "FFTDataServer(" << this << "): waited" << std::endl; +#endif if (m_server.m_exiting) return; } diff -r 74abef65711b -r e5879045d22b data/fft/FFTMemoryCache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fft/FFTMemoryCache.cpp Wed Aug 16 14:59:09 2006 +0000 @@ -0,0 +1,115 @@ +/* -*- 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 "FFTMemoryCache.h" +#include "system/System.h" + +#include + +FFTMemoryCache::FFTMemoryCache() : + m_width(0), + m_height(0), + m_magnitude(0), + m_phase(0), + m_factor(0) +{ +} + +FFTMemoryCache::~FFTMemoryCache() +{ + std::cerr << "FFTMemoryCache[" << this << "]::~Cache" << std::endl; + + for (size_t i = 0; i < m_width; ++i) { + if (m_magnitude && m_magnitude[i]) free(m_magnitude[i]); + if (m_phase && m_phase[i]) free(m_phase[i]); + } + + if (m_magnitude) free(m_magnitude); + if (m_phase) free(m_phase); + if (m_factor) free(m_factor); +} + +void +FFTMemoryCache::resize(size_t width, size_t height) +{ + std::cerr << "FFTMemoryCache[" << this << "]::resize(" << width << "x" << height << " = " << width*height << ")" << std::endl; + + if (m_width == width && m_height == height) return; + + resize(m_magnitude, width, height); + resize(m_phase, width, height); + m_colset.resize(width); + + m_factor = (float *)realloc(m_factor, width * sizeof(float)); + + m_width = width; + m_height = height; + + std::cerr << "done, width = " << m_width << " height = " << m_height << std::endl; +} + +void +FFTMemoryCache::resize(uint16_t **&array, size_t width, size_t height) +{ + for (size_t i = width; i < m_width; ++i) { + free(array[i]); + } + + if (width != m_width) { + array = (uint16_t **)realloc(array, width * sizeof(uint16_t *)); + if (!array) throw std::bad_alloc(); + MUNLOCK(array, width * sizeof(uint16_t *)); + } + + for (size_t i = m_width; i < width; ++i) { + array[i] = 0; + } + + for (size_t i = 0; i < width; ++i) { + array[i] = (uint16_t *)realloc(array[i], height * sizeof(uint16_t)); + if (!array[i]) throw std::bad_alloc(); + MUNLOCK(array[i], height * sizeof(uint16_t)); + } +} + +void +FFTMemoryCache::reset() +{ + for (size_t x = 0; x < m_width; ++x) { + for (size_t y = 0; y < m_height; ++y) { + m_magnitude[x][y] = 0; + m_phase[x][y] = 0; + } + m_factor[x] = 1.0; + } +} + +void +FFTMemoryCache::setColumnAt(size_t x, float *reals, float *imags) +{ + float max = 0.0; + + for (size_t y = 0; y < m_height; ++y) { + float mag = sqrtf(reals[y] * reals[y] + imags[y] * imags[y]); + float phase = atan2f(imags[y], reals[y]); + phase = princargf(phase); + reals[y] = mag; + imags[y] = phase; + if (mag > max) max = mag; + } + + setColumnAt(x, reals, imags, max); +} + diff -r 74abef65711b -r e5879045d22b data/fft/FFTMemoryCache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/fft/FFTMemoryCache.h Wed Aug 16 14:59:09 2006 +0000 @@ -0,0 +1,128 @@ +/* -*- 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_MEMORY_CACHE_H_ +#define _FFT_MEMORY_CACHE_H_ + +#include "FFTCache.h" + +#include "base/ResizeableBitset.h" + +/** + * For the in-memory FFT cache, we would like to cache magnitude with + * enough resolution to have gain applied afterwards and determine + * whether something is a peak or not, and also cache phase rather + * than only phase-adjusted frequency so that we don't have to + * recalculate if switching between phase and magnitude displays. At + * the same time, we don't want to take up too much memory. It's not + * expected to be accurate enough to be used as input for DSP or + * resynthesis code. + * + * This implies probably 16 bits for a normalized magnitude and at + * most 16 bits for phase. + * + * Each column's magnitudes are expected to be stored normalized + * to [0,1] with respect to the column, so the normalization + * factor should be calculated before all values in a column, and + * set appropriately. + */ + +class FFTMemoryCache : public FFTCache +{ +public: + FFTMemoryCache(); // of size zero, call resize() before using + virtual ~FFTMemoryCache(); + + virtual size_t getWidth() const { return m_width; } + virtual size_t getHeight() const { return m_height; } + + 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 { + return getNormalizedMagnitudeAt(x, y) * m_factor[x]; + } + + virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const { + return float(m_magnitude[x][y]) / 65535.0; + } + + virtual float getMaximumMagnitudeAt(size_t x) const { + return m_factor[x]; + } + + virtual float getPhaseAt(size_t x, size_t y) const { + int16_t i = (int16_t)m_phase[x][y]; + return (float(i) / 32767.0) * M_PI; + } + + virtual void getValuesAt(size_t x, size_t y, float &real, float &imag) const { + float mag = getMagnitudeAt(x, y); + float phase = getPhaseAt(x, y); + real = mag * cosf(phase); + imag = mag * sinf(phase); + } + + virtual void setNormalizationFactor(size_t x, float factor) { + if (x < m_width) m_factor[x] = factor; + } + + virtual void setMagnitudeAt(size_t x, size_t y, float mag) { + // norm factor must already be set + setNormalizedMagnitudeAt(x, y, mag / m_factor[x]); + } + + virtual void setNormalizedMagnitudeAt(size_t x, size_t y, float norm) { + if (x < m_width && y < m_height) { + m_magnitude[x][y] = uint16_t(norm * 65535.0); + } + } + + virtual void setPhaseAt(size_t x, size_t y, float phase) { + // phase in range -pi -> pi + if (x < m_width && y < m_height) { + m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI)); + } + } + + virtual bool haveSetColumnAt(size_t x) const { + return m_colset.get(x); + } + + virtual void setColumnAt(size_t x, float *mags, float *phases, float factor) { + setNormalizationFactor(x, factor); + for (size_t y = 0; y < m_height; ++y) { + setMagnitudeAt(x, y, mags[y]); + setPhaseAt(x, y, phases[y]); + } + m_colset.set(x); + } + + virtual void setColumnAt(size_t x, float *reals, float *imags); + +private: + size_t m_width; + size_t m_height; + uint16_t **m_magnitude; + uint16_t **m_phase; + float *m_factor; + ResizeableBitset m_colset; + + void resize(uint16_t **&, size_t, size_t); +}; + + +#endif +