From 400959b536180cf8912f06dd80b4de077d8f8c74 Mon Sep 17 00:00:00 2001
From: Bent Bisballe Nyeng <deva@aasimon.org>
Date: Mon, 6 Aug 2018 20:20:08 +0200
Subject: New resampler implementation.

---
 src/drumgizmo.cc     | 124 ++++++++++++++++++++++++++++-----------------------
 src/drumgizmo.h      |  16 ++++---
 src/drumkit.cc       |   4 +-
 src/drumkit.h        |   4 +-
 src/drumkitloader.cc |   7 ---
 src/drumkitloader.h  |   3 +-
 6 files changed, 83 insertions(+), 75 deletions(-)

diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc
index 5a201af..e7ebe5a 100644
--- a/src/drumgizmo.cc
+++ b/src/drumgizmo.cc
@@ -43,7 +43,7 @@
 
 DrumGizmo::DrumGizmo(Settings& settings,
                      AudioOutputEngine& o, AudioInputEngine& i)
-	: loader(settings, kit, i, resamplers, rand, audio_cache)
+	: loader(settings, kit, i, rand, audio_cache)
 	, oe(o)
 	, ie(i)
 	, audio_cache(settings)
@@ -54,6 +54,7 @@ DrumGizmo::DrumGizmo(Settings& settings,
 	audio_cache.init(10000); // start thread
 	events.reserve(1000);
 	loader.init();
+	setSamplerate(44100.0f);
 }
 
 DrumGizmo::~DrumGizmo()
@@ -81,12 +82,6 @@ void DrumGizmo::setFrameSize(size_t framesize)
 {
 	settings.buffer_size.store(framesize);
 
-	// If we are resampling override the frame size.
-	if(resamplers.isActive() && enable_resampling)
-	{
-		framesize = RESAMPLER_INPUT_BUFFER;
-	}
-
 	if(this->framesize != framesize)
 	{
 		DEBUG(drumgizmo, "New framesize: %d\n", (int)framesize);
@@ -119,6 +114,12 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
 		enable_resampling = settings_getter.enable_resampling.getValue();
 	}
 
+	if(settings_getter.drumkit_samplerate.hasChanged())
+	{
+		settings_getter.drumkit_samplerate.getValue(); // stage new value
+		setSamplerate(settings.samplerate.load());
+	}
+
 	setFrameSize(nsamples);
 	setFreeWheel(ie.isFreewheeling() && oe.isFreewheeling());
 
@@ -132,7 +133,7 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
 
 	ie.run(pos, nsamples, events);
 
-	double resample_ratio = resamplers.getRatio();
+	double resample_ratio = ratio;
 	if(enable_resampling == false)
 	{
 		resample_ratio = 1.0;
@@ -150,10 +151,10 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
 	//
 	// Write audio
 	//
-#ifdef WITH_RESAMPLER
-	if(!enable_resampling || !resamplers.isActive()) // No resampling needed
+	if(!enable_resampling || ratio == 1.0)
 	{
-#endif
+		// No resampling needed
+
 		for(size_t c = 0; c < kit.channels.size(); ++c)
 		{
 			sample_t *buf = samples;
@@ -176,55 +177,46 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)
 				}
 			}
 		}
-#ifdef WITH_RESAMPLER
 	}
 	else
 	{
 		// Resampling needed
-
-		//
-		// NOTE: Channels must be processed one buffer at a time on all channels in
-		// parallel - NOT all buffers on one channel and then all buffer on the next
-		// one since this would mess up the event queue (it would jump back and
-		// forth in time)
-		//
-
-		// Prepare output buffer
+		size_t kitpos = pos * ratio;
 		for(size_t c = 0; c < kit.channels.size(); ++c)
 		{
-			resamplers[c].setOutputSamples(resampler_output_buffer[c], nsamples);
-		}
+			sample_t *buf = samples;
+			bool internal = false;
+			if(oe.getBuffer(c))
+			{
+				buf = oe.getBuffer(c);
+				internal = true;
+			}
 
-		// Process channel data
-		size_t kitpos = pos * resamplers.getRatio();
-		size_t insize = sizeof(resampler_input_buffer[0]) / sizeof(sample_t);
+			zita[c].out_data = buf;
+			zita[c].out_count = nsamples;
 
-		while(resamplers.getOutputSampleCount() > 0)
-		{
-			for(size_t c = 0; c < kit.channels.size(); ++c)
+			if(zita[c].inp_count > 0)
 			{
-				if(resamplers[c].getInputSampleCount() == 0)
-				{
-					sample_t *sin = resampler_input_buffer[c];
-					memset(resampler_input_buffer[c], 0,
-					       sizeof(resampler_input_buffer[c]));
-					getSamples(c, kitpos, sin, insize);
-
-					resamplers[c].setInputSamples(sin, insize);
-				}
-				resamplers[c].process();
+				// Samples left from last iteration, process that one first
+				zita[c].process();
 			}
-			kitpos += insize;
-		}
 
-		// Write output data to output engine.
-		for(size_t c = 0; c < kit.channels.size(); ++c)
-		{
-			oe.run(c, resampler_output_buffer[c], nsamples);
-		}
+			std::memset(_resampler_input_buffer[c], 0,
+			            sizeof(_resampler_input_buffer[c]));
+
+			zita[c].inp_data = _resampler_input_buffer[c];
+			std::size_t sample_count =
+				std::ceil((nsamples - (nsamples - zita[c].out_count)) * ratio);
+			getSamples(c, kitpos, zita[c].inp_data, sample_count);
 
+			zita[c].inp_count = sample_count;
+			zita[c].process();
+			if(!internal)
+			{
+				oe.run(c, samples, nsamples);
+			}
+		}
 	}
