diff --git a/examples/audio.cpp b/examples/audio.cpp index 7d5b144e..04eda68f 100644 --- a/examples/audio.cpp +++ b/examples/audio.cpp @@ -68,7 +68,7 @@ struct audio_app { mixer_ = audio::make_mixer(); volume_control_ = audio::volume_stereo(mixer_, 0.5f, 0.5f, 0.1f); - engine_.output()->stream(audio::compressor(volume_control_, audio::from_db(-2.f), 0.95f, 0.002f, 1.f)); + engine_.output()->stream(audio::compressor(volume_control_, audio::from_db(-2.f), 0.95f, 0.002f, 1.f, audio::from_db(1.f))); } void on_key_down(SDL_Keycode key) override diff --git a/libs/audio/include/psemek/audio/effect/compressor.hpp b/libs/audio/include/psemek/audio/effect/compressor.hpp index 032e231c..caf4a53a 100644 --- a/libs/audio/include/psemek/audio/effect/compressor.hpp +++ b/libs/audio/include/psemek/audio/effect/compressor.hpp @@ -6,8 +6,9 @@ namespace psemek::audio { - stream_ptr compressor(stream_ptr stream, float volume_threshold = from_db(-1.f), float strength = 0.9f, float envelope_attack = 0.01f, float envelope_release = 1.f); + stream_ptr compressor(stream_ptr stream, float volume_threshold = from_db(-2.f), float strength = 0.9f, float envelope_attack = 0.01f, float envelope_release = 1.f, + float knee = from_db(1.f)); - stream_ptr limiter(stream_ptr stream, float volume_threshold = from_db(0.f), float envelope_attack = 0.01f, float envelope_release = 1.f); + stream_ptr limiter(stream_ptr stream, float volume_threshold = from_db(0.f), float envelope_attack = 0.01f, float envelope_release = 1.f, float knee = 0.f); } diff --git a/libs/audio/source/effect/compressor.cpp b/libs/audio/source/effect/compressor.cpp index 6db52e8f..5d3552bc 100644 --- a/libs/audio/source/effect/compressor.cpp +++ b/libs/audio/source/effect/compressor.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include namespace psemek::audio { @@ -11,12 +13,13 @@ namespace psemek::audio struct compressor_impl : stream { - compressor_impl(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release) + compressor_impl(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release, float knee) : stream_(std::move(stream)) , volume_threshold_log_(std::log(volume_threshold)) , strength_(strength) , envelope_attack_multiplier_(smoothness_to_multiplier(envelope_attack)) , envelope_release_multiplier_(smoothness_to_multiplier(envelope_release)) + , knee_range_(geom::expand(geom::interval::singleton(volume_threshold_log_), std::log(knee) * 0.5f)) {} std::optional length() const override @@ -38,7 +41,12 @@ namespace psemek::audio float strength = strength_; - float log_gain = strength * std::min(0.f, volume_threshold_log_ - std::log(envelope_)); + float envelope_log = std::log(envelope_); + + if (geom::contains(knee_range_, envelope_log)) + strength *= geom::unlerp(knee_range_, envelope_log); + + float log_gain = strength * std::min(0.f, volume_threshold_log_ - envelope_log); float gain = std::exp(log_gain); @@ -60,19 +68,20 @@ namespace psemek::audio float strength_; float envelope_attack_multiplier_; float envelope_release_multiplier_; + geom::interval knee_range_; float envelope_ = 0.f; }; } - stream_ptr compressor(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release) + stream_ptr compressor(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release, float knee) { - return std::make_shared(std::move(stream), volume_threshold, strength, envelope_attack, envelope_release); + return std::make_shared(std::move(stream), volume_threshold, strength, envelope_attack, envelope_release, knee); } - stream_ptr limiter(stream_ptr stream, float volume_threshold, float envelope_attack, float envelope_release) + stream_ptr limiter(stream_ptr stream, float volume_threshold, float envelope_attack, float envelope_release, float knee) { - return compressor(std::move(stream), volume_threshold, 1.f, envelope_attack, envelope_release); + return compressor(std::move(stream), volume_threshold, 1.f, envelope_attack, envelope_release, knee); } }