From 59f83aec127d98fd05bbc1dbaf01d0ec3f3620d3 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 7 Oct 2022 11:18:38 +0300 Subject: [PATCH] Add audio compressor --- .../psemek/audio/effect/compressor.hpp | 13 ++++ libs/audio/source/effect/compressor.cpp | 78 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 libs/audio/include/psemek/audio/effect/compressor.hpp create mode 100644 libs/audio/source/effect/compressor.cpp diff --git a/libs/audio/include/psemek/audio/effect/compressor.hpp b/libs/audio/include/psemek/audio/effect/compressor.hpp new file mode 100644 index 00000000..032e231c --- /dev/null +++ b/libs/audio/include/psemek/audio/effect/compressor.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +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 limiter(stream_ptr stream, float volume_threshold = from_db(0.f), float envelope_attack = 0.01f, float envelope_release = 1.f); + +} diff --git a/libs/audio/source/effect/compressor.cpp b/libs/audio/source/effect/compressor.cpp new file mode 100644 index 00000000..6db52e8f --- /dev/null +++ b/libs/audio/source/effect/compressor.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +namespace psemek::audio +{ + + namespace + { + + struct compressor_impl + : stream + { + compressor_impl(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release) + : 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)) + {} + + std::optional length() const override + { + return stream_->length(); + } + + std::size_t read(float * data, std::size_t sample_count) override + { + auto result = stream_->read(data, sample_count); + + for (std::size_t i = 0; i < result; i += 2) + { + float v = std::max(std::abs(data[i]), std::abs(data[i + 1])); + + float multiplier = (v > envelope_) ? envelope_attack_multiplier_ : envelope_release_multiplier_; + + envelope_ += (v - envelope_) * multiplier; + + float strength = strength_; + + float log_gain = strength * std::min(0.f, volume_threshold_log_ - std::log(envelope_)); + + float gain = std::exp(log_gain); + + data[i + 0] *= gain; + data[i + 1] *= gain; + } + + return result; + } + + std::size_t played() const override + { + return stream_->played(); + } + + private: + stream_ptr stream_; + float volume_threshold_log_; + float strength_; + float envelope_attack_multiplier_; + float envelope_release_multiplier_; + float envelope_ = 0.f; + }; + + } + + stream_ptr compressor(stream_ptr stream, float volume_threshold, float strength, float envelope_attack, float envelope_release) + { + return std::make_shared(std::move(stream), volume_threshold, strength, envelope_attack, envelope_release); + } + + stream_ptr limiter(stream_ptr stream, float volume_threshold, float envelope_attack, float envelope_release) + { + return compressor(std::move(stream), volume_threshold, 1.f, envelope_attack, envelope_release); + } + +}