From c8b25884550c66ea00f32b9ab9ee75b4f158742f Mon Sep 17 00:00:00 2001
From: John Glover <j@johnglover.net>
Date: Sun, 12 Aug 2012 17:24:42 +0100
Subject: [synthesis] Add C++ implementation of SndObjSynthesis.

---
 simpl/__init__.py       |  17 ++++---
 simpl/mq.py             |   3 +-
 simpl/synthesis.pxd     |   3 ++
 simpl/synthesis.pyx     |  12 +++++
 src/simpl/synthesis.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/simpl/synthesis.h   |  34 ++++++++++++++
 6 files changed, 176 insertions(+), 8 deletions(-)

diff --git a/simpl/__init__.py b/simpl/__init__.py
index de1c3d0..f52224b 100644
--- a/simpl/__init__.py
+++ b/simpl/__init__.py
@@ -11,25 +11,28 @@ import pybase
 dtype = np.double
 Frame = base.Frame
 Peak = base.Peak
+Partial = pybase.Partial
+compare_peak_amps = pybase.compare_peak_amps
+compare_peak_freqs = pybase.compare_peak_freqs
+read_wav = audio.read_wav
+
 PeakDetection = peak_detection.PeakDetection
 SMSPeakDetection = peak_detection.SMSPeakDetection
 SndObjPeakDetection = peak_detection.SndObjPeakDetection
+
 PartialTracking = partial_tracking.PartialTracking
 SMSPartialTracking = partial_tracking.SMSPartialTracking
 SndObjPartialTracking = partial_tracking.SndObjPartialTracking
+
 Synthesis = synthesis.Synthesis
 SMSSynthesis = synthesis.SMSSynthesis
+SndObjSynthesis = synthesis.SndObjSynthesis
+
 Residual = residual.Residual
 SMSResidual = residual.SMSResidual
+
 plot_peaks = plot.plot_peaks
 plot_partials = plot.plot_partials
-read_wav = audio.read_wav
-Partial = pybase.Partial
-compare_peak_amps = pybase.compare_peak_amps
-compare_peak_freqs = pybase.compare_peak_freqs
-
-import pysndobj
-SndObjSynthesis = pysndobj.SndObjSynthesis
 
 import mq
 MQPeakDetection = mq.MQPeakDetection
diff --git a/simpl/mq.py b/simpl/mq.py
index adb326a..3b4a47f 100644
--- a/simpl/mq.py
+++ b/simpl/mq.py
@@ -328,7 +328,8 @@ class MQPartialTracking(simpl.PartialTracking):
                 partials[i] = simpl.Peak()
 
         self._current_frame = frame
-        frame.partials = partials
+        for p in partials:
+            frame.add_partial(p)
         return frame
 
 
diff --git a/simpl/synthesis.pxd b/simpl/synthesis.pxd
index fe49c7b..35d17eb 100644
--- a/simpl/synthesis.pxd
+++ b/simpl/synthesis.pxd
@@ -31,3 +31,6 @@ cdef extern from "../src/simpl/synthesis.h" namespace "simpl":
         int stochastic_type()
         int det_synthesis_type()
         void det_synthesis_type(int new_det_synthesis_type)
+
+    cdef cppclass c_SndObjSynthesis "simpl::SndObjSynthesis"(c_Synthesis):
+        c_SndObjSynthesis()
diff --git a/simpl/synthesis.pyx b/simpl/synthesis.pyx
index 33f98ce..a6f7737 100644
--- a/simpl/synthesis.pyx
+++ b/simpl/synthesis.pyx
@@ -74,3 +74,15 @@ cdef class SMSSynthesis(Synthesis):
     property det_synthesis_type:
         def __get__(self): return (<c_SMSSynthesis*>self.thisptr).det_synthesis_type()
         def __set__(self, int i): (<c_SMSSynthesis*>self.thisptr).det_synthesis_type(i)
+
+
+cdef class SndObjSynthesis(Synthesis):
+    def __cinit__(self):
+        if self.thisptr:
+            del self.thisptr
+        self.thisptr = new c_SndObjSynthesis()
+
+    def __dealloc__(self):
+        if self.thisptr:
+            del self.thisptr
+            self.thisptr = <c_Synthesis*>0
diff --git a/src/simpl/synthesis.cpp b/src/simpl/synthesis.cpp
index 221e60e..43c30b2 100644
--- a/src/simpl/synthesis.cpp
+++ b/src/simpl/synthesis.cpp
@@ -138,3 +138,118 @@ void SMSSynthesis::synth_frame(Frame* frame) {
 
     sms_synthesize(&_data, frame->synth(), &_synth_params);
 }
