changeset 1086:9f4505ac9072

Tidy dense time-value model API a bit; add first simple unit test for FFT model
author Chris Cannam
date Wed, 10 Jun 2015 17:06:02 +0100
parents bf6f64dabe73
children dcf54a6964d0
files data/fft/FFTDataServer.cpp data/fft/FFTFileCacheReader.cpp data/model/AggregateWaveModel.cpp data/model/AggregateWaveModel.h data/model/DenseTimeValueModel.cpp data/model/DenseTimeValueModel.h data/model/FFTModel.h data/model/WaveFileModel.cpp data/model/WaveFileModel.h data/model/WritableWaveFileModel.cpp data/model/WritableWaveFileModel.h data/model/test/Compares.h data/model/test/MockWaveModel.cpp data/model/test/MockWaveModel.h data/model/test/TestFFTModel.h data/model/test/main.cpp data/model/test/test.pro transform/FeatureExtractionModelTransformer.cpp transform/RealTimeEffectModelTransformer.cpp
diffstat 19 files changed, 414 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/fft/FFTDataServer.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -1270,8 +1270,10 @@
     sv_frame_t startFrame = m_windowIncrement * sv_frame_t(x);
     sv_frame_t endFrame = startFrame + m_windowSize;
 
-    startFrame -= winsize / 2;
-    endFrame   -= winsize / 2;
+    if (m_windowIncrement != winsize) {
+        startFrame -= (winsize - m_windowIncrement);
+        endFrame   -= (winsize - m_windowIncrement);
+    }
 
 #ifdef DEBUG_FFT_SERVER_FILL
     std::cerr << "FFTDataServer::fillColumn: requesting frames "
--- a/data/fft/FFTFileCacheReader.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/fft/FFTFileCacheReader.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -26,7 +26,6 @@
 
 //#define DEBUG_FFT_FILE_CACHE_READER 1
 
-
 // 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
--- a/data/model/AggregateWaveModel.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/AggregateWaveModel.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -137,57 +137,11 @@
     if (mixing) delete[] readbuf;
     return longest;
 }
-         
-sv_frame_t
-AggregateWaveModel::getData(int channel, sv_frame_t start, sv_frame_t count,
-                            double *buffer) const
-{
-    int ch0 = channel, ch1 = channel;
-    bool mixing = false;
-    if (channel == -1) {
-        ch0 = 0;
-        ch1 = getChannelCount()-1;
-        mixing = true;
-    }
-
-    double *readbuf = buffer;
-    if (mixing) {
-        readbuf = new double[count];
-        for (sv_frame_t i = 0; i < count; ++i) {
-            buffer[i] = 0.0;
-        }
-    }
-
-    sv_frame_t longest = 0;
-    
-    for (int c = ch0; c <= ch1; ++c) {
-        sv_frame_t here = 
-            m_components[c].model->getData(m_components[c].channel,
-                                           start, count,
-                                           readbuf);
-        if (here > longest) {
-            longest = here;
-        }
-        if (here < count) {
-            for (sv_frame_t i = here; i < count; ++i) {
-                readbuf[i] = 0.;
-            }
-        }
-        if (mixing) {
-            for (sv_frame_t i = 0; i < count; ++i) {
-                buffer[i] += readbuf[i];
-            }
-        }
-    }
-    
-    if (mixing) delete[] readbuf;
-    return longest;
-}
 
 sv_frame_t
-AggregateWaveModel::getData(int fromchannel, int tochannel,
-                            sv_frame_t start, sv_frame_t count,
-                            float **buffer) const
+AggregateWaveModel::getMultiChannelData(int fromchannel, int tochannel,
+                                        sv_frame_t start, sv_frame_t count,
+                                        float **buffer) const
 {
     sv_frame_t min = count;
 
--- a/data/model/AggregateWaveModel.h	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/AggregateWaveModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -60,14 +60,11 @@
     virtual sv_frame_t getEndFrame() const { return getFrameCount(); }
 
     virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                           float *buffer) const;
+                               float *buffer) const;
 
-    virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                           double *buffer) const;
-
-    virtual sv_frame_t getData(int fromchannel, int tochannel,
-                           sv_frame_t start, sv_frame_t count,
-                           float **buffer) const;
+    virtual sv_frame_t getMultiChannelData(int fromchannel, int tochannel,
+                                           sv_frame_t start, sv_frame_t count,
+                                           float **buffer) const;
 
     virtual int getSummaryBlockSize(int desired) const;
 
