From 0dc69ba161bb0c8fce2eb0ab3c5eb897f7aa92a7 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 14 Oct 2017 15:24:36 +0200 Subject: Implemented engine part of the latency filter aka. humized timing. --- src/drumgizmo.cc | 2 +- src/events.h | 2 +- src/inputprocessor.cc | 5 ++-- src/inputprocessor.h | 4 +++- src/latencyfilter.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++++----- src/latencyfilter.h | 10 +++++--- src/settings.h | 23 +++++++++++++++++++ 7 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 9874bbe..d30952e 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -47,7 +47,7 @@ DrumGizmo::DrumGizmo(Settings& settings, , oe(o) , ie(i) , audio_cache(settings) - , input_processor(settings, kit, activeevents) + , input_processor(settings, kit, activeevents, rand) , settings(settings) , settings_getter(settings) { diff --git a/src/events.h b/src/events.h index 30a9e8b..f953031 100644 --- a/src/events.h +++ b/src/events.h @@ -54,7 +54,7 @@ public: virtual type_t getType() const = 0; channel_t channel; - timepos_t offset; + timepos_t offset; //< Global position (ie. not relative to buffer) }; #define NO_RAMPDOWN -1 diff --git a/src/inputprocessor.cc b/src/inputprocessor.cc index 5d96e2d..1dbd79e 100644 --- a/src/inputprocessor.cc +++ b/src/inputprocessor.cc @@ -39,14 +39,15 @@ InputProcessor::InputProcessor(Settings& settings, DrumKit& kit, - std::list* activeevents) + std::list* activeevents, + Random& random) : kit(kit) , activeevents(activeevents) , is_stopping(false) { // Build filter list filters.emplace_back(std::make_unique(settings)); - filters.emplace_back(std::make_unique(settings)); + filters.emplace_back(std::make_unique(settings, random)); } bool InputProcessor::process(std::vector& events, diff --git a/src/inputprocessor.h b/src/inputprocessor.h index fe72292..cf62ea2 100644 --- a/src/inputprocessor.h +++ b/src/inputprocessor.h @@ -37,13 +37,15 @@ #include "inputfilter.h" struct Settings; +class Random; class InputProcessor { public: InputProcessor(Settings& settings, DrumKit& kit, - std::list* activeevents); + std::list* activeevents, + Random& random); bool process(std::vector& events, std::size_t pos, diff --git a/src/latencyfilter.cc b/src/latencyfilter.cc index d83eab6..2f4bfe5 100644 --- a/src/latencyfilter.cc +++ b/src/latencyfilter.cc @@ -26,19 +26,70 @@ */ #include "latencyfilter.h" -LatencyFilter::LatencyFilter(Settings& settings) - //: settings(settings) +#include +#include + +#include "settings.h" +#include "random.h" + +LatencyFilter::LatencyFilter(Settings& settings, Random& random) + : settings(settings) + , random(random) { } -bool LatencyFilter::filter(event_t& events, size_t pos) +bool LatencyFilter::filter(event_t& event, std::size_t pos) { + auto enabled = settings.enable_latency_modifier.load(); + auto latency = settings.latency_max.load(); + auto samplerate = settings.samplerate.load(); + auto latency_laid_back = settings.latency_laid_back.load(); + auto latency_stddev = settings.latency_stddev.load(); + auto latency_regain = settings.latency_regain.load(); + + if(!enabled) + { + return true; + } + + // Assert latency_regain is within range [0; 1]. + assert(latency_regain >= 0.0f && latency_regain <= 1.0f); + + float duration = (pos - latency_last_pos) / samplerate; + latency_offset *= pow(latency_regain, duration); + + latency_last_pos = pos; + + float offset_min = latency * -1.0f; + float offset_max = latency * 1.0f; + + float mean = latency_laid_back; + float stddev = latency_stddev; + + float offset = random.normalDistribution(mean, stddev); + + latency_offset += offset; + + if(latency_offset > offset_max) latency_offset = offset_max; + if(latency_offset < offset_min) latency_offset = offset_min; + + DEBUG(offset, "latency: %d, offset: %f, drift: %f", + (int)latency, offset, latency_offset); + + event.offset += latency; + event.offset += latency_offset;//(int)std::round(offset); + return true; } std::size_t LatencyFilter::getLatency() const { - // TODO: If enabled in settings, return the maximum number of samples - // with which the latency filter can move notes forward. - return 0; + bool enabled = settings.enable_latency_modifier.load(); + std::size_t max_latency = settings.latency_max.load(); + if(enabled) + { + return max_latency; + } + + return 0u; } diff --git a/src/latencyfilter.h b/src/latencyfilter.h index e34b050..a49dd47 100644 --- a/src/latencyfilter.h +++ b/src/latencyfilter.h @@ -29,17 +29,21 @@ #include "inputfilter.h" struct Settings; +class Random; class LatencyFilter : public InputFilter { public: - LatencyFilter(Settings& settings); + LatencyFilter(Settings& settings, Random& random); - bool filter(event_t& events, size_t pos) override; + bool filter(event_t& events, std::size_t pos) override; std::size_t getLatency() const override; private: - //Settings& settings; + Settings& settings; + Random& random; + double latency_offset{0.0}; + std::size_t latency_last_pos{0}; }; diff --git a/src/settings.h b/src/settings.h index 6bba237..cdce066 100644 --- a/src/settings.h +++ b/src/settings.h @@ -90,6 +90,29 @@ struct Settings Atomic enable_bleed_control{false}; Atomic master_bleed{1.0f}; + + Atomic enable_latency_modifier{true}; + + //! Maximum "early hits" introduces latency. In no. samples. + Atomic latency_max{5000u}; + + //! 0 := on-beat + //! positive := laid back + //! negative := up-beat + Atomic latency_laid_back{0}; + + //! 0 := Robot + //! 100 := Good drummer + //! 200 := Decent drummer + //! 300 := Decent drummer on a bad day + //! 400 := Bad drummer + //! 500 := Bad and drunk drummer + Atomic latency_stddev{100.0f}; + + //! Regain on-beat position. + //! 0: instantaniously + //! 1: never + Atomic latency_regain{0.9f}; }; //! Settings getter class. -- cgit v1.2.3