# HG changeset patch # User Chris Cannam # Date 1180706195 0 # Node ID 260032c26c4f7d254551001ef5b3b3d87fd69cfb # Parent 71dfc6ab3b54529c0475b7f9058456b6bfa975fd * don't store fft values scaled by fftsize/2; that's a special requirement for the spectrogram, and other applications will not expect it -- make the spectrogram do that scaling itself * add a higher-resolution memory cache (still polar, though) as an alternative to the 16-bit compact cache * don't use the memory cache if we want rectangular coords (unless the disc cache is totally infeasible) as conversion slows it down anyway * avoid redundant rectangular -> polar -> rectangular conversion when storing values in a rectangular-mode disc cache diff -r 71dfc6ab3b54 -r 260032c26c4f data/fft/FFTDataServer.cpp --- a/data/fft/FFTDataServer.cpp Thu May 24 16:20:22 2007 +0000 +++ b/data/fft/FFTDataServer.cpp Fri Jun 01 13:56:35 2007 +0000 @@ -534,9 +534,11 @@ StorageAdviser::Criteria criteria; if (m_polar) { criteria = StorageAdviser::Criteria - (StorageAdviser::SpeedCritical | StorageAdviser::LongRetentionLikely); + (StorageAdviser::SpeedCritical | + StorageAdviser::LongRetentionLikely); } else { - criteria = StorageAdviser::Criteria(StorageAdviser::PrecisionCritical); + criteria = StorageAdviser::Criteria + (StorageAdviser::PrecisionCritical); } int cells = m_width * m_height; @@ -566,10 +568,26 @@ StorageAdviser::recommend(criteria, minimumSize, maximumSize); } -// std::cerr << "Recommendation was: " << recommendation << std::endl; + std::cerr << "Recommendation was: " << recommendation << std::endl; - m_memoryCache = ((recommendation & StorageAdviser::UseMemory) || - (recommendation & StorageAdviser::PreferMemory)); + m_memoryCache = false; + + if (recommendation & StorageAdviser::UseMemory) { + + // can't use disc, must use memory + + m_memoryCache = true; + + } else if (recommendation & StorageAdviser::PreferMemory) { + + // if memory is recommended, we use it if we're using polar + // coordinates; but we don't have a native rectangular memory + // cache, so we might as well use disc if we want rectangular + // coordinates rather than have all the bother of converting + // every time + + if (m_polar) m_memoryCache = true; + } m_compactCache = (recommendation & StorageAdviser::ConserveSpace); @@ -763,21 +781,27 @@ } try { - + if (m_memoryCache) { - cache = new FFTMemoryCache(); + cache = new FFTMemoryCache + (m_compactCache ? FFTMemoryCache::Compact : + FFTMemoryCache::Polar); } else if (m_compactCache) { - cache = new FFTFileCache(name, MatrixFile::ReadWrite, - FFTFileCache::Compact); + cache = new FFTFileCache + (name, + MatrixFile::ReadWrite, + FFTFileCache::Compact); } else { - cache = new FFTFileCache(name, MatrixFile::ReadWrite, - m_polar ? FFTFileCache::Polar : - FFTFileCache::Rectangular); + cache = new FFTFileCache + (name, + MatrixFile::ReadWrite, + m_polar ? FFTFileCache::Polar : + FFTFileCache::Rectangular); } cache->resize(width, m_height); @@ -932,10 +956,8 @@ #endif fillColumn(x); } - float magnitude = cache->getMagnitudeAt(col, y); - float phase = cache->getPhaseAt(col, y); - real = magnitude * cosf(phase); - imaginary = magnitude * sinf(phase); + + cache->getValuesAt(col, y, real, imaginary); } bool @@ -1055,23 +1077,13 @@ 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+1] = phase; + m_workbuffer[i] = m_fftOutput[i][0]; + m_workbuffer[i + m_fftSize/2 + 1] = m_fftOutput[i][1]; } cache->setColumnAt(col, m_workbuffer, - m_workbuffer + m_fftSize/2+1, - factor); + m_workbuffer + m_fftSize/2+1); if (m_suspended) { // std::cerr << "FFTDataServer::fillColumn(" << x << "): calling resume" << std::endl; diff -r 71dfc6ab3b54 -r 260032c26c4f data/fft/FFTMemoryCache.cpp --- a/data/fft/FFTMemoryCache.cpp Thu May 24 16:20:22 2007 +0000 +++ b/data/fft/FFTMemoryCache.cpp Fri Jun 01 13:56:35 2007 +0000 @@ -18,26 +18,35 @@ #include -FFTMemoryCache::FFTMemoryCache() : +FFTMemoryCache::FFTMemoryCache(StorageType storageType) : m_width(0), m_height(0), m_magnitude(0), m_phase(0), - m_factor(0) + m_fmagnitude(0), + m_fphase(0), + m_factor(0), + m_storageType(storageType) { + std::cerr << "FFTMemoryCache[" << this << "]::FFTMemoryCache (type " + << m_storageType << ")" << std::endl; } FFTMemoryCache::~FFTMemoryCache() { -// std::cerr << "FFTMemoryCache[" << this << "]::~Cache" << std::endl; +// std::cerr << "FFTMemoryCache[" << this << "]::~FFTMemoryCache" << 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_fmagnitude && m_fmagnitude[i]) free(m_fmagnitude[i]); + if (m_fphase && m_fphase[i]) free(m_fphase[i]); } if (m_magnitude) free(m_magnitude); if (m_phase) free(m_phase); + if (m_fmagnitude) free(m_fmagnitude); + if (m_fphase) free(m_fphase); if (m_factor) free(m_factor); } @@ -48,8 +57,14 @@ if (m_width == width && m_height == height) return; - resize(m_magnitude, width, height); - resize(m_phase, width, height); + if (m_storageType == Compact) { + resize(m_magnitude, width, height); + resize(m_phase, width, height); + } else { + resize(m_fmagnitude, width, height); + resize(m_fphase, width, height); + } + m_colset.resize(width); m_factor = (float *)realloc(m_factor, width * sizeof(float)); @@ -85,14 +100,53 @@ } void +FFTMemoryCache::resize(float **&array, size_t width, size_t height) +{ + for (size_t i = width; i < m_width; ++i) { + free(array[i]); + } + + if (width != m_width) { + array = (float **)realloc(array, width * sizeof(float *)); + if (!array) throw std::bad_alloc(); + MUNLOCK(array, width * sizeof(float *)); + } + + for (size_t i = m_width; i < width; ++i) { + array[i] = 0; + } + + for (size_t i = 0; i < width; ++i) { + array[i] = (float *)realloc(array[i], height * sizeof(float)); + if (!array[i]) throw std::bad_alloc(); + MUNLOCK(array[i], height * sizeof(float)); + } +} + +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; + switch (m_storageType) { + + case Compact: + 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; + } + break; + + case Polar: + for (size_t x = 0; x < m_width; ++x) { + for (size_t y = 0; y < m_height; ++y) { + m_fmagnitude[x][y] = 0; + m_fphase[x][y] = 0; + } + m_factor[x] = 1.0; + } + break; } } @@ -101,21 +155,38 @@ { 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; - } + switch (m_storageType) { + + case Compact: + case Polar: + 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; + } + break; + }; setColumnAt(x, reals, imags, max); } size_t -FFTMemoryCache::getCacheSize(size_t width, size_t height) +FFTMemoryCache::getCacheSize(size_t width, size_t height, StorageType type) { - return (height * 2 + 1) * width * sizeof(uint16_t); + size_t sz = 0; + + switch (type) { + + case Compact: + sz = (height * 2 + 1) * width * sizeof(uint16_t); + + case Polar: + sz = (height * 2 + 1) * width * sizeof(float); + } + + return sz; } diff -r 71dfc6ab3b54 -r 260032c26c4f data/fft/FFTMemoryCache.h --- a/data/fft/FFTMemoryCache.h Thu May 24 16:20:22 2007 +0000 +++ b/data/fft/FFTMemoryCache.h Fri Jun 01 13:56:35 2007 +0000 @@ -42,7 +42,12 @@ class FFTMemoryCache : public FFTCache { public: - FFTMemoryCache(); // of size zero, call resize() before using + enum StorageType { + Compact, // 16 bits normalized polar + Polar, // floating point mag+phase + }; + + FFTMemoryCache(StorageType storageType); // of size zero, call resize() before using virtual ~FFTMemoryCache(); virtual size_t getWidth() const { return m_width; } @@ -56,7 +61,8 @@ } virtual float getNormalizedMagnitudeAt(size_t x, size_t y) const { - return float(m_magnitude[x][y]) / 65535.0; + if (m_storageType == Polar) return m_fmagnitude[x][y]; + else return float(m_magnitude[x][y]) / 65535.0; } virtual float getMaximumMagnitudeAt(size_t x) const { @@ -64,6 +70,7 @@ } virtual float getPhaseAt(size_t x, size_t y) const { + if (m_storageType == Polar) return m_fphase[x][y]; int16_t i = (int16_t)m_phase[x][y]; return (float(i) / 32767.0) * M_PI; } @@ -86,14 +93,16 @@ 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); + if (m_storageType == Polar) m_fmagnitude[x][y] = norm; + else 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)); + if (m_storageType == Polar) m_fphase[x][y] = phase; + else m_phase[x][y] = uint16_t(int16_t((phase * 32767) / M_PI)); } } @@ -112,17 +121,21 @@ virtual void setColumnAt(size_t x, float *reals, float *imags); - static size_t getCacheSize(size_t width, size_t height); + static size_t getCacheSize(size_t width, size_t height, StorageType type); private: size_t m_width; size_t m_height; uint16_t **m_magnitude; uint16_t **m_phase; + float **m_fmagnitude; + float **m_fphase; float *m_factor; + StorageType m_storageType; ResizeableBitset m_colset; void resize(uint16_t **&, size_t, size_t); + void resize(float **&, size_t, size_t); }; diff -r 71dfc6ab3b54 -r 260032c26c4f data/fileio/MP3FileReader.cpp --- a/data/fileio/MP3FileReader.cpp Thu May 24 16:20:22 2007 +0000 +++ b/data/fileio/MP3FileReader.cpp Fri Jun 01 13:56:35 2007 +0000 @@ -31,7 +31,8 @@ MP3FileReader::MP3FileReader(QString path, DecodeMode decodeMode, CacheMode mode) : CodedAudioFileReader(mode), - m_path(path) + m_path(path), + m_decodeThread(0) { m_frameCount = 0; m_channelCount = 0;