+
+
+// ---------------------------------------------------------------------------
+// SndObjSynthesis
+// ---------------------------------------------------------------------------
+SimplSndObjAnalysisWrapper::SimplSndObjAnalysisWrapper(int max_partials) {
+    partials.resize(max_partials);
+}
+
+SimplSndObjAnalysisWrapper::~SimplSndObjAnalysisWrapper() {
+    partials.clear();
+}
+
+int SimplSndObjAnalysisWrapper::GetTrackID(int track) {
+    if(track < partials.size()) {
+        return track;
+    }
+    return 0;
+}
+
+int SimplSndObjAnalysisWrapper::GetTracks() {
+    return partials.size();
+}
+
+double SimplSndObjAnalysisWrapper::Output(int pos) {
+    int peak = pos / 3;
+
+    if(peak > partials.size()) {
+        return 0.0;
+    }
+
+    int data_field = pos % 3;
+
+    if(partials[peak]) {
+        if(data_field == 0) {
+            return partials[peak]->amplitude;
+        }
+        else if(data_field == 1) {
+            return partials[peak]->frequency;
+        }
+        return partials[peak]->phase;
+    }
+
+    return 0.0;
+}
+
+SndObjSynthesis::SndObjSynthesis() {
+    _analysis = NULL;
+    _table = NULL;
+    _synth = NULL;
+    reset();
+}
+
+SndObjSynthesis::~SndObjSynthesis() {
+    if(_analysis) {
+        delete _analysis;
+    }
+    if(_table) {
+        delete _table;
+    }
+    if(_synth) {
+        delete _synth;
+    }
+
+    _analysis = NULL;
+    _table = NULL;
+    _synth = NULL;
+}
+
+void SndObjSynthesis::reset() {
+    if(_analysis) {
+        delete _analysis;
+    }
+    if(_table) {
+        delete _table;
+    }
+    if(_synth) {
+        delete _synth;
+    }
+
+    _analysis = new SimplSndObjAnalysisWrapper(_max_partials);
+    _table = new HarmTable(10000, 1, 1, 0.25);
+    _synth = new AdSyn(_analysis, _max_partials, _table, 1, 1, _hop_size);
+}
+
+void SndObjSynthesis::hop_size(int new_hop_size) {
+    _hop_size = new_hop_size;
+    reset();
+}
+
+void SndObjSynthesis::max_partials(int new_max_partials) {
+    _max_partials = new_max_partials;
+    reset();
+}
+
+
+void SndObjSynthesis::synth_frame(Frame* frame) {
+    int num_partials = _max_partials;
+    if(frame->num_partials() < _max_partials) {
+        num_partials = frame->num_partials();
+    }
+
+    for(int i = 0; i < num_partials; i++) {
+        _analysis->partials[i] = frame->partial(i);
+    }
+    for(int i = num_partials; i < _max_partials; i++) {
+        _analysis->partials[i] = NULL;
+    }
+
+    _synth->DoProcess();
+
+    for(int i = 0; i < _hop_size; i++) {
+        frame->synth()[i] = _synth->Output(i);
+    }
+}
diff --git a/src/simpl/synthesis.h b/src/simpl/synthesis.h
index b3efd9c..85dd959 100644
--- a/src/simpl/synthesis.h
+++ b/src/simpl/synthesis.h
@@ -7,6 +7,11 @@ extern "C" {
     #include "sms.h"
 }
 
+#include "SndObj.h"
+#include "HarmTable.h"
+#include "SinAnal.h"
+#include "AdSyn.h"
+
 using namespace std;
 
 namespace simpl
@@ -63,6 +68,35 @@ class SMSSynthesis : public Synthesis {
 };
 
 
+// ---------------------------------------------------------------------------
+// SndObjSynthesis
+// ---------------------------------------------------------------------------
+class SimplSndObjAnalysisWrapper : public SinAnal {
+    public:
+        SimplSndObjAnalysisWrapper(int max_partials);
+        ~SimplSndObjAnalysisWrapper();
+        Peaks partials;
+        int GetTrackID(int track);
+        int GetTracks();
+        double Output(int pos);
+};
+
+
+class SndObjSynthesis : public Synthesis {
+    private:
+        SimplSndObjAnalysisWrapper* _analysis;
+        HarmTable* _table;
+        AdSyn* _synth;
+        void reset();
+
+    public:
+        SndObjSynthesis();
+        ~SndObjSynthesis();
+        void hop_size(int new_hop_size);
+        void max_partials(int new_max_partials);
+        void synth_frame(Frame* frame);
+};
+
 } // end of namespace Simpl
 
 #endif
-- 
cgit v1.2.3