summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--simpl/__init__.py1
-rw-r--r--simpl/partial_tracking.pxd3
-rw-r--r--simpl/partial_tracking.pyx12
-rw-r--r--src/simpl/partial_tracking.cpp98
-rw-r--r--src/simpl/partial_tracking.h41
-rw-r--r--src/simpl/peak_detection.h6
-rw-r--r--tests/test_partial_tracking.cpp65
8 files changed, 228 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c5aa23..1a79a5e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,8 +42,14 @@ install(FILES ${include_files} DESTINATION include/simpl)
# tests
set(test_base_src ${source_files} tests/test_base.cpp)
set(test_peak_detection_src ${source_files} tests/test_peak_detection.cpp)
+set(test_partial_tracking_src ${source_files} tests/test_partial_tracking.cpp)
+
LIST(APPEND libs cppunit sndfile)
+
add_executable(test_base ${test_base_src})
add_executable(test_peak_detection ${test_peak_detection_src})
+add_executable(test_partial_tracking ${test_partial_tracking_src})
+
target_link_libraries(test_base ${libs})
target_link_libraries(test_peak_detection ${libs})
+target_link_libraries(test_partial_tracking ${libs})
diff --git a/simpl/__init__.py b/simpl/__init__.py
index 915d2f6..798e31b 100644
--- a/simpl/__init__.py
+++ b/simpl/__init__.py
@@ -24,6 +24,7 @@ LorisPeakDetection = peak_detection.LorisPeakDetection
PartialTracking = partial_tracking.PartialTracking
SMSPartialTracking = partial_tracking.SMSPartialTracking
SndObjPartialTracking = partial_tracking.SndObjPartialTracking
+LorisPartialTracking = partial_tracking.LorisPartialTracking
Synthesis = synthesis.Synthesis
SMSSynthesis = synthesis.SMSSynthesis
diff --git a/simpl/partial_tracking.pxd b/simpl/partial_tracking.pxd
index bbe9893..69e9821 100644
--- a/simpl/partial_tracking.pxd
+++ b/simpl/partial_tracking.pxd
@@ -30,3 +30,6 @@ cdef extern from "../src/simpl/partial_tracking.h" namespace "simpl":
cdef cppclass c_SndObjPartialTracking "simpl::SndObjPartialTracking"(c_PartialTracking):
c_SndObjPartialTracking()
+
+ cdef cppclass c_LorisPartialTracking "simpl::LorisPartialTracking"(c_PartialTracking):
+ c_LorisPartialTracking()
diff --git a/simpl/partial_tracking.pyx b/simpl/partial_tracking.pyx
index e0599f8..58a0a78 100644
--- a/simpl/partial_tracking.pyx
+++ b/simpl/partial_tracking.pyx
@@ -80,3 +80,15 @@ cdef class SndObjPartialTracking(PartialTracking):
if self.thisptr:
del self.thisptr
self.thisptr = <c_PartialTracking*>0
+
+
+cdef class LorisPartialTracking(PartialTracking):
+ def __cinit__(self):
+ if self.thisptr:
+ del self.thisptr
+ self.thisptr = new c_LorisPartialTracking()
+
+ 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 fdafb84..42df76b 100644
--- a/src/simpl/partial_tracking.cpp
+++ b/src/simpl/partial_tracking.cpp
@@ -304,3 +304,101 @@ Peaks SndObjPartialTracking::update_partials(Frame* frame) {
return peaks;
}
+
+// ---------------------------------------------------------------------------
+// LorisPartialTracking
+// ---------------------------------------------------------------------------
+SimplLorisPTAnalyzer::SimplLorisPTAnalyzer() :
+ Loris::Analyzer(50, 100),
+ _env(1.0) {
+ buildFundamentalEnv(false);
+ _partial_builder = new Loris::PartialBuilder(m_freqDrift, _env);
+}
+
+SimplLorisPTAnalyzer::~SimplLorisPTAnalyzer() {
+ delete _partial_builder;
+}
+
+void SimplLorisPTAnalyzer::analyze() {
+ m_ampEnvBuilder->reset();
+ m_f0Builder->reset();
+ m_partials.clear();
+
+ // estimate the amplitude in this frame:
+ m_ampEnvBuilder->build(peaks, 0);
+
+ // collect amplitudes and frequencies and try to
+ // estimate the fundamental
+ m_f0Builder->build(peaks, 0);
+
+ // form Partials from the extracted Breakpoints:
+ _partial_builder->buildPartials(peaks, 0);
+
+ // unwarp the Partial frequency envelopes:
+ _partial_builder->finishBuilding(m_partials);
+}
+
+// ---------------------------------------------------------------------------
+
+LorisPartialTracking::LorisPartialTracking() {
+ _analyzer = NULL;
+ reset();
+}
+
+LorisPartialTracking::~LorisPartialTracking() {
+ if(_analyzer) {
+ delete _analyzer;
+ }
+}
+
+void LorisPartialTracking::reset() {
+ if(_analyzer) {
+ delete _analyzer;
+ }
+ _analyzer = new SimplLorisPTAnalyzer();
+}
+
+void LorisPartialTracking::max_partials(int new_max_partials) {
+ _max_partials = new_max_partials;
+ reset();
+}
+
+Peaks LorisPartialTracking::update_partials(Frame* frame) {
+ int num_peaks = frame->num_peaks();
+ if(num_peaks > _max_partials) {
+ num_peaks = _max_partials;
+ }
+
+ Peaks peaks;
+
+ _analyzer->peaks.clear();
+ for(int i = 0; i < num_peaks; i++) {
+ Loris::Breakpoint bp = Loris::Breakpoint(frame->peak(i)->frequency,
+ frame->peak(i)->amplitude,
+ frame->peak(i)->bandwidth,
+ frame->peak(i)->phase);
+ _analyzer->peaks.push_back(Loris::SpectralPeak(1, bp));
+ }
+
+ _analyzer->analyze();
+ _partials = _analyzer->partials();
+ int num_partials = _partials.size();
+
+ for(Loris::PartialListIterator i = _partials.begin(); i != _partials.end(); ++i) {
+ Peak* p = new Peak();
+ p->amplitude = i->amplitudeAt(1);
+ p->frequency = i->frequencyAt(1);
+ p->phase = i->phaseAt(1);
+ p->bandwidth = i->bandwidthAt(1);
+ 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);
+ }
+
+ return peaks;
+}
diff --git a/src/simpl/partial_tracking.h b/src/simpl/partial_tracking.h
index 4491b42..b9f2d28 100644
--- a/src/simpl/partial_tracking.h
+++ b/src/simpl/partial_tracking.h
@@ -12,6 +12,15 @@ extern "C" {
#include "IFGram.h"
#include "SinAnal.h"
+#include "Analyzer.h"
+#include "AssociateBandwidth.h"
+#include "BreakpointEnvelope.h"
+#include "KaiserWindow.h"
+#include "PartialBuilder.h"
+#include "PartialList.h"
+#include "ReassignedSpectrum.h"
+#include "SpectralPeakSelector.h"
+
using namespace std;
namespace simpl
@@ -72,6 +81,7 @@ class SMSPartialTracking : public PartialTracking {
Peaks update_partials(Frame* frame);
};
+
// ---------------------------------------------------------------------------
// SndObjPartialTracking
// ---------------------------------------------------------------------------
@@ -93,7 +103,36 @@ class SndObjPartialTracking : public PartialTracking {
Peaks update_partials(Frame* frame);
};
+// ---------------------------------------------------------------------------
+// LorisPartialTracking
+// ---------------------------------------------------------------------------
+class SimplLorisPTAnalyzer : public Loris::Analyzer {
+ protected:
+ Loris::BreakpointEnvelope _env;
+ Loris::PartialBuilder* _partial_builder;
+
+ public:
+ SimplLorisPTAnalyzer();
+ ~SimplLorisPTAnalyzer();
+ Loris::Peaks peaks;
+ void analyze();
+};
+
+
+class LorisPartialTracking : public PartialTracking {
+ private:
+ SimplLorisPTAnalyzer* _analyzer;
+ Loris::PartialList _partials;
+ void reset();
+
+ public:
+ LorisPartialTracking();
+ ~LorisPartialTracking();
+ void max_partials(int new_max_partials);
+ Peaks update_partials(Frame* frame);
+};
+
-} // end of namespace Simpl
+} // end of namespace simpl
#endif
diff --git a/src/simpl/peak_detection.h b/src/simpl/peak_detection.h
index 30c9225..398c2bf 100644
--- a/src/simpl/peak_detection.h
+++ b/src/simpl/peak_detection.h
@@ -13,12 +13,12 @@ extern "C" {
#include "SinAnal.h"
#include "Analyzer.h"
+#include "AssociateBandwidth.h"
+#include "BreakpointEnvelope.h"
#include "KaiserWindow.h"
+#include "PartialBuilder.h"
#include "ReassignedSpectrum.h"
#include "SpectralPeakSelector.h"
-#include "PartialBuilder.h"
-#include "AssociateBandwidth.h"
-#include "BreakpointEnvelope.h"
using namespace std;
diff --git a/tests/test_partial_tracking.cpp b/tests/test_partial_tracking.cpp
new file mode 100644
index 0000000..25fcfff
--- /dev/null
+++ b/tests/test_partial_tracking.cpp
@@ -0,0 +1,65 @@
+#include <iostream>
+#include <cppunit/ui/text/TextTestRunner.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/BriefTestProgressListener.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <sndfile.hh>
+
+#include "../src/simpl/base.h"
+#include "../src/simpl/peak_detection.h"
+#include "../src/simpl/partial_tracking.h"
+
+namespace simpl
+{
+
+// ---------------------------------------------------------------------------
+// TestLorisPartialTracking
+// ---------------------------------------------------------------------------
+class TestLorisPartialTracking : public CPPUNIT_NS::TestCase {
+ CPPUNIT_TEST_SUITE(TestLorisPartialTracking);
+ CPPUNIT_TEST(test_basic);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ static const double PRECISION = 0.001;
+ LorisPeakDetection* pd;
+ LorisPartialTracking* pt;
+ SndfileHandle sf;
+ int num_samples;
+
+ void test_basic() {
+ sample* audio = new sample[(int)sf.frames()];
+ sf.read(audio, (int)sf.frames());
+ Frames frames = pd->find_peaks(num_samples, &(audio[(int)sf.frames() / 2]));
+ frames = pt->find_partials(frames);
+
+ for(int i = 0; i < frames.size(); i++) {
+ CPPUNIT_ASSERT(frames[i]->num_peaks() > 0);
+ CPPUNIT_ASSERT(frames[i]->num_partials() > 0);
+ }
+ }
+
+public:
+ void setUp() {
+ pd = new LorisPeakDetection();
+ pt = new LorisPartialTracking();
+ sf = SndfileHandle("../tests/audio/flute.wav");
+ num_samples = 4096;
+ }
+
+ void tearDown() {
+ delete pd;
+ }
+};
+
+} // end of namespace simpl
+
+CPPUNIT_TEST_SUITE_REGISTRATION(simpl::TestLorisPartialTracking);
+
+int main(int arg, char **argv) {
+ CppUnit::TextTestRunner runner;
+ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
+ return runner.run("", false);
+}