changeset 266:2268963dabd1

* FFT: fix invalid write of normalisation factor in compact mode of disc cache * FFT: fix range problem for normalisation factor in compact mode (it was stored as an unsigned scaled from an assumed float range of 0->1, which is not very plausible and not accurate enough even if true -- use a float instead) * Spectrogram: fix vertical zoom behaviour for log frequency spectrograms: make the thing in the middle of the display remain in the middle after zoom * Overview widget: don't update the detailed waveform if still decoding the audio file (too expensive to do all those redraws)
author Chris Cannam
date Fri, 08 Jun 2007 15:19:50 +0000
parents e08f486e8d8c
children fa612dc181af
files base/LogRange.cpp base/LogRange.h data/fft/FFTFileCache.cpp data/fft/FFTFileCache.h data/fileio/CodedAudioFileReader.cpp data/model/WaveFileModel.cpp
diffstat 6 files changed, 82 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/base/LogRange.cpp	Wed Jun 06 16:24:55 2007 +0000
+++ b/base/LogRange.cpp	Fri Jun 08 15:19:50 2007 +0000
@@ -58,3 +58,8 @@
     return log10f(fabsf(value));
 }
 
+float
+LogRange::unmap(float value)
+{
+    return powf(10.0, value);
+}
--- a/base/LogRange.h	Wed Jun 06 16:24:55 2007 +0000
+++ b/base/LogRange.h	Fri Jun 08 15:19:50 2007 +0000
@@ -33,6 +33,12 @@
      * value if the absolute value is zero.
      */
     static float map(float value, float thresh = -10);
+
+    /**
+     * Map a value from the logarithmic range back again.  This just
+     * means taking the value'th power of ten.
+     */
+    static float unmap(float value);
 };
 
 #endif
--- a/data/fft/FFTFileCache.cpp	Wed Jun 06 16:24:55 2007 +0000
+++ b/data/fft/FFTFileCache.cpp	Fri Jun 08 15:19:50 2007 +0000
@@ -26,7 +26,7 @@
 // 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].
+// [m_height * 2].  In compact mode, the factor takes two cells.
 
 FFTFileCache::FFTFileCache(QString fileBase, MatrixFile::Mode mode,
                            StorageType storageType) :
@@ -38,7 +38,8 @@
           (fileBase, mode, 
            storageType == Compact ? sizeof(uint16_t) : sizeof(float),
            mode == MatrixFile::ReadOnly)),
-    m_storageType(storageType)
+    m_storageType(storageType),
+    m_factorSize(storageType == Compact ? 2 : 1)
 {
 //    std::cerr << "FFTFileCache: storage type is " << (storageType == Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << std::endl;
 }
@@ -60,7 +61,7 @@
 FFTFileCache::getHeight() const
 {
     size_t mh = m_mfc->getHeight();
-    if (mh > 0) return (mh - 1) / 2;
+    if (mh > m_factorSize) return (mh - m_factorSize) / 2;
     else return 0;
 }
 
@@ -69,7 +70,7 @@
 {
     QMutexLocker locker(&m_writeMutex);
 
-    m_mfc->resize(width, height * 2 + 1);
+    m_mfc->resize(width, height * 2 + m_factorSize);
     if (m_readbuf) {
         delete[] m_readbuf;
         m_readbuf = 0;
@@ -77,7 +78,7 @@
     if (m_writebuf) {
         delete[] m_writebuf;
     }
-    m_writebuf = new char[(height * 2 + 1) * m_mfc->getCellSize()];
+    m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()];
 }
 
 void
@@ -229,20 +230,12 @@
         break;
     }
 
-    static float maxFactor = 0;
-    if (factor > maxFactor) maxFactor = factor;
-//    std::cerr << "Normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
+//    static float maxFactor = 0;
+//    if (factor > maxFactor) maxFactor = factor;
+//    std::cerr << "Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
 
-    if (m_storageType == Compact) {
-        if (factor < 0.f || factor > 1.f) {
-            std::cerr << "WARNING: FFTFileCache::setColumnAt: Normalization factor " << factor << " out of range" << std::endl;
-            if (factor < 0.f) factor = 0.f;
-            if (factor > 1.f) factor = 1.f;
-        }
-        ((uint16_t *)m_writebuf)[h * 2] = (uint16_t)(factor * 65535.0);
-    } else {
-        ((float *)m_writebuf)[h * 2] = factor;
-    }
+    setNormalizationFactorToWritebuf(factor);
+
     m_mfc->setColumnAt(x, m_writebuf);
 }
 
@@ -253,19 +246,19 @@
 
     size_t h = getHeight();
 
-    float max = 0.0f;
+    float factor = 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;
+            if (mag > factor) factor = 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] = uint16_t((mag / factor) * 65535.0);
             ((uint16_t *)m_writebuf)[y * 2 + 1] = uint16_t(int16_t((phase * 32767) / M_PI));
         }
         break;
