#include #include #include #include #include namespace psemek::audio { namespace { struct echo_impl : audio::effect { echo_impl(float delay, float volume) : delay_(delay) , volume_(volume) {} void init(int frequency, int channels) override { int sample_count = std::round(delay_ * frequency) * channels; samples_.reserve(sample_count); } std::string_view name() const override { return "echo"; } void operator()(std::int16_t * data, std::size_t size) override { if (samples_.size() < samples_.capacity()) { auto count = std::min(samples_.capacity() - samples_.size(), size); std::copy(data, data + count, std::back_inserter(samples_)); pos_ += count; data += count; size -= count; if (pos_ == samples_.capacity()) pos_ = 0; } for (; size > 0; ++data, --size) { float s = clamp((*data) + samples_[pos_] * volume_); samples_[pos_] = *data; *data = s; ++pos_; if (pos_ == samples_.capacity()) pos_ = 0; } } private: std::vector samples_; std::size_t pos_ = 0; float delay_; float volume_; }; } std::shared_ptr echo(float delay, float volume) { return std::make_shared(delay, volume); } }