changeset 264:260032c26c4f

* 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
author Chris Cannam
date Fri, 01 Jun 2007 13:56:35 +0000
parents 71dfc6ab3b54
children e08f486e8d8c
files data/fft/FFTDataServer.cpp data/fft/FFTMemoryCache.cpp data/fft/FFTMemoryCache.h data/fileio/MP3FileReader.cpp
diffstat 4 files changed, 153 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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 <iostream>
 
-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;
 }
 
--- 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);
 };
 
 
--- 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;