changeset 1100:5cbf71022679 simple-fft-model

Smooth signal flow through from file to fft model
author Chris Cannam
date Mon, 15 Jun 2015 16:02:58 +0100
parents 0c351e061945
children cd156ede1395
files data/fileio/CodedAudioFileReader.cpp data/fileio/CodedAudioFileReader.h data/model/AggregateWaveModel.cpp data/model/FFTModel.cpp data/model/FFTModel.h data/model/WaveFileModel.cpp
diffstat 6 files changed, 70 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/data/fileio/CodedAudioFileReader.cpp	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/fileio/CodedAudioFileReader.cpp	Mon Jun 15 16:02:58 2015 +0100
@@ -367,7 +367,7 @@
         break;
 
     case CacheInMemory:
-        m_dataLock.lockForWrite();
+        m_dataLock.lock();
         m_data.insert(m_data.end(), buffer, buffer + count);
         m_dataLock.unlock();
         break;
@@ -449,26 +449,25 @@
         if (!isOK()) return {};
         if (count == 0) return {};
 
-        sv_frame_t idx = start * m_channelCount;
-        sv_frame_t i = 0;
-        sv_frame_t n = count * m_channelCount;
+        sv_frame_t ix0 = start * m_channelCount;
+        sv_frame_t ix1 = ix0 + (count * m_channelCount);
 
-        frames.resize(n);
-
-        m_dataLock.lockForRead();
-        while (i < n && in_range_for(m_data, idx)) {
-            frames[i++] = m_data[idx++];
-        }
+        // This lock used to be a QReadWriteLock, but it appears that
+        // its lock mechanism is significantly slower than QMutex so
+        // it's not a good idea in cases like this where we don't
+        // really have threads taking a long time to read concurrently
+        m_dataLock.lock();
+        sv_frame_t n = sv_frame_t(m_data.size());
+        if (ix1 > n) ix1 = n;
+        frames = vector<float>(m_data.begin() + ix0, m_data.begin() + ix1);
         m_dataLock.unlock();
-
-        frames.resize(i);
     }
     }
 
     if (m_normalised) {
         for (auto &f: frames) f *= m_gain;
     }
-
+    
     return frames;
 }
 
--- a/data/fileio/CodedAudioFileReader.h	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/fileio/CodedAudioFileReader.h	Mon Jun 15 16:02:58 2015 +0100
@@ -84,7 +84,7 @@
     QMutex m_cacheMutex;
     CacheMode m_cacheMode;
     std::vector<float> m_data;
-    mutable QReadWriteLock m_dataLock;
+    mutable QMutex m_dataLock;
     bool m_initialised;
     Serialiser *m_serialiser;
     sv_samplerate_t m_fileRate;
--- a/data/model/AggregateWaveModel.cpp	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/model/AggregateWaveModel.cpp	Mon Jun 15 16:02:58 2015 +0100
@@ -111,8 +111,8 @@
 
         auto here = m_components[c].model->getData(m_components[c].channel,
                                                    start, count);