@@ -275,28 +268,33 @@
             ((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;
+            if (mag > factor) factor = 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;
+            if (mag > factor) factor = 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;
+//    static float maxFactor = 0;
+//    if (factor > maxFactor) maxFactor = factor;
+//    std::cerr << "[RI] Column " << x << ": normalization factor: " << factor << ", max " << maxFactor << " (height " << getHeight() << ")" << std::endl;
+
+    setNormalizationFactorToWritebuf(factor);
+
     m_mfc->setColumnAt(x, m_writebuf);
 }
 
 size_t
 FFTFileCache::getCacheSize(size_t width, size_t height, StorageType type)
 {
-    return (height * 2 + 1) * width *
+    return (height * 2 + (type == Compact ? 2 : 1)) * width *
         (type == Compact ? sizeof(uint16_t) : sizeof(float)) +
         2 * sizeof(size_t); // matrix file header size
 }
--- a/data/fft/FFTFileCache.h	Wed Jun 06 16:24:55 2007 +0000
+++ b/data/fft/FFTFileCache.h	Fri Jun 08 15:19:50 2007 +0000
@@ -97,18 +97,47 @@
     void populateReadBuf(size_t x) const;
 
     float getNormalizationFactor(size_t col) const {
+        size_t h = m_mfc->getHeight();
+        if (h < m_factorSize) return 0;
         if (m_storageType != Compact) {
-            return getFromReadBufStandard(col, m_mfc->getHeight() - 1);
+            return getFromReadBufStandard(col, h - 1);
         } else {
-            float factor;
-            factor = getFromReadBufCompactUnsigned(col, m_mfc->getHeight() - 1);
-            return factor / 65535.0;
+            union {
+                float f;
+                uint16_t u[2];
+            } factor;
+            if (!m_readbuf ||
+                !(m_readbufCol == col ||
+                  (m_readbufWidth > 1 && m_readbufCol+1 == col))) {
+                populateReadBuf(col);
+            }
+            size_t ix = (col - m_readbufCol) * m_mfc->getHeight() + h;
+            factor.u[0] = ((uint16_t *)m_readbuf)[ix - 2];
+            factor.u[1] = ((uint16_t *)m_readbuf)[ix - 1];
+            return factor.f;
         }
     }
 
+    void setNormalizationFactorToWritebuf(float newfactor) {
+        size_t h = m_mfc->getHeight();
+        if (h < m_factorSize) return;
+        if (m_storageType != Compact) {
+            ((float *)m_writebuf)[h - 1] = newfactor;
+        } else {
+            union {
+                float f;
+                uint16_t u[2];
+            } factor;
+            factor.f = newfactor;
+            ((uint16_t *)m_writebuf)[h - 2] = factor.u[0];
+            ((uint16_t *)m_writebuf)[h - 1] = factor.u[1];
+        }
+    }            
+
     MatrixFile *m_mfc;
     QMutex m_writeMutex;
     StorageType m_storageType;
+    size_t m_factorSize;
 };
 
 #endif
--- a/data/fileio/CodedAudioFileReader.cpp	Wed Jun 06 16:24:55 2007 +0000
+++ b/data/fileio/CodedAudioFileReader.cpp	Fri Jun 08 15:19:50 2007 +0000
@@ -129,11 +129,11 @@
                             m_cacheWriteBufferSize);
 
             m_cacheWriteBufferIndex = 0;
+        }
 
-            if (m_cacheWriteBufferIndex % 10240 == 0 &&
-                m_cacheFileReader) {
-                m_cacheFileReader->updateFrameCount();
-            }
+        if (m_cacheWriteBufferIndex % 10240 == 0 &&
+            m_cacheFileReader) {
+            m_cacheFileReader->updateFrameCount();
         }
         break;
 
--- a/data/model/WaveFileModel.cpp	Wed Jun 06 16:24:55 2007 +0000
+++ b/data/model/WaveFileModel.cpp	Fri Jun 08 15:19:50 2007 +0000
@@ -96,14 +96,22 @@
 {
     bool ready = (isOK() && (m_fillThread == 0));
     double c = double(m_lastFillExtent) / double(getEndFrame() - getStartFrame());
+    static int prevCompletion = 0;
     if (completion) {
         *completion = int(c * 100.0 + 0.01);
         if (m_reader) {
             int decodeCompletion = m_reader->getDecodeCompletion();
-//            std::cerr << "decodeCompletion " << decodeCompletion << ", completion " << *completion << std::endl;
-//            if (decodeCompletion < *completion) *completion = decodeCompletion;
-            if (decodeCompletion < 100) *completion = decodeCompletion;
+            if (decodeCompletion < 90) *completion = decodeCompletion;
+            else *completion = std::min(*completion, decodeCompletion);
         }
+        if (*completion != 0 &&
+            *completion != 100 &&
+            prevCompletion != 0 &&
+            prevCompletion > *completion) {
+            // just to avoid completion going backwards
+            *completion = prevCompletion;
+        }
+        prevCompletion = *completion;
     }
 #ifdef DEBUG_WAVE_FILE_MODEL
     std::cerr << "WaveFileModel::isReady(): ready = " << ready << ", completion = " << (completion ? *completion : -1) << std::endl;