diff --git a/libs/audio/include/psemek/audio/effect/distortion.hpp b/libs/audio/include/psemek/audio/effect/distortion.hpp new file mode 100644 index 00000000..26017935 --- /dev/null +++ b/libs/audio/include/psemek/audio/effect/distortion.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace psemek::audio +{ + + struct distortion_control + : stream + { + virtual float strength() const = 0; + virtual float strength(float value) = 0; + }; + + stream_ptr distortion(stream_ptr stream, float strength = 100.f); + +} diff --git a/libs/audio/source/effect/distortion.cpp b/libs/audio/source/effect/distortion.cpp new file mode 100644 index 00000000..f8a0be5d --- /dev/null +++ b/libs/audio/source/effect/distortion.cpp @@ -0,0 +1,65 @@ +#include + +#include +#include + +namespace psemek::audio +{ + + namespace + { + + struct distortion_impl + : distortion_control + { + distortion_impl(stream_ptr stream, float strength) + : stream_(std::move(stream)) + , strength_(strength) + {} + + float strength() const override + { + return strength_.load(); + } + + float strength(float value) override + { + return strength_.exchange(value); + } + + std::optional length() const override + { + return stream_->length(); + } + + std::size_t read(float * data, std::size_t sample_count) override + { + auto result = stream_->read(data, sample_count); + float strength = strength_.load(); + + for (std::size_t i = 0; i < result; ++i) + { + data[i] = std::tanh(strength * data[i]); + } + + return result; + } + + std::size_t played() const override + { + return stream_->played(); + } + + private: + stream_ptr stream_; + std::atomic strength_; + }; + + } + + stream_ptr distortion(stream_ptr stream, float strength) + { + return std::make_shared(std::move(stream), strength); + } + +}