-#endif/*WITH_RESAMPLER*/
 
 	ie.post();
 	oe.post(nsamples);
@@ -395,28 +387,50 @@ void DrumGizmo::stop()
 std::size_t DrumGizmo::getLatency() const
 {
 	auto latency = input_processor.getLatency();
-	if(enable_resampling)
+	if(enable_resampling && ratio != 0.0)
 	{
-		latency += resamplers.getLatency();
+		// TODO:
+		latency += zita[0].inpsize(); // resampler latency
 	}
 
 	return latency;
 }
 
-int DrumGizmo::samplerate()
+float DrumGizmo::samplerate()
 {
 	return settings.samplerate.load();
 }
 
-void DrumGizmo::setSamplerate(int samplerate)
+void DrumGizmo::setSamplerate(float samplerate)
 {
-	DEBUG(dgeditor, "%s samplerate: %d\n", __PRETTY_FUNCTION__, samplerate);
+	DEBUG(dgeditor, "%s samplerate: %f\n", __PRETTY_FUNCTION__, samplerate);
 	settings.samplerate.store(samplerate);
 
 	// Notify input engine of the samplerate change.
 	ie.setSampleRate(samplerate);
 
-#ifdef WITH_RESAMPLER
-	resamplers.setup(kit.getSamplerate(), settings.samplerate.load());
-#endif/*WITH_RESAMPLER*/
+	auto input_fs = kit.getSamplerate();
+	auto output_fs = samplerate;
+	ratio = input_fs / output_fs;
+	settings.resamplig_recommended.store(ratio != 1.0);
+
+	for(int c = 0; c < MAX_NUM_CHANNELS; ++c)
+	{
+		zita[c].reset();
+		auto nchan = 1u; // mono
+		auto hlen = 72u; // 16 ≤ hlen ≤ 96
+		zita[c].setup(input_fs, output_fs, nchan, hlen);
+
+		// Prefill
+		auto null_size = zita[c].inpsize() - 1;// / 2 - 1;
+		zita[c].inp_data = nullptr;
+		zita[c].inp_count = null_size;
+
+		constexpr auto sz = 4096 * 16;
+		sample_t s[sz];
+		zita[c].out_data = s;
+		zita[c].out_count = sz;
+
+		zita[c].process();
+	}
 }
diff --git a/src/drumgizmo.h b/src/drumgizmo.h
index 0f2c20e..2f74062 100644
--- a/src/drumgizmo.h
+++ b/src/drumgizmo.h
@@ -30,6 +30,8 @@
 #include <list>
 #include <array>
 
+#include <zita-resampler/resampler.h>
+
 #include "audiooutputengine.h"
 #include "audioinputengine.h"
 #include "events.h"
@@ -37,7 +39,6 @@
 #include "drumkit.h"
 #include "drumkitloader.h"
 #include "audiocache.h"
-#include "chresampler.h"
 #include "settings.h"
 #include "inputprocessor.h"
 
@@ -62,8 +63,8 @@ public:
 	//! Get the current engine latency in samples.
 	std::size_t getLatency() const;
 
-	int samplerate();
-	void setSamplerate(int samplerate);
+	float samplerate();
+	void setSamplerate(float samplerate);
 
 	void setFrameSize(size_t framesize);
 
