#include #include namespace psemek::audio { namespace { struct echo_impl : stream { echo_impl(stream_ptr stream, duration delay, float gain) : stream_(std::move(stream)) , buffer_(std::max(2l, delay.samples()), 0.f) , gain_(gain) {} std::optional length() const override { return std::nullopt; } std::size_t read(util::span samples) override { auto count = stream_->read(samples); for (std::size_t i = 0; i < count; ++i) { float output = buffer_[buffer_pos_]; buffer_[buffer_pos_] = samples[i] + buffer_[buffer_pos_] * gain_; samples[i] = output; ++buffer_pos_; buffer_pos_ %= buffer_.size(); } for (std::size_t i = count; i < samples.size(); ++i) { samples[i] = buffer_[buffer_pos_]; buffer_[buffer_pos_] = buffer_[buffer_pos_] * gain_; ++buffer_pos_; buffer_pos_ %= buffer_.size(); } return samples.size(); } std::size_t played() const override { return stream_->played(); } private: stream_ptr stream_; std::vector buffer_; std::size_t buffer_pos_ = 0; float gain_; }; } stream_ptr echo(stream_ptr stream, duration delay, float gain) { return std::make_shared(std::move(stream), delay, gain); } }