#include #include #include #include #include #include #include namespace psemek::audio { namespace { struct karplus_strong_impl : stream { karplus_strong_impl(float frequency) : buffer_(detail::white_noise(2 * std::round(audio::frequency / frequency))) {} std::optional length() const override { return std::nullopt; } std::size_t read(util::span samples) override { std::size_t const size = buffer_.size(); for (std::size_t i = 0; i < samples.size(); i += 2) { buffer_[buffer_pos_ + 0] = (buffer_[buffer_pos_ + 0] + buffer_[(buffer_pos_ + 2) % size + 0]) / 2.f; buffer_[buffer_pos_ + 1] = (buffer_[buffer_pos_ + 1] + buffer_[(buffer_pos_ + 2) % size + 1]) / 2.f; samples[i + 0] = buffer_[buffer_pos_ + 0]; samples[i + 1] = buffer_[buffer_pos_ + 1]; buffer_pos_ += 2; buffer_pos_ %= size; } return samples.size(); } std::size_t played() const override { return played_.load(); } private: std::vector buffer_; std::size_t buffer_pos_{0}; std::atomic played_; }; } stream_ptr karplus_strong(float frequency) { return std::make_shared(frequency); } }