9#include "arg_wrappers.hpp"
10#include "data_types.hpp"
48static_assert(
decltype(std::minstd_rand())::min() == 1);
49static_assert(
decltype(std::minstd_rand())::max() == 2'147'483'646);
58static_assert(std::numeric_limits<double>::is_iec559);
59static_assert(std::numeric_limits<double>::radix == 2);
60static_assert(std::numeric_limits<double>::digits == 53);
64[[nodiscard]]
inline auto
65uniform_double_0_1_minstd(std::minstd_rand::result_type r) ->
double {
66 assert(r < 2'147'483'648u);
71 auto bits = std::uint64_t(r) << (52u - 31u);
72 bits |= 1023uLL << 52;
74 std::memcpy(&d, &bits,
sizeof(d));
81[[nodiscard]]
inline auto
82triangular_double_0_2_minstd(std::minstd_rand::result_type r0,
83 std::minstd_rand::result_type r1) ->
double {
84 auto const d0 = uniform_double_0_1_minstd(r0);
85 auto const d1 = uniform_double_0_1_minstd(r1);
86 return d0 + (1.0 - d1);
92[[nodiscard]]
inline auto apply_dither(
double value,
double dither_noise_0_2)
94 assert(dither_noise_0_2 >= 0.0);
95 assert(dither_noise_0_2 < 2.0);
96 return static_cast<T
>(std::floor(value + dither_noise_0_2 - 0.5));
99template <
typename T>
class dithering_quantizer {
100 std::minstd_rand prng;
103 [[nodiscard]]
auto operator()(
double value) -> T {
105 auto const r0 = prng();
106 auto const r1 = prng();
107 return apply_dither<T>(value, triangular_double_0_2_minstd(r0, r1));
121template <
typename DataTypes = default_data_types>
123 std::optional<typename DataTypes::abstime_type> next;
126 internal::dithering_quantizer<typename DataTypes::abstime_type> dithq;
139 throw std::invalid_argument(
140 "dithered timing generator delay must be at least 1.5");
144 template <
typename TriggerEvent>
void trigger(TriggerEvent
const &event) {
145 static_assert(std::is_same_v<
decltype(
event.abstime),
146 typename DataTypes::abstime_type>);
147 next =
event.abstime + dithq(dly);
151 [[nodiscard]]
auto peek() const
152 -> std::optional<typename DataTypes::abstime_type> {
157 void pop() { next.reset(); }
173template <
typename DataTypes = default_data_types>
175 std::optional<typename DataTypes::abstime_type> next;
177 internal::dithering_quantizer<typename DataTypes::abstime_type> dithq;
181 template <
typename TriggerEvent>
void trigger(TriggerEvent
const &event) {
182 static_assert(std::is_same_v<
decltype(
event.abstime),
183 typename DataTypes::abstime_type>);
184 static_assert(std::is_same_v<
decltype(
event.delay),
double>);
185 if (event.delay < 1.5)
187 "dithered timing generator delay must be at least 1.5");
188 next =
event.abstime + dithq(event.delay);
192 [[nodiscard]]
auto peek() const
193 -> std::optional<typename DataTypes::abstime_type> {
198 void pop() { next.reset(); }
203template <
typename Abstime>
class dithered_linear_timing_generator_impl {
204 Abstime trigger_time{};
205 std::size_t remaining = 0;
212 dithering_quantizer<Abstime> dithq;
214 void compute_next() {
217 auto const index = ct - remaining;
218 next = trigger_time + dithq(dly + intv *
static_cast<double>(index));
222 dithered_linear_timing_generator_impl() =
default;
224 explicit dithered_linear_timing_generator_impl(
225 arg::delay<double>
delay, arg::interval<double> interval,
226 arg::count<std::size_t>
count)
227 : dly(
delay.value), intv(interval.value), ct(
count.value) {
229 throw std::invalid_argument(
230 "dithered timing generator delay must be at least 1.5");
232 throw std::invalid_argument(
233 "dithered timing generator interval must be at least 3.0");
236 void trigger(arg::abstime<Abstime> abstime) {
237 trigger_time = abstime.value;
242 void trigger_and_configure(arg::abstime<Abstime> abstime,
243 arg::delay<double>
delay,
244 arg::interval<double> interval,
245 arg::count<std::size_t>
count) {
247 intv = interval.value;
250 throw data_validation_error(
251 "dithered timing generator delay must be at least 1.5");
253 throw data_validation_error(
254 "dithered timing generator interval must be at least 3.0");
258 [[nodiscard]]
auto peek() const -> std::optional<Abstime> {
259 return remaining > 0 ? next : std::optional<Abstime>{};
278template <
typename DataTypes = default_data_types>
280 internal::dithered_linear_timing_generator_impl<
281 typename DataTypes::abstime_type>
298 template <
typename TriggerEvent>
void trigger(TriggerEvent
const &event) {
299 static_assert(std::is_same_v<
decltype(
event.abstime),
300 typename DataTypes::abstime_type>);
305 [[nodiscard]]
auto peek() const
306 -> std::optional<typename DataTypes::abstime_type> {
311 void pop() { impl.pop(); }
328template <
typename DataTypes = default_data_types>
330 internal::dithered_linear_timing_generator_impl<
331 typename DataTypes::abstime_type>
336 template <
typename TriggerEvent>
void trigger(TriggerEvent
const &event) {
337 static_assert(std::is_same_v<
decltype(
event.abstime),
338 typename DataTypes::abstime_type>);
339 impl.trigger_and_configure(
345 [[nodiscard]]
auto peek() const
346 -> std::optional<typename DataTypes::abstime_type> {
351 void pop() { impl.pop(); }
Error thrown when the data being processed does not meet expectations.
Definition errors.hpp:95
dithered_linear_timing_generator(arg::delay< double > delay, arg::interval< double > interval, arg::count< std::size_t > count)
Construct an instance that generates count timings at interval after delay relative to each trigger.
Definition dither.hpp:292
void pop()
Implements timing generator requirement.
Definition dither.hpp:311
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition dither.hpp:305
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition dither.hpp:298
void pop()
Implements timing generator requirement.
Definition dither.hpp:157
dithered_one_shot_timing_generator(arg::delay< double > delay)
Construct an instance that generates a timing after delay (plus dither) relative to each trigger.
Definition dither.hpp:136
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition dither.hpp:144
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition dither.hpp:151
Timing generator that generates a periodic series of timings, configured by the trigger event,...
Definition dither.hpp:329
void pop()
Implements timing generator requirement.
Definition dither.hpp:351
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition dither.hpp:336
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition dither.hpp:345
Timing generator that generates a single, delayed timing, configured by the trigger event,...
Definition dither.hpp:174
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition dither.hpp:181
void pop()
Implements timing generator requirement.
Definition dither.hpp:198
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition dither.hpp:192
auto count(access_tracker< count_access > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:313
auto delay(arg::delta< typename DataTypes::abstime_type > delta, Downstream downstream)
Create a processor that applies an abstime offset to all events.
Definition delay.hpp:123
libtcspc namespace.
Definition acquire.hpp:29
Function argument wrapper for abstime parameter.
Definition arg_wrappers.hpp:37
Function argument wrapper for count parameter.
Definition arg_wrappers.hpp:97
Function argument wrapper for delay parameter.
Definition arg_wrappers.hpp:117
Function argument wrapper for interval parameter.
Definition arg_wrappers.hpp:177