From 47adc0e3e96b7845f71fc1ce029833908fe8d8dc Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Mon, 8 Feb 2021 18:42:44 +0100 Subject: WIP: PoC on stereo map feature. --- src/DGDOM.h | 2 ++ src/channel.h | 2 ++ src/dgxmlparser.cc | 9 ++++++++- src/domloader.cc | 2 ++ src/drumgizmo.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/settings.h | 9 +++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/DGDOM.h b/src/DGDOM.h index 474b29c..7d2bbc6 100644 --- a/src/DGDOM.h +++ b/src/DGDOM.h @@ -87,6 +87,8 @@ struct InstrumentDOM struct ChannelDOM { std::string name; + double stereo_panning; + double stereo_volume; }; struct ChannelMapDOM diff --git a/src/channel.h b/src/channel.h index aaa2843..fcc43e7 100644 --- a/src/channel.h +++ b/src/channel.h @@ -47,6 +47,8 @@ public: Channel(const std::string& name = ""); std::string name; + double stereo_panning; //! [-1; 1] where -1 i left, 0 is center and 1 is right + double stereo_volume; //! [0; 1] volume scalar channel_t num; }; diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc index 0d3cdcd..983c2fd 100644 --- a/src/dgxmlparser.cc +++ b/src/dgxmlparser.cc @@ -256,7 +256,14 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom, LogFunction for(pugi::xml_node channel: channels.children("channel")) { dom.channels.emplace_back(); - res &= attrcpy(dom.channels.back().name, channel, "name", logger, filename); + auto& ch = dom.channels.back(); + res &= attrcpy(ch.name, channel, "name", logger, filename); + ch.stereo_panning = 0.0f; + ch.stereo_volume = 1.0f; + res &= attrcpy(ch.stereo_panning, channel, "stereo_panning", + logger, filename, true); + res &= attrcpy(ch.stereo_volume, channel, "stereo_volume", + logger, filename, true); } pugi::xml_node instruments = doc.child("drumkit").child("instruments"); diff --git a/src/domloader.cc b/src/domloader.cc index c78ed75..bc5eea1 100644 --- a/src/domloader.cc +++ b/src/domloader.cc @@ -65,6 +65,8 @@ bool DOMLoader::loadDom(const std::string& basepath, { drumkit.channels.emplace_back(); drumkit.channels.back().name = channel.name; + drumkit.channels.back().stereo_panning = channel.stereo_panning; + drumkit.channels.back().stereo_volume = channel.stereo_volume; drumkit.channels.back().num = drumkit.channels.size() - 1; } diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index ca91c12..a67dace 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -185,6 +185,63 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) // // Write audio // + if(settings.enable_stereo_mode) + { + static sample_t left[4096]; + static sample_t right[4096]; + std::memset(left, 0, sizeof(left)); + std::memset(right, 0, sizeof(right)); + for(size_t c = 0; c < kit.channels.size(); ++c) + { + const auto& channel = kit.channels[c]; + (void)channel; + const auto pan = channel.stereo_panning * 0.5 + 0.5; // -> [0; 1] + const auto scale = channel.stereo_volume; + static sample_t buf[4096]; + std::memset(buf, 0, sizeof(buf)); + getSamples(c, pos, buf, nsamples); + for(auto i = 0u; i < nsamples; ++i) + { + left[i] += buf[i] * pan * scale; + right[i] += buf[i] * (1 - pan) * scale; + } + } + + for(size_t c = 0; c < kit.channels.size(); ++c) + { + sample_t *buf = samples; + bool internal = false; + if(oe.getBuffer(c)) + { + buf = oe.getBuffer(c); + internal = true; + } + + if(buf) + { + if(c == 0) // left channel + { + memcpy(buf, left, nsamples * sizeof(sample_t)); + } + else if(c == 1) // right channel + { + memcpy(buf, right, nsamples * sizeof(sample_t)); + } + else + { + std::memset(buf, 0, nsamples * sizeof(sample_t)); + } + + if(!internal) + { + oe.run(c, samples, nsamples); + } + } + } + + } + else + { if(!enable_resampling || ratio == 1.0) { // No resampling needed @@ -250,6 +307,7 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) } } } + } ie.post(); oe.post(nsamples); diff --git a/src/settings.h b/src/settings.h index 7507827..39c3534 100644 --- a/src/settings.h +++ b/src/settings.h @@ -174,6 +174,8 @@ struct Settings // Time it takes for an old sample to completely fall silent. static float constexpr voice_limit_rampdown_default = 0.5f; Atomic voice_limit_rampdown{voice_limit_rampdown_default}; + + Atomic enable_stereo_mode{true}; }; //! Settings getter class. @@ -256,6 +258,8 @@ struct SettingsGetter SettingRef voice_limit_max; SettingRef voice_limit_rampdown; + SettingRef enable_stereo_mode; + SettingsGetter(Settings& settings) : drumkit_file(settings.drumkit_file) , drumkit_load_status(settings.drumkit_load_status) @@ -316,6 +320,7 @@ struct SettingsGetter , enable_voice_limit{settings.enable_voice_limit} , voice_limit_max{settings.voice_limit_max} , voice_limit_rampdown{settings.voice_limit_rampdown} + , enable_stereo_mode{settings.enable_stereo_mode} { } }; @@ -399,6 +404,8 @@ public: Notifier voice_limit_max; Notifier voice_limit_rampdown; + Notifier enable_stereo_mode; + void evaluate() { #define EVAL(x) if(settings.x.hasChanged()) { x(settings.x.getValue()); } @@ -477,6 +484,8 @@ public: EVAL(enable_voice_limit); EVAL(voice_limit_max); EVAL(voice_limit_rampdown); + + EVAL(enable_stereo_mode); } SettingsNotifier(Settings& settings) -- cgit v1.2.3