2 #include <Fx/Types.hpp>
4 #include <ossia/detail/flicks.hpp>
5 #include <ossia/detail/math.hpp>
7 #include <halp/controls.hpp>
8 #include <halp/meta.hpp>
9 #include <halp/midi.hpp>
10 #include <rnd/random.hpp>
11 #include <tuplet/tuple.hpp>
20 static inline std::random_device& random_source()
22 static thread_local std::random_device d;
30 halp_meta(name,
"LFO (old)")
31 halp_meta(c_name,
"LFO")
32 halp_meta(category,
"Control/Generators")
33 halp_meta(author,
"ossia score")
34 halp_meta(manual_url,
"https://ossia.io/score-docs/processes/lfo.html#lfo")
35 halp_meta(description,
"Low-frequency oscillator")
36 halp_flag(deprecated);
37 halp_meta(recommended_height, 130.)
38 halp_meta(uuid,
"0697b807-f588-49b5-926c-f97701edd0d8");
43 halp::log_hslider_f32<
"Freq.", halp::range{0.01f, 100.f, 1.f}> freq;
44 halp::knob_f32<
"Ampl.", halp::range{0., 1000., 0.}> ampl;
45 halp::knob_f32<
"Fine", halp::range{0., 1., 0.5}> ampl_fine;
46 halp::knob_f32<
"Offset", halp::range{-1000., 1000., 0.}> offset;
47 halp::knob_f32<
"Fine", halp::range{-1., 1., 0.5}> offset_fine;
48 halp::knob_f32<
"Jitter", halp::range{0., 1., 0}> jitter;
49 halp::knob_f32<
"Phase", halp::range{-1., 1., 0.}> phase;
50 halp::enum_t<Control::Widgets::Waveform,
"Waveform"> waveform;
55 halp::val_port<
"Out", std::optional<float>> out;
61 using tick = halp::tick_flicks;
62 void operator()(
const halp::tick_flicks& tk)
64 constexpr
const double sine_ratio = ossia::two_pi / ossia::flicks_per_second<double>;
65 const auto elapsed = tk.model_read_duration();
67 const auto quantif = inputs.quant.value;
68 auto freq = inputs.freq.value;
69 auto ampl = inputs.ampl.value;
70 const auto ampl_fine = inputs.ampl_fine.value;
71 auto offset = inputs.offset.value;
72 const auto offset_fine = inputs.offset_fine.value;
73 const auto jitter = inputs.jitter.value;
74 auto custom_phase = inputs.phase.value;
75 const auto type = inputs.waveform.value;
80 if(tk.unexpected_bar_change())
91 freq = 1. / (2. * quantif);
94 const auto ph_delta = elapsed * freq * sine_ratio;
97 auto ph = this->phase;
100 ph += std::normal_distribution<float>(0., 0.25)(this->rd) * jitter;
104 offset += offset_fine;
106 using namespace Control::Widgets;
109 = [&](
auto new_val) { outputs.out.value = ampl * new_val + offset; };
111 custom_phase = custom_phase * ossia::pi;
115 add_val(std::sin(custom_phase + ph));
118 add_val(std::asin(std::sin(custom_phase + ph)) / ossia::half_pi);
121 add_val(std::atan(std::tan(custom_phase + ph)) / ossia::half_pi);
124 add_val((std::sin(custom_phase + ph) > 0.f) ? 1.f : -1.f);
126 case SampleAndHold: {
127 const auto start_s = std::sin(custom_phase + ph);
128 const auto end_s = std::sin(custom_phase + ph + ph_delta);
129 if((start_s > 0 && end_s <= 0) || (start_s <= 0 && end_s > 0))
131 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(this->rd));
136 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(this->rd));
139 add_val(std::normal_distribution<float>(0.f, 1.f)(this->rd));
143 std::clamp(std::cauchy_distribution<float>(0.f, 1.f)(this->rd), 0.f, 1.f));
148 this->phase += ph_delta;