--- a/data/model/DenseTimeValueModel.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/DenseTimeValueModel.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -42,7 +42,7 @@
         all[c] = new float[f1 - f0];
     }
 
-    sv_frame_t n = getData(0, ch - 1, f0, f1 - f0, all);
+    sv_frame_t n = getMultiChannelData(0, ch - 1, f0, f1 - f0, all);
 
     QStringList list;
     for (sv_frame_t i = 0; i < n; ++i) {
--- a/data/model/DenseTimeValueModel.h	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/DenseTimeValueModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -66,23 +66,13 @@
                                float *buffer) const = 0;
 
     /**
-     * Get the specified set of samples from the given channel of the
-     * model in double-precision floating-point format.  Return the
-     * number of samples actually retrieved.
-     * If the channel is given as -1, mix all available channels and
-     * return the result.
-     */
-    virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                               double *buffer) const = 0;
-    
-    /**
      * Get the specified set of samples from given contiguous range
      * of channels of the model in single-precision floating-point
      * format.  Return the number of sample frames actually retrieved.
      */
-    virtual sv_frame_t getData(int fromchannel, int tochannel,
-                               sv_frame_t start, sv_frame_t count,
-                               float **buffers) const = 0;
+    virtual sv_frame_t getMultiChannelData(int fromchannel, int tochannel,
+                                           sv_frame_t start, sv_frame_t count,
+                                           float **buffers) const = 0;
 
     virtual bool canPlay() const { return true; }
     virtual QString getDefaultPlayClipId() const { return ""; }
--- a/data/model/FFTModel.h	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/FFTModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -13,8 +13,8 @@
     COPYING included with this distribution for more information.
 */
 
-#ifndef _FFT_MODEL_H_
-#define _FFT_MODEL_H_
+#ifndef FFT_MODEL_H
+#define FFT_MODEL_H
 
 #include "data/fft/FFTDataServer.h"
 #include "DenseThreeDimensionalModel.h"
--- a/data/model/WaveFileModel.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/WaveFileModel.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -252,65 +252,9 @@
 }
 
 sv_frame_t
-WaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
-                       double *buffer) const
-{
-#ifdef DEBUG_WAVE_FILE_MODEL
-    cout << "WaveFileModel::getData(double)[" << 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.0;
-        if (count <= m_startFrame - start) {
-            return 0;
-        } else {
-            count -= (m_startFrame - start);
-            start = 0;
-        }
-    }
-
-    if (!m_reader || !m_reader->isOK() || count == 0) {
-        for (sv_frame_t i = 0; i < count; ++i) buffer[i] = 0.0;
-        return 0;
-    }
-
-    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;
-}
-
-sv_frame_t
-WaveFileModel::getData(int fromchannel, int tochannel,
-                       sv_frame_t start, sv_frame_t count,
-                       float **buffer) const
+WaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
+                                   sv_frame_t start, sv_frame_t count,
+                                   float **buffer) const
 {
 #ifdef DEBUG_WAVE_FILE_MODEL
     cout << "WaveFileModel::getData[" << this << "]: " << fromchannel << "," << tochannel << ", " << start << ", " << count << ", " << buffer << endl;
--- a/data/model/WaveFileModel.h	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/WaveFileModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -63,14 +63,11 @@
     void setStartFrame(sv_frame_t startFrame) { m_startFrame = startFrame; }
 
     virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                        float *buffer) const;
+                               float *buffer) const;
 
-    virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                        double *buffer) const;
-
-    virtual sv_frame_t getData(int fromchannel, int tochannel,
-                        sv_frame_t start, sv_frame_t count,
-                        float **buffers) const;
+    virtual sv_frame_t getMultiChannelData(int fromchannel, int tochannel,
+                                           sv_frame_t start, sv_frame_t count,
+                                           float **buffers) const;
 
     virtual int getSummaryBlockSize(int desired) const;
 
--- a/data/model/WritableWaveFileModel.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/WritableWaveFileModel.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -178,20 +178,12 @@
 }
 
 sv_frame_t
