diff --git a/libs/audio/include/psemek/audio/oscillator.hpp b/libs/audio/include/psemek/audio/oscillator.hpp new file mode 100644 index 00000000..236546ed --- /dev/null +++ b/libs/audio/include/psemek/audio/oscillator.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include + +namespace psemek::audio +{ + + struct oscillator + { + oscillator(float frequency) + : m_(std::exp(std::complex{0.f, 2.f * geom::pi * frequency * inv_frequency})) + {} + + std::complex phase() const + { + return phase_; + } + + std::complex next() + { + phase_ *= m_; + phase_ /= std::abs(phase_); + return phase_; + } + + private: + std::complex phase_{1.f, 0.f}; + std::complex m_; + }; + +} diff --git a/libs/audio/include/psemek/audio/wave/generator.hpp b/libs/audio/include/psemek/audio/wave/generator.hpp index 441b0f3b..25717e6e 100644 --- a/libs/audio/include/psemek/audio/wave/generator.hpp +++ b/libs/audio/include/psemek/audio/wave/generator.hpp @@ -12,7 +12,6 @@ namespace psemek::audio { generator_stream(Func func) : func_(std::move(func)) - , phase_(0.f) {} std::size_t read(float * data, std::size_t sample_count) override @@ -20,17 +19,15 @@ namespace psemek::audio auto end = data + sample_count; for (auto p = data; p != end;) { - float v = func_(phase_); + float v = func_(); *p++ = v; *p++ = v; - phase_ += inv_frequency; } return sample_count; } private: Func func_; - float phase_; }; } diff --git a/libs/audio/source/wave/sawtooth.cpp b/libs/audio/source/wave/sawtooth.cpp index e3d9d387..979a02bb 100644 --- a/libs/audio/source/wave/sawtooth.cpp +++ b/libs/audio/source/wave/sawtooth.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include #include +#include #include @@ -10,9 +11,9 @@ namespace psemek::audio stream_ptr sawtooth_wave(float frequency) { - auto func = [frequency](float t){ - t *= frequency; - return (t - std::floor(t)) * 2.f - 1.f; + auto func = [o = oscillator{frequency}]() mutable { + auto z = o.next(); + return (2.f / geom::pi) * (- std::atan2(z.real() + 1.f, z.imag())); }; return util::to_shared(generator_stream(func)); diff --git a/libs/audio/source/wave/sine.cpp b/libs/audio/source/wave/sine.cpp index c014fc08..bcbd8ae6 100644 --- a/libs/audio/source/wave/sine.cpp +++ b/libs/audio/source/wave/sine.cpp @@ -1,19 +1,18 @@ #include #include -#include +#include #include #include +#include namespace psemek::audio { stream_ptr sine_wave(float frequency) { - float angular_frequency = frequency * 2.f * geom::pi; - - auto func = [angular_frequency](float t){ - return std::sin(angular_frequency * t); + auto func = [o = oscillator{frequency}]() mutable { + return o.next().imag(); }; return util::to_shared(generator_stream(func)); diff --git a/libs/audio/source/wave/square.cpp b/libs/audio/source/wave/square.cpp index 59225377..1770c4fa 100644 --- a/libs/audio/source/wave/square.cpp +++ b/libs/audio/source/wave/square.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -10,9 +10,8 @@ namespace psemek::audio stream_ptr square_wave(float frequency) { - auto func = [frequency](float t){ - t *= frequency; - return (t - std::floor(t)) < 0.5f ? 1.f : -1.f; + auto func = [o = oscillator{frequency}]() mutable { + return o.next().imag() > 0.f ? 1.f : -1.f; }; return util::to_shared(generator_stream(func)); diff --git a/libs/audio/source/wave/triangle.cpp b/libs/audio/source/wave/triangle.cpp index 6d36d405..f66a894c 100644 --- a/libs/audio/source/wave/triangle.cpp +++ b/libs/audio/source/wave/triangle.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -10,8 +10,9 @@ namespace psemek::audio stream_ptr triangle_wave(float frequency) { - auto func = [frequency](float t){ - t *= frequency; + auto func = [o = oscillator{frequency}]() mutable { + auto const z = o.next(); + float const t = 0.5f * std::atan2(z.imag(), z.real()) / (geom::pi) + 0.5f; return 4.f * std::abs(t - std::floor(t + 0.5f)) - 1.f; };