diff --git a/libs/audio/include/psemek/audio/echo.hpp b/libs/audio/include/psemek/audio/echo.hpp new file mode 100644 index 00000000..d21fa65a --- /dev/null +++ b/libs/audio/include/psemek/audio/echo.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include + +namespace psemek::audio +{ + + std::shared_ptr echo(float delay, float volume); + +} diff --git a/libs/audio/include/psemek/audio/utils.hpp b/libs/audio/include/psemek/audio/utils.hpp new file mode 100644 index 00000000..4a9c884b --- /dev/null +++ b/libs/audio/include/psemek/audio/utils.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +namespace psemek::audio +{ + + inline std::int16_t clamp(float v) + { + static auto const min = std::numeric_limits::min(); + static auto const max = std::numeric_limits::max(); + + return static_cast(std::min(max, std::max(min, std::round(v)))); + } + +} diff --git a/libs/audio/source/echo.cpp b/libs/audio/source/echo.cpp new file mode 100644 index 00000000..0973b114 --- /dev/null +++ b/libs/audio/source/echo.cpp @@ -0,0 +1,68 @@ +#include +#include +#include + +#include +#include + +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 samples_; + std::size_t pos_ = 0; + float volume_; + }; + + } + + std::shared_ptr echo(float delay, float volume) + { + return std::make_shared(delay, volume); + } + +}