23 halp_meta(name,
"Rate Limiter (old)")
24 halp_meta(c_name,
"RateLimiter")
25 halp_meta(category,
"Control/Mappings")
27 manual_url,
"https://ossia.io/score-docs/processes/rate-limiter.html#rate-limiter")
28 halp_meta(author,
"ossia score")
31 "Limit and quantize a value stream, or debounce after quiet milliseconds "
32 "(debounce ignores quantization)")
33 halp_flag(deprecated);
34 halp_meta(uuid,
"76cfd504-7c10-4bdb-a1b4-fbe449cc06f0")
35 halp_flag(process_exec);
47 struct : halp::hslider_i32<
"Duration", halp::irange{0, 1000, 10}>
51 "Minimum interval in milliseconds, or quiet time before a debounced value")
53 struct : halp::enum_t<Mode,
"Mode">
55 void update(
Node& self)
57 if(self.previous_mode != this->value)
64 halp::timed_callback<
"out", ossia::value> out;
70 using tick = ossia::token_request;
71 ossia::exec_state_facade ossia_state;
73 static constexpr int64_t flicks_per_ms = 705'600;
75 std::optional<ossia::value> pending;
76 long double deadline{};
77 std::optional<int64_t> previous_end;
78 Mode previous_mode{Mode::Limit};
79 ossia::small_vector<const ossia::timed_value*, 16> ordered_events;
86 previous_mode = inputs.mode.value;
89 void prepare(halp::setup)
noexcept { reset(); }
90 void start() noexcept { reset(); }
91 void stop() noexcept { reset(); }
92 void transport(
auto) noexcept { reset(); }
94 bool should_output(
float quantif, int64_t ms,
const tick& t)
98 else if(t.date.impl >= (last_time + ms * flicks_per_ms))
100 last_time = t.date.impl;
106 void operator()(
const tick& t)
108 if(previous_mode != inputs.mode.value
109 || (previous_end && t.prev_date.impl != *previous_end))
111 previous_end = t.date.impl;
113 const auto [start, frames] = ossia_state.timings(t);
114 if(inputs.mode.value == Mode::Debounce)
117 if(t.date <= t.prev_date || t.speed <= 0.)
124 debounce(t, start, frames);
128 auto quantif = inputs.quantification.value;
129 auto ms = inputs.ms.value;
130 for(
const ossia::timed_value& v : inputs.port.value->get_data())
132 if(v.timestamp < start || v.timestamp >= start + frames)
136 if(should_output(quantif, ms, t))
137 outputs.out(v.timestamp - start, v.value);
141 for(
const auto& point : t.get_quantification_dates(1. / quantif))
144 t.physical_position(point.position, ossia_state.modelToSamples()),
152 void debounce(
const tick& t, int64_t start, int64_t frames)
157 const long double begin = t.prev_date.impl;
158 const long double duration =
static_cast<long double>(t.date.impl) - begin;
159 const int64_t delay = std::max(0, inputs.ms.value) * flicks_per_ms;
160 const auto emit = [&] {
164 = std::max(0.L, std::ceil((deadline - begin) * frames / duration));
167 outputs.out(
static_cast<int64_t
>(frame), std::move(*pending));
171 const auto event = [&](
const ossia::timed_value& v) {
172 if(v.timestamp < start || v.timestamp >= start + frames)
174 const auto date = begin + (v.timestamp - start) * duration / frames;
177 if(pending && deadline < date)
182 outputs.out(v.timestamp - start, v.value);
187 deadline = date + delay;
191 const auto& data = inputs.port.value->get_data();
192 if(std::is_sorted(data.begin(), data.end(), [](
const auto& a,
const auto& b) {
193 return a.timestamp < b.timestamp;
196 for(
const auto& v : data)
203 ordered_events.clear();
204 for(
const auto& v : data)
205 ordered_events.push_back(&v);
207 ordered_events.begin(), ordered_events.end(),
208 [](
const auto* a,
const auto* b) {
209 return a->timestamp < b->timestamp || (a->timestamp == b->timestamp && a < b);
211 for(
const auto* v : ordered_events)
214 if(pending && deadline < t.date.impl)
220 halp_meta(layout, halp::layouts::hbox)
221 halp_meta(background, halp::colors::background_mid)
222 halp::control<&ins::quantification> q;
223 halp::control<&ins::ms> t;
224 halp::control<&ins::mode> mode;