Reimplement basic waveforms using a complex oscillator
This commit is contained in:
parent
051e812358
commit
65f71e54a8
6 changed files with 51 additions and 20 deletions
34
libs/audio/include/psemek/audio/oscillator.hpp
Normal file
34
libs/audio/include/psemek/audio/oscillator.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/audio/constants.hpp>
|
||||||
|
#include <psemek/geom/constants.hpp>
|
||||||
|
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
namespace psemek::audio
|
||||||
|
{
|
||||||
|
|
||||||
|
struct oscillator
|
||||||
|
{
|
||||||
|
oscillator(float frequency)
|
||||||
|
: m_(std::exp(std::complex<float>{0.f, 2.f * geom::pi * frequency * inv_frequency}))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::complex<float> phase() const
|
||||||
|
{
|
||||||
|
return phase_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::complex<float> next()
|
||||||
|
{
|
||||||
|
phase_ *= m_;
|
||||||
|
phase_ /= std::abs(phase_);
|
||||||
|
return phase_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::complex<float> phase_{1.f, 0.f};
|
||||||
|
std::complex<float> m_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,7 +12,6 @@ namespace psemek::audio
|
||||||
{
|
{
|
||||||
generator_stream(Func func)
|
generator_stream(Func func)
|
||||||
: func_(std::move(func))
|
: func_(std::move(func))
|
||||||
, phase_(0.f)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::size_t read(float * data, std::size_t sample_count) override
|
std::size_t read(float * data, std::size_t sample_count) override
|
||||||
|
|
@ -20,17 +19,15 @@ namespace psemek::audio
|
||||||
auto end = data + sample_count;
|
auto end = data + sample_count;
|
||||||
for (auto p = data; p != end;)
|
for (auto p = data; p != end;)
|
||||||
{
|
{
|
||||||
float v = func_(phase_);
|
float v = func_();
|
||||||
*p++ = v;
|
*p++ = v;
|
||||||
*p++ = v;
|
*p++ = v;
|
||||||
phase_ += inv_frequency;
|
|
||||||
}
|
}
|
||||||
return sample_count;
|
return sample_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Func func_;
|
Func func_;
|
||||||
float phase_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
#include <psemek/audio/wave/sawtooth.hpp>
|
#include <psemek/audio/wave/sawtooth.hpp>
|
||||||
#include <psemek/audio/wave/generator.hpp>
|
#include <psemek/audio/wave/generator.hpp>
|
||||||
#include <psemek/geom/math.hpp>
|
#include <psemek/audio/oscillator.hpp>
|
||||||
#include <psemek/util/to_shared.hpp>
|
#include <psemek/util/to_shared.hpp>
|
||||||
|
#include <psemek/log/log.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
|
@ -10,9 +11,9 @@ namespace psemek::audio
|
||||||
|
|
||||||
stream_ptr sawtooth_wave(float frequency)
|
stream_ptr sawtooth_wave(float frequency)
|
||||||
{
|
{
|
||||||
auto func = [frequency](float t){
|
auto func = [o = oscillator{frequency}]() mutable {
|
||||||
t *= frequency;
|
auto z = o.next();
|
||||||
return (t - std::floor(t)) * 2.f - 1.f;
|
return (2.f / geom::pi) * (- std::atan2(z.real() + 1.f, z.imag()));
|
||||||
};
|
};
|
||||||
|
|
||||||
return util::to_shared(generator_stream(func));
|
return util::to_shared(generator_stream(func));
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
#include <psemek/audio/wave/sine.hpp>
|
#include <psemek/audio/wave/sine.hpp>
|
||||||
#include <psemek/audio/wave/generator.hpp>
|
#include <psemek/audio/wave/generator.hpp>
|
||||||
#include <psemek/geom/math.hpp>
|
#include <psemek/audio/oscillator.hpp>
|
||||||
#include <psemek/util/to_shared.hpp>
|
#include <psemek/util/to_shared.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
namespace psemek::audio
|
namespace psemek::audio
|
||||||
{
|
{
|
||||||
|
|
||||||
stream_ptr sine_wave(float frequency)
|
stream_ptr sine_wave(float frequency)
|
||||||
{
|
{
|
||||||
float angular_frequency = frequency * 2.f * geom::pi;
|
auto func = [o = oscillator{frequency}]() mutable {
|
||||||
|
return o.next().imag();
|
||||||
auto func = [angular_frequency](float t){
|
|
||||||
return std::sin(angular_frequency * t);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return util::to_shared(generator_stream(func));
|
return util::to_shared(generator_stream(func));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <psemek/audio/wave/square.hpp>
|
#include <psemek/audio/wave/square.hpp>
|
||||||
#include <psemek/audio/wave/generator.hpp>
|
#include <psemek/audio/wave/generator.hpp>
|
||||||
#include <psemek/geom/math.hpp>
|
#include <psemek/audio/oscillator.hpp>
|
||||||
#include <psemek/util/to_shared.hpp>
|
#include <psemek/util/to_shared.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
@ -10,9 +10,8 @@ namespace psemek::audio
|
||||||
|
|
||||||
stream_ptr square_wave(float frequency)
|
stream_ptr square_wave(float frequency)
|
||||||
{
|
{
|
||||||
auto func = [frequency](float t){
|
auto func = [o = oscillator{frequency}]() mutable {
|
||||||
t *= frequency;
|
return o.next().imag() > 0.f ? 1.f : -1.f;
|
||||||
return (t - std::floor(t)) < 0.5f ? 1.f : -1.f;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return util::to_shared(generator_stream(func));
|
return util::to_shared(generator_stream(func));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <psemek/audio/wave/triangle.hpp>
|
#include <psemek/audio/wave/triangle.hpp>
|
||||||
#include <psemek/audio/wave/generator.hpp>
|
#include <psemek/audio/wave/generator.hpp>
|
||||||
#include <psemek/geom/math.hpp>
|
#include <psemek/audio/oscillator.hpp>
|
||||||
#include <psemek/util/to_shared.hpp>
|
#include <psemek/util/to_shared.hpp>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
@ -10,8 +10,9 @@ namespace psemek::audio
|
||||||
|
|
||||||
stream_ptr triangle_wave(float frequency)
|
stream_ptr triangle_wave(float frequency)
|
||||||
{
|
{
|
||||||
auto func = [frequency](float t){
|
auto func = [o = oscillator{frequency}]() mutable {
|
||||||
t *= frequency;
|
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;
|
return 4.f * std::abs(t - std::floor(t + 0.5f)) - 1.f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue