summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2017-10-14 15:24:36 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2018-02-18 11:43:40 +0100
commit0dc69ba161bb0c8fce2eb0ab3c5eb897f7aa92a7 (patch)
treed33fcf6f429124cd551177e3d28aa3ac7bc29272
parent3515fe8b970bd7cd849ea44e24bc01331e894314 (diff)
Implemented engine part of the latency filter aka. humized timing.
-rw-r--r--src/drumgizmo.cc2
-rw-r--r--src/events.h2
-rw-r--r--src/inputprocessor.cc5
-rw-r--r--src/inputprocessor.h4
-rw-r--r--src/latencyfilter.cc63
-rw-r--r--src/latencyfilter.h10
-rw-r--r--src/settings.h23
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<Event*>* activeevents)
+ std::list<Event*>* activeevents,
+ Random& random)
: kit(kit)
, activeevents(activeevents)
, is_stopping(false)
{
// Build filter list
filters.emplace_back(std::make_unique<StaminaFilter>(settings));
- filters.emplace_back(std::make_unique<LatencyFilter>(settings));
+ filters.emplace_back(std::make_unique<LatencyFilter>(settings, random));
}
bool InputProcessor::process(std::vector<event_t>& 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<Event*>* activeevents);
+ std::list<Event*>* activeevents,
+ Random& random);
bool process(std::vector<event_t>& 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 <cmath>
+#include <hugin.hpp>
+
+#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<bool> enable_bleed_control{false};
Atomic<float> master_bleed{1.0f};
+
+ Atomic<bool> enable_latency_modifier{true};
+
+ //! Maximum "early hits" introduces latency. In no. samples.
+ Atomic<std::size_t> latency_max{5000u};
+
+ //! 0 := on-beat
+ //! positive := laid back
+ //! negative := up-beat
+ Atomic<int> 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<float> latency_stddev{100.0f};
+
+ //! Regain on-beat position.
+ //! 0: instantaniously
+ //! 1: never
+ Atomic<float> latency_regain{0.9f};
};
//! Settings getter class.