-        if (here.size() > longest) {
-            longest = here.size();
+        if (sv_frame_t(here.size()) > longest) {
+            longest = sv_frame_t(here.size());
         }
         for (sv_frame_t i = 0; in_range_for(here, i); ++i) {
             result[i] += here[i];
@@ -133,7 +133,9 @@
 
     for (int c = fromchannel; c <= tochannel; ++c) {
         auto here = getData(c, start, count);
-        if (here.size() < min) min = here.size();
+        if (sv_frame_t(here.size()) < min) {
+            min = sv_frame_t(here.size());
+        }
         result.push_back(here);
     }
 
--- a/data/model/FFTModel.cpp	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/model/FFTModel.cpp	Mon Jun 15 16:02:58 2015 +0100
@@ -225,23 +225,24 @@
 //         << "): saved range is (" << m_savedData.range.first
 //         << "," << m_savedData.range.second << ")" << endl;
 
-    if (m_savedData.range == range) return m_savedData.data;
+    if (m_savedData.range == range) {
+        return m_savedData.data;
+    }
 
     if (range.first < m_savedData.range.second &&
         range.first >= m_savedData.range.first &&
         range.second > m_savedData.range.second) {
 
-        //!!! Need FFTModel overlap tests to exercise this
-        
-        sv_frame_t off = range.first - m_savedData.range.first;
-                
-        vector<float> acc(m_savedData.data.begin() + off, m_savedData.data.end());
+        sv_frame_t discard = range.first - m_savedData.range.first;
+
+        vector<float> acc(m_savedData.data.begin() + discard,
+                          m_savedData.data.end());
 
         vector<float> rest =
             getSourceDataUncached({ m_savedData.range.second, range.second });
+
+        acc.insert(acc.end(), rest.begin(), rest.end());
         
-        acc.insert(acc.end(), rest.begin(), rest.end());
-
         m_savedData = { range, acc };
         return acc;
 
@@ -279,6 +280,7 @@
 	if (channels > 1) {
             int n = int(data.size());
             float factor = 1.f / float(channels);
+            // use mean instead of sum for fft model input
 	    for (int i = 0; i < n; ++i) {
 		data[i] *= factor;
 	    }
@@ -298,7 +300,7 @@
     }
     
     auto samples = getSourceSamples(n);
-    m_windower.cut(&samples[0]);
+    m_windower.cut(samples.data());
     auto col = m_fft.process(samples);
 
     SavedColumn sc { n, col };
--- a/data/model/FFTModel.h	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/model/FFTModel.h	Mon Jun 15 16:02:58 2015 +0100
@@ -183,8 +183,6 @@
     };
     mutable std::deque<SavedColumn> m_cached;
     size_t m_cacheSize;
-
-    //!!! also optionally cache polar?
 };
 
 #endif
--- a/data/model/WaveFileModel.cpp	Mon Jun 15 15:35:57 2015 +0100
+++ b/data/model/WaveFileModel.cpp	Mon Jun 15 16:02:58 2015 +0100
@@ -189,35 +189,55 @@
 vector<float>
 WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count) const
 {
-    // Always read these directly from the file. 
-    // This is used for e.g. audio playback or input to transforms.
+    // Read directly from the file.  This is used for e.g. audio
+    // playback or input to transforms.
 
 #ifdef DEBUG_WAVE_FILE_MODEL
     cout << "WaveFileModel::getData[" << this << "]: " << channel << ", " << start << ", " << count << ", " << buffer << endl;
 #endif
 
+    int channels = getChannelCount();
+
+    if (channel >= channels) {
+        cerr << "ERROR: WaveFileModel::getData: channel ("
+             << channel << ") >= channel count (" << channels << ")"
+             << endl;
+        return {};
+    }
+
     if (!m_reader || !m_reader->isOK() || count == 0) {
         return {};
     }
 
+    if (start >= m_startFrame) {
+        start -= m_startFrame;
+    } else {
+        if (count <= m_startFrame - start) {
+            return {};
+        } else {
+            count -= (m_startFrame - start);
+            start = 0;
+        }
+    }
+
+    vector<float> interleaved = m_reader->getInterleavedFrames(start, count);
+    if (channels == 1) return interleaved;
+
+    sv_frame_t obtained = interleaved.size() / channels;
+    
+    vector<float> result(obtained, 0.f);
+    
     if (channel != -1) {
         // get a single channel
-        auto data = getMultiChannelData(channel, channel, start, count);
-        if (data.empty()) return {};
-        else return data[0];
-    }
-
-    // channel == -1, mix down all channels
-
-    auto all = getMultiChannelData(0, getChannelCount()-1, start, count);
-    if (all.empty()) return {};
-
-    sv_frame_t n = all[0].size();
-    vector<float> result(n, 0.f);
-
-    for (int c = 0; in_range_for(all, c); ++c) {
-        for (sv_frame_t i = 0; i < n; ++i) {
-            result[i] += all[c][i];
+        for (int i = 0; i < obtained; ++i) {
+            result[i] = interleaved[i * channels + channel];
+        }
+    } else {
+        // channel == -1, mix down all channels
+        for (int c = 0; c < channels; ++c) {
+            for (int i = 0; i < obtained; ++i) {
+                result[i] += interleaved[i * channels + c];
+            }
         }
     }
 
@@ -228,6 +248,9 @@
 WaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
                                    sv_frame_t start, sv_frame_t count) const
 {
+    // Read directly from the file.  This is used for e.g. audio
+    // playback or input to transforms.
+
 #ifdef DEBUG_WAVE_FILE_MODEL
     cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl;
 #endif