2 #include <Engine/Node/SimpleApi.hpp>
4 #include <ossia/detail/flicks.hpp>
5 #include <ossia/detail/math.hpp>
7 #include <rnd/random.hpp>
8 #include <tuplet/tuple.hpp>
21 static inline std::random_device& random_source()
23 static thread_local std::random_device d;
33 static const constexpr
auto prettyName =
"LFO (old)";
34 static const constexpr
auto objectKey =
"LFO";
35 static const constexpr
auto category =
"Control/Generators";
36 static const constexpr
auto author =
"ossia score";
37 static const constexpr
auto tags = std::array<const char*, 0>{};
38 static const constexpr
auto kind
39 = Process::ProcessCategory::Generator | Process::ProcessCategory::Deprecated;
40 static const constexpr
auto description =
"Low-frequency oscillator";
41 static const constexpr
double recommended_height = 130.;
42 static const uuid_constexpr
auto uuid
43 = make_uuid(
"0697b807-f588-49b5-926c-f97701edd0d8");
45 static const constexpr value_out value_outs[]{
"out"};
47 static const constexpr
auto controls = tuplet::tuple{
48 Control::Widgets::LFOFreqKnob(),
55 Control::Widgets::WaveformChooser(),
56 Control::Widgets::QuantificationChooser()};
66 using control_policy = ossia::safe_nodes::precise_tick;
69 run(
float freq,
float ampl,
float ampl_fine,
float offset,
float offset_fine,
70 float jitter,
float custom_phase,
const std::string& type,
float quantif,
71 ossia::value_port& out, ossia::token_request tk, ossia::exec_state_facade st,
74 constexpr
const double sine_ratio = ossia::two_pi / ossia::flicks_per_second<double>;
75 const auto& waveform_map = Control::Widgets::waveformMap();
76 const auto elapsed = tk.model_read_duration().impl;
81 if(tk.unexpected_bar_change())
92 freq = 1. / (2. * quantif);
95 const auto ph_delta = elapsed * freq * sine_ratio;
97 if(
const auto it = waveform_map.find_key(type))
102 ph += std::normal_distribution<float>(0., 0.25)(s.rd) * jitter;
106 offset += offset_fine;
108 using namespace Control::Widgets;
110 const auto add_val = [&](
auto new_val) {
111 const auto [tick_start, d] = st.timings(tk);
112 out.write_value(ampl * new_val + offset, tick_start);
115 custom_phase = custom_phase * ossia::pi;
119 add_val(std::sin(custom_phase + ph));
122 add_val(std::asin(std::sin(custom_phase + ph)) / ossia::half_pi);
125 add_val(std::atan(std::tan(custom_phase + ph)) / ossia::half_pi);
128 add_val((std::sin(custom_phase + ph) > 0.f) ? 1.f : -1.f);
130 case SampleAndHold: {
131 const auto start_s = std::sin(custom_phase + ph);
132 const auto end_s = std::sin(custom_phase + ph + ph_delta);
133 if((start_s > 0 && end_s <= 0) || (start_s <= 0 && end_s > 0))
135 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(s.rd));
140 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(s.rd));
143 add_val(std::normal_distribution<float>(0.f, 1.f)(s.rd));
146 add_val(std::clamp(std::cauchy_distribution<float>(0.f, 1.f)(s.rd), 0.f, 1.f));
155 Process::LogFloatSlider& freq, Process::FloatKnob& ampl,
156 Process::FloatKnob& ampl_fine, Process::FloatKnob& offset,
157 Process::FloatKnob& offset_fine, Process::FloatKnob& jitter,
158 Process::FloatKnob& phase, Process::Enum& type, Process::ComboBox& quantif,
164 using namespace tuplet;
175 c0_bg->setRect({0., 0., 170., 130.});
177 c1_bg->setRect({170., 0., 100., 130.});
179 c2_bg->setRect({270., 0., 60., 130.});
181 auto freq_item = makeControl(
182 get<0>(Metadata::controls), freq, parent, context, doc, portFactory);
183 freq_item.root.setPos(c0, 0);
185 auto quant_item = makeControlNoText(
186 get<8>(Metadata::controls), quantif, parent, context, doc, portFactory);
187 quant_item.root.setPos(90, 25);
188 quant_item.port.setPos(-10, 2);
190 auto type_item = makeControlNoText(
191 get<7>(Metadata::controls), type, parent, context, doc, portFactory);
192 type_item.root.setPos(c0, h);
193 type_item.control.rows = 2;
194 type_item.control.columns = 4;
195 type_item.control.setRect(QRectF{0, 0, 104, 44});
196 type_item.control.setPos(10, 0);
197 type_item.port.setPos(0, 17);
199 auto ampl_item = makeControl(
200 get<1>(Metadata::controls), ampl, parent, context, doc, portFactory);
201 ampl_item.root.setPos(c1, 0);
203 auto ampl_fine_item = makeControl(
204 get<2>(Metadata::controls), ampl_fine, parent, context, doc, portFactory);
205 ampl_fine_item.root.setPos(c1 + w, 0);
207 auto offset_item = makeControl(
208 get<3>(Metadata::controls), offset, parent, context, doc, portFactory);
209 offset_item.root.setPos(c1, h);
211 auto offset_fine_item = makeControl(
212 get<4>(Metadata::controls), offset_fine, parent, context, doc, portFactory);
213 offset_fine_item.root.setPos(c1 + w, h);
215 auto jitter_item = makeControl(
216 get<5>(Metadata::controls), jitter, parent, context, doc, portFactory);
217 jitter_item.root.setPos(c2 + w, 0);
219 auto phase_item = makeControl(
220 get<6>(Metadata::controls), phase, parent, context, doc, portFactory);
221 phase_item.root.setPos(c2 + w, h);
235 static const constexpr
auto prettyName =
"LFO";
236 static const constexpr
auto objectKey =
"LFO";
237 static const constexpr
auto category =
"Control/Generators";
238 static const constexpr
auto author =
"ossia score";
239 static const constexpr
auto tags = std::array<const char*, 0>{};
240 static const constexpr
auto kind = Process::ProcessCategory::Generator;
241 static const constexpr
auto description =
"Low-frequency oscillator";
242 static const constexpr
double recommended_height = 130.;
243 static const uuid_constexpr
auto uuid
244 = make_uuid(
"1e17e479-3513-44c8-a8a7-017be9f6ac8a");
246 static const constexpr value_out value_outs[]{
"out"};
248 static const constexpr
auto controls = tuplet::tuple{
249 Control::Widgets::LFOFreqKnob(),
254 Control::Widgets::WaveformChooser(),
255 Control::Widgets::QuantificationChooser()};
262 rnd::pcg rd{random_source()};
265 using control_policy = ossia::safe_nodes::precise_tick;
268 run(
float freq,
float ampl,
float offset,
float jitter,
float custom_phase,
269 const std::string& type,
float quantif, ossia::value_port& out,
270 ossia::token_request tk, ossia::exec_state_facade st,
State& s)
272 constexpr
const double sine_ratio = ossia::two_pi / ossia::flicks_per_second<double>;
273 const auto& waveform_map = Control::Widgets::waveformMap();
274 const auto elapsed = tk.model_read_duration().impl;
276 out.type = ossia::val_type::FLOAT;
277 out.domain = ossia::domain_base<float>{0., 1.};
282 if(tk.unexpected_bar_change())
293 freq = 1. / (2. * quantif);
296 const auto ph_delta = elapsed * freq * sine_ratio;
298 if(
const auto it = waveform_map.find_key(type))
303 ph += std::normal_distribution<float>(0., 0.25)(s.rd) * jitter;
306 using namespace Control::Widgets;
308 const auto add_val = [&](
auto new_val) {
309 const auto [tick_start, d] = st.timings(tk);
310 out.write_value(ampl * new_val + offset, tick_start);
315 add_val(std::sin(custom_phase + ph));
318 add_val(std::asin(std::sin(custom_phase + ph)) / ossia::half_pi);
321 add_val(std::atan(std::tan(custom_phase + ph)) / ossia::half_pi);
324 add_val((std::sin(custom_phase + ph) > 0.f) ? 1.f : -1.f);
326 case SampleAndHold: {
327 const auto start_s = std::sin(custom_phase + ph);
328 const auto end_s = std::sin(custom_phase + ph + ph_delta);
329 if((start_s > 0 && end_s <= 0) || (start_s <= 0 && end_s > 0))
331 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(s.rd));
336 add_val(std::uniform_real_distribution<float>(-1.f, 1.f)(s.rd));
339 add_val(std::normal_distribution<float>(0.f, 1.f)(s.rd));
342 add_val(std::clamp(std::cauchy_distribution<float>(0.f, 1.f)(s.rd), 0.f, 1.f));
351 Process::LogFloatSlider& freq, Process::FloatKnob& ampl,
352 Process::FloatKnob& offset, Process::FloatKnob& jitter, Process::FloatKnob& phase,
353 Process::Enum& type, Process::ComboBox& quantif,
359 using namespace tuplet;
370 c0_bg->setRect({0., 0., 170., 130.});
372 c1_bg->setRect({170., 0., 100., 130.});
374 c2_bg->setRect({270., 0., 60., 130.});
376 auto freq_item = makeControl(
377 get<0>(Metadata::controls), freq, parent, context, doc, portFactory);
378 freq_item.root.setPos(c0, 0);
380 auto ampl_item = makeControl(
381 get<1>(Metadata::controls), ampl, parent, context, doc, portFactory);
382 ampl_item.root.setPos(c1, 0);
384 auto offset_item = makeControl(
385 get<2>(Metadata::controls), offset, parent, context, doc, portFactory);
386 offset_item.root.setPos(c1, h);
388 auto jitter_item = makeControl(
389 get<3>(Metadata::controls), jitter, parent, context, doc, portFactory);
390 jitter_item.root.setPos(c2 + w, 0);
392 auto phase_item = makeControl(
393 get<4>(Metadata::controls), phase, parent, context, doc, portFactory);
394 phase_item.root.setPos(c2 + w, h);
396 auto type_item = makeControlNoText(
397 get<5>(Metadata::controls), type, parent, context, doc, portFactory);
398 type_item.root.setPos(c0, h);
399 type_item.control.rows = 2;
400 type_item.control.columns = 4;
401 type_item.control.setRect(QRectF{0, 0, 104, 44});
402 type_item.control.setPos(10, 0);
403 type_item.port.setPos(0, 17);
405 auto quant_item = makeControlNoText(
406 get<6>(Metadata::controls), quantif, parent, context, doc, portFactory);
407 quant_item.root.setPos(90, 25);
408 quant_item.port.setPos(-10, 2);
Definition: PortFactory.hpp:65
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
Definition: RectItem.hpp:96
Base classes and tools to implement processes and layers.
Definition: JSONVisitor.hpp:1324
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: score-lib-process/Control/Widgets.hpp:77
Definition: ProcessContext.hpp:12
const T & interfaces() const
Access to a specific interface list.
Definition: ApplicationContext.hpp:67