@@ -74,7 +75,7 @@ public:
 private:
 	static constexpr int MAX_NUM_CHANNELS = 64;
 	static constexpr int RESAMPLER_OUTPUT_BUFFER = 4096;
-	static constexpr int RESAMPLER_INPUT_BUFFER = 64;
+	static constexpr int RESAMPLER_INPUT_BUFFER = 2048;//64;
 
 protected:
 	DrumKitLoader loader;
@@ -84,9 +85,6 @@ protected:
 
 	std::list< Event* > activeevents[MAX_NUM_CHANNELS];
 
-	Resamplers resamplers;
-	sample_t resampler_output_buffer[MAX_NUM_CHANNELS][RESAMPLER_OUTPUT_BUFFER];
-	sample_t resampler_input_buffer[MAX_NUM_CHANNELS][RESAMPLER_INPUT_BUFFER];
 	bool enable_resampling{true};
 
 	std::map<std::string, AudioFile *> audiofiles;
@@ -103,4 +101,8 @@ protected:
 	SettingsGetter settings_getter;
 
 	Random rand;
+	Resampler zita[MAX_NUM_CHANNELS];
+	sample_t _resampler_input_buffer[MAX_NUM_CHANNELS][4096 * 8];
+	double ratio = 1.0;
+
 };
diff --git a/src/drumkit.cc b/src/drumkit.cc
index e557de1..61fabf6 100644
--- a/src/drumkit.cc
+++ b/src/drumkit.cc
@@ -45,7 +45,7 @@ void DrumKit::clear()
 
 	_name = "";
 	_description = "";
-	_samplerate = 44100;
+	_samplerate = 44100.0f;
 }
 
 bool DrumKit::isValid() const
@@ -73,7 +73,7 @@ VersionStr DrumKit::getVersion() const
 	return _version;
 }
 
-std::size_t DrumKit::getSamplerate() const
+float DrumKit::getSamplerate() const
 {
 	return _samplerate;
 }
diff --git a/src/drumkit.h b/src/drumkit.h
index 0ea5e26..ae3a49b 100644
--- a/src/drumkit.h
+++ b/src/drumkit.h
@@ -53,7 +53,7 @@ public:
 
 	bool isValid() const;
 
-	std::size_t getSamplerate() const;
+	float getSamplerate() const;
 
 	//! Get the number of audio files (as in single channel) in this drumkit.
 	std::size_t getNumberOfFiles() const;
@@ -67,7 +67,7 @@ private:
 
 	std::string _name;
 	std::string _description;
-	std::size_t _samplerate{0};
+	float _samplerate{44100.0f};
 
 	VersionStr _version;
 };
diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc
index e6f4c45..246e79b 100644
--- a/src/drumkitloader.cc
+++ b/src/drumkitloader.cc
@@ -36,14 +36,12 @@
 
 DrumKitLoader::DrumKitLoader(Settings& settings, DrumKit& kit,
                              AudioInputEngine& ie,
-                             Resamplers& resamplers,
                              Random& rand,
                              AudioCache& audio_cache)
 	: settings(settings)
 	, getter(settings)
 	, kit(kit)
 	, ie(ie)
-	, resamplers(resamplers)
 	, rand(rand)
 	, audio_cache(audio_cache)
 {
@@ -136,11 +134,6 @@ bool DrumKitLoader::loadkit(const std::string& file)
 
 	loadKit(&kit);
 
-#ifdef WITH_RESAMPLER
-	resamplers.setup(kit.getSamplerate(), settings.samplerate.load());
-#endif/*WITH_RESAMPLER*/
-	settings.resamplig_recommended.store(resamplers.isActive());
-
 	DEBUG(loadkit, "loadkit: Success\n");
 
 	return true;
diff --git a/src/drumkitloader.h b/src/drumkitloader.h
index 82ab4b5..2758a98 100644
--- a/src/drumkitloader.h
+++ b/src/drumkitloader.h
@@ -50,7 +50,7 @@ class DrumKitLoader
 {
 public:
 	DrumKitLoader(Settings& settings, DrumKit& kit, AudioInputEngine& ie,
-	              Resamplers& resamplers, Random& rand, AudioCache& audio_cache);
+	              Random& rand, AudioCache& audio_cache);
 
 	~DrumKitLoader();
 
@@ -89,7 +89,6 @@ protected:
 	SettingsGetter getter;
 	DrumKit& kit;
 	AudioInputEngine& ie;
-	Resamplers& resamplers;
 	//MemChecker memchecker;
 	Random& rand;
 	AudioCache& audio_cache;
-- 
cgit v1.2.3