35 std::span<const GrooveKernelStep>
steps{};
56class OrderPreservingGrooveKernel {
60 if (input.swing_grid.value < 0 ||
65 if ((input.table_grid.value != 0) != !input.steps.empty() || input.table_grid.value < 0 ||
73 for (
const auto& step : input.steps) {
74 if (step.timing_offset.value <= -input.table_grid.value ||
75 step.timing_offset.value >= input.table_grid.value)
81 OrderPreservingGrooveKernel result(input);
82 const auto order = result.validate_order();
97 std::span<const GrooveKernelStep>
steps() const noexcept {
98 return {steps_.data(), size_};
101 return timing_strength_;
104 return velocity_strength_;
109 std::int64_t swing_offset = 0;
110 if (swing_grid_.value != 0)
111 swing_offset = scaled_by_strength(
113 std::int64_t table_offset = 0;
114 if (
const auto* step = step_at(authored)) {
115 table_offset = scaled_by_strength(step->timing_offset.value, timing_strength_);
117 std::int64_t displacement = 0;
118 if (!checked_add(swing_offset, table_offset, displacement))
120 std::int64_t transformed = 0;
121 if (!checked_add(authored.value, displacement, transformed))
127 const auto* step = step_at(authored);
130 const auto deviation =
133 scaled_by_strength(deviation, velocity_strength_));
138 : swing_grid_(input.swing_grid), swing_(input.swing), table_grid_(input.table_grid),
139 size_(input.steps.size()), timing_strength_(input.timing_strength),
140 velocity_strength_(input.velocity_strength) {
141 for (std::size_t index = 0; index < size_; ++index)
142 steps_[index] = input.
steps[index];
145 static constexpr bool checked_add(std::int64_t lhs, std::int64_t rhs,
146 std::int64_t& result)
noexcept {
147 constexpr auto min = std::numeric_limits<std::int64_t>::min();
148 constexpr auto max = std::numeric_limits<std::int64_t>::max();
149 if ((rhs > 0 && lhs > max - rhs) || (rhs < 0 && lhs < min - rhs))
155 static constexpr std::int64_t scaled_by_strength(std::int64_t value,
156 std::int32_t strength)
noexcept {
157 if (value == 0 || strength == 0)
159 const auto negative = value < 0;
160 const auto magnitude = negative ?
static_cast<std::uint64_t
>(-(value + 1)) + 1U
161 : static_cast<
std::uint64_t>(value);
165 whole *
static_cast<std::uint32_t
>(strength) +
169 return static_cast<std::int64_t
>(scaled);
170 if (scaled == (std::uint64_t{1} << 63U))
171 return std::numeric_limits<std::int64_t>::min();
172 return -
static_cast<std::int64_t
>(scaled);
175 const GrooveKernelStep* step_at(TickPosition authored)
const noexcept {
178 auto index = authored.value / table_grid_.value;
179 if (authored.value % table_grid_.value < 0)
181 auto slot =
index %
static_cast<std::int64_t
>(size_);
183 slot +=
static_cast<std::int64_t
>(size_);
184 return &steps_[
static_cast<std::size_t
>(slot)];
188 if (timing_strength_ == 0)
193 const auto swing_period = swing_grid_.value == 0 ? std::int64_t{1} : 2 * swing_grid_.value;
194 const auto phase_count = swing_period / std::gcd(swing_period, table_grid_.value);
195 const auto step_count =
static_cast<std::int64_t
>(size_);
196 const auto divisor = std::gcd(phase_count, step_count);
200 const auto boundaries = phase_count * (step_count / divisor);
202 for (std::int64_t index = 1;
index <= boundaries; ++
index) {
203 const auto boundary =
index * table_grid_.value;
206 if (!before || !after)
208 if (before.value() > after.value())
214 TickDuration swing_grid_{};
216 TickDuration table_grid_{};
217 std::array<GrooveKernelStep, kMaximumGrooveKernelSteps> steps_{};
218 std::size_t size_ = 0;
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
Definition groove_kernel.hpp:56
runtime::Result< TickPosition, GrooveKernelError > apply_timing(TickPosition authored) const noexcept
Definition groove_kernel.hpp:108
std::int32_t velocity_scale_at(TickPosition authored) const noexcept
Definition groove_kernel.hpp:126
std::int32_t timing_strength() const noexcept
Definition groove_kernel.hpp:100
std::span< const GrooveKernelStep > steps() const noexcept
Definition groove_kernel.hpp:97
TickDuration swing_grid() const noexcept
Definition groove_kernel.hpp:88
std::int32_t velocity_strength() const noexcept
Definition groove_kernel.hpp:103
static runtime::Result< OrderPreservingGrooveKernel, GrooveKernelError > create(GrooveKernelInput input) noexcept
Definition groove_kernel.hpp:59
SwingRatio swing() const noexcept
Definition groove_kernel.hpp:91
TickDuration table_grid() const noexcept
Definition groove_kernel.hpp:94
@ index
Definition gpu_pass.hpp:140
@ Ok
No error; bytes is authoritative.
Definition stream.hpp:32
Definition beat_division.hpp:11
constexpr bool valid_swing_ratio(SwingRatio ratio) noexcept
Definition quantize.hpp:79
constexpr bool valid_swing_grid(TickDuration grid) noexcept
Definition quantize.hpp:72
TickDuration swing_displacement(TickPosition position, TickDuration grid, SwingRatio ratio) noexcept
Definition quantize.hpp:114
GrooveKernelError
Definition groove_kernel.hpp:40
@ ReordersEvents
Definition groove_kernel.hpp:48
@ ValidationLimitExceeded
Definition groove_kernel.hpp:49
@ InvalidSwing
Definition groove_kernel.hpp:43
@ None
Definition groove_kernel.hpp:41
@ InvalidTable
Definition groove_kernel.hpp:44
@ TooManySteps
Definition groove_kernel.hpp:45
@ RangeExceeded
Definition groove_kernel.hpp:50
@ InvalidStrength
Definition groove_kernel.hpp:46
@ InvalidSwingGrid
Definition groove_kernel.hpp:42
@ InvalidVelocityScale
Definition groove_kernel.hpp:47
constexpr std::int32_t kMaximumGrooveKernelVelocityScale
Definition groove_kernel.hpp:19
constexpr std::size_t kMaximumGrooveValidationBoundaries
Definition groove_kernel.hpp:21
constexpr std::int64_t kMaxSwingGridTicks
Definition quantize.hpp:69
@ RangeExceeded
Definition beat_division.hpp:49
constexpr std::size_t kMaximumGrooveKernelSteps
Definition groove_kernel.hpp:20
@ None
Definition grid_projection.hpp:97
constexpr std::int32_t kGrooveKernelUnitScale
Definition groove_kernel.hpp:18
constexpr SwingRatio kStraightSwing
Definition quantize.hpp:61
Result<T, E> — success / failure union for fallible operations.
Definition groove_kernel.hpp:23
std::int32_t velocity_scale
Definition groove_kernel.hpp:25
constexpr auto operator<=>(const GrooveKernelStep &) const =default
TickDuration timing_offset
Definition groove_kernel.hpp:24
Definition quantize.hpp:53