diff --git a/libs/audio/include/psemek/audio/effect/filter.hpp b/libs/audio/include/psemek/audio/effect/filter.hpp index 72f4081e..6d65bb52 100644 --- a/libs/audio/include/psemek/audio/effect/filter.hpp +++ b/libs/audio/include/psemek/audio/effect/filter.hpp @@ -5,9 +5,12 @@ namespace psemek::audio { - // Turns x[n] into a0*x[n] + a1*x[n-1] + // Turns x[n] into y[n] = a0*x[n] + a1*x[n-1] stream_ptr feedforward_filter(stream_ptr stream, float a0, float a1); + // Turns x[n] into y[n] = a0*x[n] + b1*y[n-1] + stream_ptr feedback_filter(stream_ptr stream, float a0, float b1); + stream_ptr low_pass_filter(stream_ptr stream); stream_ptr high_pass_filter(stream_ptr stream); diff --git a/libs/audio/source/effect/filter.cpp b/libs/audio/source/effect/filter.cpp index 8d5892e9..d54b496a 100644 --- a/libs/audio/source/effect/filter.cpp +++ b/libs/audio/source/effect/filter.cpp @@ -48,6 +48,47 @@ namespace psemek::audio float prev_[2]{0.f}; }; + struct feedback_filter_impl + : stream + { + feedback_filter_impl(stream_ptr stream, float a0, float b1) + : stream_(std::move(stream)) + , a0_(a0) + , b1_(b1) + {} + + std::optional length() const override + { + return stream_->length(); + } + + std::size_t read(util::span samples) override + { + std::size_t count = stream_->read(samples); + + for (std::size_t i = 0; i < count; i += 2) + { + samples[i + 0] = prev_[0] * b1_ + samples[i + 0] * a0_; + samples[i + 1] = prev_[1] * b1_ + samples[i + 1] * a0_; + prev_[0] = samples[i + 0]; + prev_[1] = samples[i + 1]; + } + + return count; + } + + std::size_t played() const override + { + return stream_->played(); + } + + private: + stream_ptr stream_; + float a0_; + float b1_; + float prev_[2]{0.f}; + }; + } stream_ptr feedforward_filter(stream_ptr stream, float a0, float a1) @@ -55,6 +96,11 @@ namespace psemek::audio return std::make_shared(std::move(stream), a0, a1); } + stream_ptr feedback_filter(stream_ptr stream, float a0, float b1) + { + return std::make_shared(std::move(stream), a0, b1); + } + stream_ptr low_pass_filter(stream_ptr stream) { return feedforward_filter(std::move(stream), 1.f, 1.f);