-WritableWaveFileModel::getData(int channel, sv_frame_t start, sv_frame_t count,
-                               double *buffer) const
+WritableWaveFileModel::getMultiChannelData(int fromchannel, int tochannel,
+                                           sv_frame_t start, sv_frame_t count,
+                                           float **buffers) const
 {
     if (!m_model || m_model->getChannelCount() == 0) return 0;
-    return m_model->getData(channel, start, count, buffer);
-}
-
-sv_frame_t
-WritableWaveFileModel::getData(int fromchannel, int tochannel,
-                               sv_frame_t start, sv_frame_t count,
-                               float **buffers) const
-{
-    if (!m_model || m_model->getChannelCount() == 0) return 0;
-    return m_model->getData(fromchannel, tochannel, start, count, buffers);
+    return m_model->getMultiChannelData(fromchannel, tochannel, start, count, buffers);
 }    
 
 int
--- a/data/model/WritableWaveFileModel.h	Wed Jun 10 14:44:09 2015 +0100
+++ b/data/model/WritableWaveFileModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -61,14 +61,11 @@
     void setStartFrame(sv_frame_t startFrame);
 
     virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                           float *buffer) const;
+                               float *buffer) const;
 
-    virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
-                           double *buffer) const;
-
-    virtual sv_frame_t getData(int fromchannel, int tochannel,
-                           sv_frame_t start, sv_frame_t count,
-                           float **buffer) const;
+    virtual sv_frame_t getMultiChannelData(int fromchannel, int tochannel,
+                                           sv_frame_t start, sv_frame_t count,
+                                           float **buffer) const;
 
     virtual int getSummaryBlockSize(int desired) const;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/Compares.h	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,52 @@
