Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
ratchet.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <bit>
6#include <cstddef>
7#include <cstdint>
8#include <limits>
9#include <span>
10
11namespace pulp::timebase {
12
22
25 std::size_t event_count = 0;
26
27 constexpr explicit operator bool() const noexcept {
28 return error == RatchetError::None;
29 }
30};
31
32namespace detail {
33
34inline constexpr std::uint64_t kSignedTickOrderBit = std::uint64_t{1} << 63U;
35
36constexpr std::uint64_t ordered_tick_coordinate(TickPosition position) noexcept {
37 return std::bit_cast<std::uint64_t>(position.value) ^ kSignedTickOrderBit;
38}
39
40constexpr TickPosition tick_from_ordered_coordinate(std::uint64_t coordinate) noexcept {
41 return {std::bit_cast<std::int64_t>(coordinate ^ kSignedTickOrderBit)};
42}
43
45 public:
46 constexpr RatchetSubdivisionCursor(TickPosition interval_begin, TickPosition interval_end,
47 std::uint64_t hit_count) noexcept
48 : coordinate_(ordered_tick_coordinate(interval_begin)),
49 step_((ordered_tick_coordinate(interval_end) - coordinate_) / hit_count),
50 remainder_((ordered_tick_coordinate(interval_end) - coordinate_) % hit_count),
51 hit_count_(hit_count) {}
52
53 constexpr TickPosition position() const noexcept {
54 return tick_from_ordered_coordinate(coordinate_);
55 }
56
57 constexpr void advance() noexcept {
58 coordinate_ += step_;
59 if (error_ >= hit_count_ - remainder_) {
60 ++coordinate_;
61 error_ -= hit_count_ - remainder_;
62 } else {
63 error_ += remainder_;
64 }
65 }
66
67 private:
68 std::uint64_t coordinate_ = 0;
69 std::uint64_t step_ = 0;
70 std::uint64_t remainder_ = 0;
71 std::uint64_t hit_count_ = 1;
72 std::uint64_t error_ = 0;
73};
74
75} // namespace detail
76
85template <std::size_t MaximumHits = 64>
86[[nodiscard]] constexpr RatchetProjectionResult
88 std::size_t hit_count, TickPosition window_begin, TickPosition window_end,
89 std::span<TickPosition> output) noexcept {
90 static_assert(MaximumHits > 0, "ratchet capacity must be positive");
91 static_assert(MaximumHits <= std::numeric_limits<std::uint64_t>::max(),
92 "ratchet capacity must fit the subdivision domain");
93
94 if (interval_end <= interval_begin)
96 if (hit_count == 0)
98 if (hit_count > MaximumHits)
100 const auto interval_span = detail::ordered_tick_coordinate(interval_end) -
101 detail::ordered_tick_coordinate(interval_begin);
102 if (static_cast<std::uint64_t>(hit_count) > interval_span)
104 if (window_end < window_begin)
105 return {RatchetError::InvalidWindow, 0};
106
107 const auto count_visible = [&]() constexpr noexcept {
108 std::size_t event_count = 0;
109 detail::RatchetSubdivisionCursor cursor(interval_begin, interval_end,
110 static_cast<std::uint64_t>(hit_count));
111 for (std::size_t index = 0; index < hit_count; ++index) {
112 const auto position = cursor.position();
113 if (position >= window_begin && position < window_end)
114 ++event_count;
115 cursor.advance();
116 }
117 return event_count;
118 };
119
120 const auto event_count = count_visible();
121 if (event_count > output.size())
123
124 std::size_t output_index = 0;
125 detail::RatchetSubdivisionCursor cursor(interval_begin, interval_end,
126 static_cast<std::uint64_t>(hit_count));
127 for (std::size_t index = 0; index < hit_count; ++index) {
128 const auto position = cursor.position();
129 if (position >= window_begin && position < window_end)
130 output[output_index++] = position;
131 cursor.advance();
132 }
133 return {RatchetError::None, event_count};
134}
135
136} // namespace pulp::timebase
constexpr void advance() noexcept
Definition ratchet.hpp:57
constexpr RatchetSubdivisionCursor(TickPosition interval_begin, TickPosition interval_end, std::uint64_t hit_count) noexcept
Definition ratchet.hpp:46
constexpr TickPosition position() const noexcept
Definition ratchet.hpp:53
constexpr std::uint64_t kSignedTickOrderBit
Definition ratchet.hpp:34
constexpr std::uint64_t ordered_tick_coordinate(TickPosition position) noexcept
Definition ratchet.hpp:36
constexpr TickPosition tick_from_ordered_coordinate(std::uint64_t coordinate) noexcept
Definition ratchet.hpp:40
Definition beat_division.hpp:11
RatchetError
Definition ratchet.hpp:13
@ None
Definition ratchet.hpp:14
@ InvalidHitCount
Definition ratchet.hpp:16
@ InvalidInterval
Definition ratchet.hpp:15
@ InvalidWindow
Definition ratchet.hpp:19
@ InsufficientResolution
Definition ratchet.hpp:18
@ OutputTooSmall
Definition ratchet.hpp:20
@ CapacityExceeded
Definition ratchet.hpp:17
constexpr RatchetProjectionResult project_ratchet_interval(TickPosition interval_begin, TickPosition interval_end, std::size_t hit_count, TickPosition window_begin, TickPosition window_end, std::span< TickPosition > output) noexcept
Projects a bounded ratchet burst into an exact clock interval.
Definition ratchet.hpp:87
@ None
Definition grid_projection.hpp:97
@ OutputTooSmall
Definition grid_projection.hpp:104
std::size_t event_count
Definition ratchet.hpp:25
RatchetError error
Definition ratchet.hpp:24
Definition tick.hpp:61