diff data/model/WaveFileModel.cpp @ 1096:4d9816ba0ebe simple-fft-model

Rework audio file reader API to prefer using std containers
author Chris Cannam
date Mon, 15 Jun 2015 12:19:47 +0100
parents 9f4505ac9072
children 5cbf71022679
line wrap: on
line diff
--- a/data/model/WaveFileModel.cpp	Sat Jun 13 08:47:05 2015 +0100
+++ b/data/model/WaveFileModel.cpp	Mon Jun 15 12:19:47 2015 +0100
@@ -32,6 +32,8 @@
 
 #include <cassert>
 
+using namespace std;
+
 //#define DEBUG_WAVE_FILE_MODEL 1
 
 PowerOfSqrtTwoZoomConstraint
@@ -107,7 +109,7 @@
         if (m_reader) {
             int decodeCompletion = m_reader->getDecodeCompletion();
             if (decodeCompletion < 90) *completion = decodeCompletion;
-            else *completion = std::min(*completion, decodeCompletion);
+            else *completion = min(*completion, decodeCompletion);
         }
         if (*completion != 0 &&
             *completion != 100 &&
@@ -184,77 +186,47 @@
     return "";
 }
     
-sv_frame_t
-WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
-                       float *buffer) const
+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.
-    // Could be much more efficient (although compiler optimisation will help)
+    // 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
 
-    if (start >= m_startFrame) {
-        start -= m_startFrame;
-    } else {
-        for (sv_frame_t i = 0; i < count; ++i) {
-            buffer[i] = 0.f;
-        }
-        if (count <= m_startFrame - start) {
-            return 0;
-        } else {
-            count -= (m_startFrame - start);
-            start = 0;
+    if (!m_reader || !m_reader->isOK() || count == 0) {
+        return {};
+    }
+
+    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];
         }
     }
 
-    if (!m_reader || !m_reader->isOK() || count == 0) {
-        for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.f;
-        return 0;
-    }
-
-#ifdef DEBUG_WAVE_FILE_MODEL
-//    SVDEBUG << "WaveFileModel::getValues(" << channel << ", "
-//              << start << ", " << end << "): calling reader" << endl;
-#endif
-
-    int channels = getChannelCount();
-
-    SampleBlock frames = m_reader->getInterleavedFrames(start, count);
-
-    sv_frame_t i = 0;
-
-    int ch0 = channel, ch1 = channel;
-    if (channel == -1) {
-	ch0 = 0;
-	ch1 = channels - 1;
-    }
-    
-    while (i < count) {
-
-	buffer[i] = 0.0;
-
-	for (int ch = ch0; ch <= ch1; ++ch) {
-
-	    sv_frame_t index = i * channels + ch;
-	    if (index >= (sv_frame_t)frames.size()) break;
-            
-	    float sample = frames[index];
-	    buffer[i] += sample;
-	}
-
-	++i;
-    }
-
-    return i;
+    return result;
 }
 
-sv_frame_t
+vector<vector<float>>
 WaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
-                                   sv_frame_t start, sv_frame_t count,
-                                   float **buffer) const
+                                   sv_frame_t start, sv_frame_t count) const
 {
 #ifdef DEBUG_WAVE_FILE_MODEL
     cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl;
@@ -266,73 +238,47 @@
         cerr << "ERROR: WaveFileModel::getData: fromchannel ("
                   << fromchannel << ") > tochannel (" << tochannel << ")"
                   << endl;
-        return 0;
+        return {};
     }
 
     if (tochannel >= channels) {
         cerr << "ERROR: WaveFileModel::getData: tochannel ("
                   << tochannel << ") >= channel count (" << channels << ")"
                   << endl;
-        return 0;
+        return {};
     }
 
-    if (fromchannel == tochannel) {
-        return getData(fromchannel, start, count, buffer[0]);
+    if (!m_reader || !m_reader->isOK() || count == 0) {
+        return {};
     }
 
     int reqchannels = (tochannel - fromchannel) + 1;
 
-    // Always read these directly from the file. 
-    // This is used for e.g. audio playback.
-    // Could be much more efficient (although compiler optimisation will help)
-
     if (start >= m_startFrame) {
         start -= m_startFrame;
     } else {
-        for (int c = 0; c < reqchannels; ++c) {
-            for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
-        }
         if (count <= m_startFrame - start) {
-            return 0;
+            return {};
         } else {
             count -= (m_startFrame - start);
             start = 0;
         }
     }
 
-    if (!m_reader || !m_reader->isOK() || count == 0) {
-        for (int c = 0; c < reqchannels; ++c) {
-            for (sv_frame_t i = 0; i < count; ++i) buffer[c][i] = 0.f;
+    vector<float> interleaved = m_reader->getInterleavedFrames(start, count);
+    if (channels == 1) return { interleaved };
+
+    sv_frame_t obtained = interleaved.size() / channels;
+    vector<vector<float>> result(reqchannels, vector<float>(obtained, 0.f));
+
+    for (int c = fromchannel; c <= tochannel; ++c) {
+        int destc = c - fromchannel;
+        for (int i = 0; i < obtained; ++i) {
+            result[destc][i] = interleaved[i * channels + c];
         }
-        return 0;
     }
-
-    SampleBlock frames = m_reader->getInterleavedFrames(start, count);
-
-    sv_frame_t i = 0;
-
-    sv_frame_t index = 0, available = frames.size();
-
-    while (i < count) {
-
-        if (index >= available) break;
-
-        int destc = 0;
-
-        for (int c = 0; c < channels; ++c) {
-            
-            if (c >= fromchannel && c <= tochannel) {
-                buffer[destc][i] = frames[index];
-                ++destc;
-            }
-
-            ++index;
-        }
-
-        ++i;
-    }
-
-    return i;
+    
+    return result;
 }
 
 int
@@ -521,16 +467,16 @@
 
     if (blockStart > start) {
         Range startRange = getSummary(channel, start, blockStart - start);
-        range.setMin(std::min(range.min(), startRange.min()));
-        range.setMax(std::max(range.max(), startRange.max()));
-        range.setAbsmean(std::min(range.absmean(), startRange.absmean()));
+        range.setMin(min(range.min(), startRange.min()));
+        range.setMax(max(range.max(), startRange.max()));
+        range.setAbsmean(min(range.absmean(), startRange.absmean()));
     }
 
     if (blockEnd < start + count) {
         Range endRange = getSummary(channel, blockEnd, start + count - blockEnd);
-        range.setMin(std::min(range.min(), endRange.min()));
-        range.setMax(std::max(range.max(), endRange.max()));
-        range.setAbsmean(std::min(range.absmean(), endRange.absmean()));
+        range.setMin(min(range.min(), endRange.min()));
+        range.setMax(max(range.max(), endRange.max()));
+        range.setAbsmean(min(range.absmean(), endRange.absmean()));
     }
 
     return range;
@@ -605,7 +551,7 @@
     
     sv_frame_t frame = 0;
     const sv_frame_t readBlockSize = 16384;
-    SampleBlock block;
+    vector<float> block;
 
     if (!m_model.isOK()) return;