diff options
-rw-r--r-- | simpl/partial_tracking.pxd | 3 | ||||
-rw-r--r-- | simpl/partial_tracking.pyx | 12 | ||||
-rw-r--r-- | src/simpl/partial_tracking.cpp | 94 | ||||
-rw-r--r-- | src/simpl/partial_tracking.h | 26 | ||||
-rw-r--r-- | tests/create_test_data.py | 2 | ||||
-rw-r--r-- | tests/test_partial_tracking.py | 66 |
6 files changed, 202 insertions, 1 deletions
diff --git a/simpl/partial_tracking.pxd b/simpl/partial_tracking.pxd index 398ff14..bbe9893 100644 --- a/simpl/partial_tracking.pxd +++ b/simpl/partial_tracking.pxd @@ -27,3 +27,6 @@ cdef extern from "../src/simpl/partial_tracking.h" namespace "simpl": cdef cppclass c_SMSPartialTracking "simpl::SMSPartialTracking"(c_PartialTracking): c_SMSPartialTracking() + + cdef cppclass c_SndObjPartialTracking "simpl::SndObjPartialTracking"(c_PartialTracking): + c_SndObjPartialTracking() diff --git a/simpl/partial_tracking.pyx b/simpl/partial_tracking.pyx index 69053a3..e0599f8 100644 --- a/simpl/partial_tracking.pyx +++ b/simpl/partial_tracking.pyx @@ -68,3 +68,15 @@ cdef class SMSPartialTracking(PartialTracking): if self.thisptr: del self.thisptr self.thisptr = <c_PartialTracking*>0 + + +cdef class SndObjPartialTracking(PartialTracking): + def __cinit__(self): + if self.thisptr: + del self.thisptr + self.thisptr = new c_SndObjPartialTracking() + + def __dealloc__(self): + if self.thisptr: + del self.thisptr + self.thisptr = <c_PartialTracking*>0 diff --git a/src/simpl/partial_tracking.cpp b/src/simpl/partial_tracking.cpp index 34da931..27b7e12 100644 --- a/src/simpl/partial_tracking.cpp +++ b/src/simpl/partial_tracking.cpp @@ -189,7 +189,101 @@ Peaks SMSPartialTracking::update_partials(Frame* frame) { p->frequency = _data.pFSinFreq[i]; p->phase = _data.pFSinPha[i]; peaks.push_back(p); + frame->add_partial(p); + } + + return peaks; +} + +// --------------------------------------------------------------------------- +// SndObjPartialTracking +// --------------------------------------------------------------------------- + +SndObjPartialTracking::SndObjPartialTracking() { + _threshold = 0.003; + _num_bins = 1025; + _input = new SndObj(); + _analysis = new SinAnal(_input, _num_bins, _threshold, _max_partials); + _peak_amplitude = NULL; + _peak_frequency = NULL;; + _peak_phase = NULL; + init_peaks(); +} + +SndObjPartialTracking::~SndObjPartialTracking() { + delete _input; + delete _analysis; + + _input = NULL; + _analysis = NULL; + + delete [] _peak_amplitude; + delete [] _peak_frequency; + delete [] _peak_phase; + + _peak_amplitude = NULL; + _peak_frequency = NULL;; + _peak_phase = NULL; +} + +void SndObjPartialTracking::init_peaks() { + if(_peak_amplitude) { + delete [] _peak_amplitude; + } + if(_peak_frequency) { + delete [] _peak_frequency; + } + if(_peak_phase) { + delete [] _peak_phase; + } + + _peak_amplitude = new sample[_max_partials]; + _peak_frequency = new sample[_max_partials]; + _peak_phase = new sample[_max_partials]; + + memset(_peak_amplitude, 0.0, sizeof(sample) * _max_partials); + memset(_peak_frequency, 0.0, sizeof(sample) * _max_partials); + memset(_peak_phase, 0.0, sizeof(sample) * _max_partials); +} + +void SndObjPartialTracking::max_partials(int new_max_partials) { + _max_partials = new_max_partials; + _analysis->Set("max tracks", new_max_partials); +} + +Peaks SndObjPartialTracking::update_partials(Frame* frame) { + int num_peaks = _max_partials; + if(num_peaks > frame->num_peaks()) { + num_peaks = frame->num_peaks(); + } + + for(int i = 0; i < num_peaks; i++) { + _peak_amplitude[i] = frame->peak(i)->amplitude; + _peak_frequency[i] = frame->peak(i)->frequency; + _peak_phase[i] = frame->peak(i)->phase; + } + + _analysis->SetPeaks(_max_partials, _peak_amplitude, + _max_partials, _peak_frequency, + _max_partials, _peak_phase); + _analysis->PartialTracking(); + + int num_partials = _analysis->GetTracks(); + Peaks peaks; + + for(int i = 0; i < num_partials; i++) { + Peak* p = new Peak(); + p->amplitude = _analysis->Output(i * 3); + p->frequency = _analysis->Output((i * 3) + 1); + p->phase = _analysis->Output((i * 3) + 2); + peaks.push_back(p); + frame->add_partial(p); + } + + for(int i = num_partials; i < _max_partials; i++) { + Peak* p = new Peak(); + peaks.push_back(p); frame->add_partial(p); } diff --git a/src/simpl/partial_tracking.h b/src/simpl/partial_tracking.h index 964d959..f94886e 100644 --- a/src/simpl/partial_tracking.h +++ b/src/simpl/partial_tracking.h @@ -7,6 +7,11 @@ extern "C" { #include "sms.h" } +#include "SndObj.h" +#include "HammingTable.h" +#include "IFGram.h" +#include "SinAnal.h" + using namespace std; namespace simpl @@ -67,6 +72,27 @@ class SMSPartialTracking : public PartialTracking { Peaks update_partials(Frame* frame); }; +// --------------------------------------------------------------------------- +// SndObjPartialTracking +// --------------------------------------------------------------------------- +class SndObjPartialTracking : public PartialTracking { + private: + sample _threshold; + int _num_bins; + SndObj* _input; + SinAnal* _analysis; + sample* _peak_amplitude; + sample* _peak_frequency; + sample* _peak_phase; + void init_peaks(); + + public: + SndObjPartialTracking(); + ~SndObjPartialTracking(); + void max_partials(int new_max_partials); + Peaks update_partials(Frame* frame); +}; + } // end of namespace Simpl diff --git a/tests/create_test_data.py b/tests/create_test_data.py index 0bb1567..b44a855 100644 --- a/tests/create_test_data.py +++ b/tests/create_test_data.py @@ -333,7 +333,7 @@ def sndobj_partial_tracking(): frames = [] i = 0 - while i < len(audio) - hop_size: + while (i < len(audio) - hop_size) and len(frames) < num_frames: frame = np.asarray(audio[i:i + frame_size], dtype=np.float32) input.PushIn(frame) ifgram.DoProcess() diff --git a/tests/test_partial_tracking.py b/tests/test_partial_tracking.py index cab6b2b..69e2548 100644 --- a/tests/test_partial_tracking.py +++ b/tests/test_partial_tracking.py @@ -7,8 +7,10 @@ import simpl.partial_tracking as partial_tracking PeakDetection = peak_detection.PeakDetection SMSPeakDetection = peak_detection.SMSPeakDetection +SndObjPeakDetection = peak_detection.SndObjPeakDetection PartialTracking = partial_tracking.PartialTracking SMSPartialTracking = partial_tracking.SMSPartialTracking +SndObjPartialTracking = partial_tracking.SndObjPartialTracking float_precision = 2 frame_size = 512 @@ -23,6 +25,9 @@ audio_path = os.path.join( libsms_test_data_path = os.path.join( os.path.dirname(__file__), 'libsms_test_data.json' ) +sndobj_test_data_path = os.path.join( + os.path.dirname(__file__), 'sndobj_test_data.json' +) def _load_libsms_test_data(): @@ -32,6 +37,13 @@ def _load_libsms_test_data(): return test_data +def _load_sndobj_test_data(): + test_data = None + with open(sndobj_test_data_path, 'r') as f: + test_data = json.loads(f.read()) + return test_data + + class TestPartialTracking(object): @classmethod def setup_class(cls): @@ -99,3 +111,57 @@ class TestSMSPartialTracking(object): assert_almost_equals(frames[i].partials[p].phase, sms_frames[i]['partials'][p]['phase'], float_precision) + + +class TestSndObjPartialTracking(object): + @classmethod + def setup_class(cls): + cls.audio = simpl.read_wav(audio_path)[0] + cls.audio = cls.audio[0:num_samples] + cls.test_data = _load_sndobj_test_data() + + def test_basic(self): + pd = SndObjPeakDetection() + pd.hop_size = hop_size + pd.frame_size = hop_size + pd.max_peaks = max_peaks + frames = pd.find_peaks(self.audio) + + pt = SndObjPartialTracking() + pt.max_partials = max_partials + frames = pt.find_partials(frames) + + assert len(frames[0].partials) == max_partials + assert frames[0].max_partials == max_partials + + def test_partial_tracking(self): + pd = SndObjPeakDetection() + pd.max_peaks = max_peaks + pd.frame_size = hop_size + pd.hop_size = hop_size + peaks = pd.find_peaks(self.audio) + pt = SndObjPartialTracking() + pt.max_partials = max_partials + frames = pt.find_partials(peaks) + + sndobj_frames = self.test_data['partial_tracking'] + + assert len(sndobj_frames) == len(frames), \ + (len(sndobj_frames), len(frames)) + + for i in range(len(frames)): + print sndobj_frames[i] + assert len(frames[i].partials) == len(sndobj_frames[i]) + + for p in range(len(frames[i].partials)): + partial = frames[i].partials[p] + sndobj_partial = sndobj_frames[i][p] + assert_almost_equals(partial.amplitude, + sndobj_partial['amplitude'], + float_precision) + assert_almost_equals(partial.frequency, + sndobj_partial['frequency'], + float_precision) + assert_almost_equals(partial.phase, + sndobj_partial['phase'], + float_precision) |