+
+#ifndef TEST_COMPARES_H
+#define TEST_COMPARES_H
+
+// These macros are used for comparing generated results, and they
+// aren't always going to be exact. Adding 0.1 to each value gives
+// us a little more fuzz in qFuzzyCompare (which ultimately does
+// the comparison).
+
+#define COMPARE_ZERO(a) \
+    QCOMPARE(a + 0.1, 0.1)
+
+#define COMPARE_ZERO_F(a) \
+    QCOMPARE(a + 0.1f, 0.1f)
+
+#define COMPARE_FUZZIER(a, b) \
+    QCOMPARE(a + 0.1, b + 0.1)
+
+#define COMPARE_FUZZIER_F(a, b) \
+    QCOMPARE(a + 0.1f, b + 0.1f)
+
+#define COMPARE_ALL_TO(a, n) \
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER(a[cmp_i], n); \
+    }
+
+#define COMPARE_ALL(a, b)						\
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER(a[cmp_i], b[cmp_i]); \
+    }
+
+#define COMPARE_SCALED(a, b, s)						\
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER(a[cmp_i] / s, b[cmp_i]); \
+    }
+
+#define COMPARE_ALL_TO_F(a, n) \
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER_F(a[cmp_i], n); \
+    }
+
+#define COMPARE_ALL_F(a, b)						\
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER_F(a[cmp_i], b[cmp_i]); \
+    }
+
+#define COMPARE_SCALED_F(a, b, s)						\
+    for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \
+        COMPARE_FUZZIER_F(a[cmp_i] / s, b[cmp_i]); \
+    }
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/MockWaveModel.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,85 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006 Chris Cannam.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "MockWaveModel.h"
+
+using namespace std;
+
+MockWaveModel::MockWaveModel(vector<Sort> sorts, int length)
+{
+    for (auto sort: sorts) {
+	m_data.push_back(generate(sort, length));
+    }
+}
+
+sv_frame_t
+MockWaveModel::getData(int channel, sv_frame_t start, sv_frame_t count,
+		       float *buffer) const
+{
+    sv_frame_t i = 0;
+
+    cerr << "MockWaveModel::getData(" << channel << "," << start << "," << count << "): ";
+
+    while (i < count) {
+	sv_frame_t idx = start + i;
+	if (!in_range_for(m_data[channel], idx)) break;
+	buffer[i] = m_data[channel][idx];
+	cerr << buffer[i] << " ";
+	++i;
+    }
+
+    cerr << endl;
+    
+    return i;
+}
+
+sv_frame_t
+MockWaveModel::getMultiChannelData(int fromchannel, int tochannel,
+				   sv_frame_t start, sv_frame_t count,
+				   float **buffers) const
+{
+    sv_frame_t min = count;
+
+    for (int c = fromchannel; c <= tochannel; ++c) {
+	sv_frame_t n = getData(c, start, count, buffers[c]);
+	if (n < min) min = n;
+    }
+
+    return min;
+}
+
+vector<float>
+MockWaveModel::generate(Sort sort, int length) const
+{
+    vector<float> data;
+
+    for (int i = 0; i < length; ++i) {
+
+	float v = 0.f;
+	
+	switch (sort) {
+	case DC: v = 1.f; break;
+	case Sine: v = (float)sin((2.0 * M_PI / 8.0) * i); break;
+	case Cosine: v = (float)cos((2.0 * M_PI / 8.0) * i); break;
+	case Nyquist: v = (i % 2) * 2 - 1; break;
+	case Dirac: v = (i == 0) ? 1.f : 0.f; break;
+	}
+
+	data.push_back(v);
+    }
+
+    return data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/MockWaveModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,64 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006 Chris Cannam.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef MOCK_WAVE_MODEL_H
+#define MOCK_WAVE_MODEL_H
+
+#include "../DenseTimeValueModel.h"
+
+#include <vector>
+
+enum Sort {
+    DC,
+    Sine,
+    Cosine,
+    Nyquist,
+    Dirac
+};
+
+class MockWaveModel : public DenseTimeValueModel
+{
+    Q_OBJECT
+
+public:
+    /** One Sort per channel! Length is in samples */
+    MockWaveModel(std::vector<Sort> sorts, int length);
+
+    virtual float getValueMinimum() const { return -1.f; }
+    virtual float getValueMaximum() const { return  1.f; }
+    virtual int getChannelCount() const { return int(m_data.size()); }
+    
+    virtual sv_frame_t getData(int channel, sv_frame_t start, sv_frame_t count,
+                               float *buffer) const;
+    virtual sv_frame_t getMultiChannelData(int fromchannel, int tochannel,
+					   sv_frame_t start, sv_frame_t count,
+					   float **buffers) const;
+
+    virtual bool canPlay() const { return true; }
+    virtual QString getDefaultPlayClipId() const { return ""; }
+
+    virtual sv_frame_t getStartFrame() const { return 0; }
+    virtual sv_frame_t getEndFrame() const { return m_data[0].size(); }
+    virtual sv_samplerate_t getSampleRate() const { return 44100; }
+    virtual bool isOK() const { return true; }
+    
+    QString getTypeName() const { return tr("Mock Wave"); }
+
+private:
+    std::vector<std::vector<float> > m_data;
+    std::vector<float> generate(Sort sort, int length) const;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/TestFFTModel.h	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef TEST_FFT_MODEL_H
+#define TEST_FFT_MODEL_H
+
+#include "../FFTModel.h"
+
+#include "MockWaveModel.h"
+
+#include "Compares.h"
+
+#include <QObject>
+#include <QtTest>
+#include <QDir>
+
+#include <iostream>
+
+using namespace std;
+
+class TestFFTModel : public QObject
+{
+    Q_OBJECT
+
+private slots:
+
+    void example() {
+	MockWaveModel mwm({ DC }, 16);
+	FFTModel fftm(&mwm, 0, RectangularWindow, 8, 8, 8, false);
+	float reals[6], imags[6];
+	reals[5] = 999.f; // overrun guards
+	imags[5] = 999.f;
+	fftm.getValuesAt(0, reals, imags);
+	cerr << "reals: " << reals[0] << "," << reals[1] << "," << reals[2] << "," << reals[3] << "," << reals[4] <<  endl;
+	cerr << "imags: " << imags[0] << "," << imags[1] << "," << imags[2] << "," << imags[3] << "," << imags[4] <<  endl;
+	QCOMPARE(reals[0], 4.f); // rectangular window scales by 0.5
+	QCOMPARE(reals[1], 0.f);
+	QCOMPARE(reals[2], 0.f);
+	QCOMPARE(reals[3], 0.f);
+	QCOMPARE(reals[4], 0.f);
+	QCOMPARE(reals[5], 999.f);
+	QCOMPARE(imags[5], 999.f);
+	imags[5] = 0.f;
+	COMPARE_ALL_TO_F(imags, 0.f);
+    }
+    
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/main.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,44 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#include "TestFFTModel.h"
+
+#include <QtTest>
+
+#include <iostream>
+
+using namespace std;
+
+int main(int argc, char *argv[])
+{
+    int good = 0, bad = 0;
+
+    QCoreApplication app(argc, argv);
+    app.setOrganizationName("Sonic Visualiser");
+    app.setApplicationName("test-model");
+
+    {
+	TestFFTModel t;
+	if (QTest::qExec(&t, argc, argv) == 0) ++good;
+	else ++bad;
+    }
+
+    if (bad > 0) {
+	cerr << "\n********* " << bad << " test suite(s) failed!\n" << endl;
+	return 1;
+    } else {
+	cerr << "All tests passed" << endl;
+	return 0;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/test/test.pro	Wed Jun 10 17:06:02 2015 +0100
@@ -0,0 +1,72 @@
+
+TEMPLATE = app
+
+LIBS += -L../../.. -L../../../../dataquay -L../../../release -L../../../../dataquay/release -lsvcore -ldataquay
+
+win32-g++ {
+    INCLUDEPATH += ../../../../sv-dependency-builds/win32-mingw/include
+    LIBS += -L../../../../sv-dependency-builds/win32-mingw/lib
+}
+win32-msvc* {
+    INCLUDEPATH += ../../../../sv-dependency-builds/win32-msvc/include
+    LIBS += -L../../../../sv-dependency-builds/win32-msvc/lib
+}
+mac* {
+    INCLUDEPATH += ../../../../sv-dependency-builds/osx/include
+    LIBS += -L../../../../sv-dependency-builds/osx/lib
+}
+
+exists(../../../config.pri) {
+    include(../../../config.pri)
+}
+
+!exists(../../../config.pri) {
+
+    CONFIG += release
+    DEFINES += NDEBUG BUILD_RELEASE NO_TIMING
+
+    DEFINES += HAVE_BZ2 HAVE_FFTW3 HAVE_FFTW3F HAVE_SNDFILE HAVE_SAMPLERATE HAVE_VAMP HAVE_VAMPHOSTSDK HAVE_RUBBERBAND HAVE_DATAQUAY HAVE_LIBLO HAVE_MAD HAVE_ID3TAG HAVE_PORTAUDIO_2_0
+
+    LIBS += -lbz2 -lrubberband -lvamp-hostsdk -lfftw3 -lfftw3f -lsndfile -lFLAC -logg -lvorbis -lvorbisenc -lvorbisfile -logg -lmad -lid3tag -lportaudio -lsamplerate -lz -lsord-0 -lserd-0
+
+    win* {
+        LIBS += -llo -lwinmm -lws2_32
+    }
+    macx* {
+        DEFINES += HAVE_COREAUDIO
+        LIBS += -framework CoreAudio -framework CoreMidi -framework AudioUnit -framework AudioToolbox -framework CoreFoundation -framework CoreServices -framework Accelerate
+    }
+}
+
+CONFIG += qt thread warn_on stl rtti exceptions console c++11
+QT += network xml testlib
+QT -= gui
+
+TARGET = svcore-data-model-test
+
+DEPENDPATH += ../../..
+INCLUDEPATH += ../../..
+OBJECTS_DIR = o
+MOC_DIR = o
+
+HEADERS += Compares.h MockWaveModel.h TestFFTModel.h
+SOURCES += MockWaveModel.cpp main.cpp
+
+win* {
+//PRE_TARGETDEPS += ../../../svcore.lib
+}
+!win* {
+PRE_TARGETDEPS += ../../../libsvcore.a
+}
+
+!win32 {
+    !macx* {
+        QMAKE_POST_LINK=./$${TARGET}
+    }
+    macx* {
+        QMAKE_POST_LINK=./$${TARGET}.app/Contents/MacOS/$${TARGET}
+    }
+}
+
+win32:QMAKE_POST_LINK=./release/$${TARGET}.exe
+
--- a/transform/FeatureExtractionModelTransformer.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/transform/FeatureExtractionModelTransformer.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -811,7 +811,8 @@
             }
         }
 
-        got = input->getData(0, channelCount-1, startFrame, size, writebuf);
+        got = input->getMultiChannelData
+            (0, channelCount-1, startFrame, size, writebuf);
 
         if (writebuf != buffers) delete[] writebuf;
     }
--- a/transform/RealTimeEffectModelTransformer.cpp	Wed Jun 10 14:44:09 2015 +0100
+++ b/transform/RealTimeEffectModelTransformer.cpp	Wed Jun 10 17:06:02 2015 +0100
@@ -204,9 +204,9 @@
             }
 	} else {
             if (inbufs && inbufs[0]) {
-                got = input->getData(0, channelCount - 1,
-                                     blockFrame, blockSize,
-                                     inbufs);
+                got = input->getMultiChannelData(0, channelCount - 1,
+                                                 blockFrame, blockSize,
+                                                 inbufs);
                 while (got < blockSize) {
                     for (int ch = 0; ch < channelCount; ++ch) {
                         inbufs[ch][got] = 0.0;