73 lines
1.4 KiB
C++
73 lines
1.4 KiB
C++
#include <psemek/audio/echo.hpp>
|
|
#include <psemek/audio/engine.hpp>
|
|
#include <psemek/audio/utils.hpp>
|
|
|
|
#include <cmath>
|
|
#include <vector>
|
|
|
|
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<std::int16_t> samples_;
|
|
std::size_t pos_ = 0;
|
|
float delay_;
|
|
float volume_;
|
|
};
|
|
|
|
}
|
|
|
|
std::shared_ptr<effect> echo(float delay, float volume)
|
|
{
|
|
return std::make_shared<echo_impl>(delay, volume);
|
|
}
|
|
|
|
}
|