66 lines
1.4 KiB
C++
66 lines
1.4 KiB
C++
#include <psemek/audio/wave/karplus_strong.hpp>
|
|
#include <psemek/audio/constants.hpp>
|
|
#include <psemek/audio/white_noise.hpp>
|
|
#include <psemek/random/generator.hpp>
|
|
#include <psemek/random/uniform.hpp>
|
|
|
|
#include <vector>
|
|
#include <atomic>
|
|
|
|
namespace psemek::audio
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
struct karplus_strong_impl
|
|
: stream
|
|
{
|
|
karplus_strong_impl(float frequency)
|
|
: buffer_(white_noise(2 * std::round(audio::frequency / frequency)))
|
|
{}
|
|
|
|
std::optional<std::size_t> length() const override
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::size_t read(util::span<float> 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<float> buffer_;
|
|
std::size_t buffer_pos_{0};
|
|
|
|
std::atomic<std::size_t> played_;
|
|
};
|
|
|
|
}
|
|
|
|
stream_ptr karplus_strong(float frequency)
|
|
{
|
|
return std::make_shared<karplus_strong_impl>(frequency);
|
|
}
|
|
|
|
}
|