Add simple echo effect

This commit is contained in:
Nikita Lisitsa 2020-09-21 12:25:24 +03:00
parent 87681a036a
commit 97518a0a4a
3 changed files with 98 additions and 0 deletions

View file

@ -0,0 +1,12 @@
#pragma once
#include <psemek/audio/effect.hpp>
#include <memory>
namespace psemek::audio
{
std::shared_ptr<effect> echo(float delay, float volume);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <cmath>
#include <limits>
#include <cstdint>
namespace psemek::audio
{
inline std::int16_t clamp(float v)
{
static auto const min = std::numeric_limits<std::int16_t>::min();
static auto const max = std::numeric_limits<std::int16_t>::max();
return static_cast<std::int16_t>(std::min<int>(max, std::max<int>(min, std::round(v))));
}
}

View file

@ -0,0 +1,68 @@
#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)
: volume_(volume)
{
int sample_count = std::round(delay * audio::engine::frequency * audio::engine::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 volume_;
};
}
std::shared_ptr<effect> echo(float delay, float volume)
{
return std::make_shared<echo_impl>(delay, volume);
}
}