Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
coordinate_random.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <bit>
7#include <compare>
8#include <cstdint>
9
10namespace pulp::timebase {
11
12// Stable musical coordinates replace mutable callback-local RNG state. The
13// same event therefore receives the same value regardless of block partition.
16 std::uint64_t lane = 0;
17 std::uint64_t cycle = 0;
18 std::uint64_t stream = 0;
19 constexpr auto operator<=>(const RandomCoordinate&) const = default;
20};
21
22namespace detail {
23
24constexpr std::uint64_t mix_coordinate(std::uint64_t value) noexcept {
25 value += 0x9e3779b97f4a7c15ULL;
26 value = (value ^ (value >> 30U)) * 0xbf58476d1ce4e5b9ULL;
27 value = (value ^ (value >> 27U)) * 0x94d049bb133111ebULL;
28 return value ^ (value >> 31U);
29}
30
31constexpr std::uint64_t multiply_high(std::uint64_t lhs, std::uint64_t rhs) noexcept {
32 const auto lhs_low = static_cast<std::uint64_t>(static_cast<std::uint32_t>(lhs));
33 const auto lhs_high = lhs >> 32U;
34 const auto rhs_low = static_cast<std::uint64_t>(static_cast<std::uint32_t>(rhs));
35 const auto rhs_high = rhs >> 32U;
36 const auto low_low = lhs_low * rhs_low;
37 const auto low_high = lhs_low * rhs_high;
38 const auto high_low = lhs_high * rhs_low;
39 const auto high_high = lhs_high * rhs_high;
40 const auto middle = (low_low >> 32U) + static_cast<std::uint32_t>(low_high) +
41 static_cast<std::uint32_t>(high_low);
42 return high_high + (low_high >> 32U) + (high_low >> 32U) + (middle >> 32U);
43}
44
45} // namespace detail
46
47constexpr std::uint64_t coordinate_random(std::uint64_t seed,
48 RandomCoordinate coordinate) noexcept {
49 auto value = detail::mix_coordinate(seed);
50 value = detail::mix_coordinate(value ^ std::bit_cast<std::uint64_t>(coordinate.tick.value));
51 value = detail::mix_coordinate(value ^ coordinate.lane);
52 value = detail::mix_coordinate(value ^ coordinate.cycle);
53 return detail::mix_coordinate(value ^ coordinate.stream);
54}
55
59
60// Exact probability predicate with no floating-point conversion. `numerator`
61// may equal denominator (always) and zero means never.
63coordinate_chance(std::uint64_t seed, RandomCoordinate coordinate, std::uint64_t numerator,
64 std::uint64_t denominator) noexcept {
65 if (denominator == 0 || numerator > denominator)
67 if (numerator == 0)
68 return runtime::Ok(false);
69 if (numerator == denominator)
70 return runtime::Ok(true);
71 // Multiply-high range reduction avoids modulo's strong low-bit patterns.
72 const auto bucket = detail::multiply_high(coordinate_random(seed, coordinate), denominator);
73 return runtime::Ok(bucket < numerator);
74}
75
76} // namespace pulp::timebase
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
Err(E) -> Err< E >
@ Ok
No error; bytes is authoritative.
Definition stream.hpp:32
Definition beat_division.hpp:52
constexpr std::uint64_t multiply_high(std::uint64_t lhs, std::uint64_t rhs) noexcept
Definition coordinate_random.hpp:31
constexpr std::uint64_t mix_coordinate(std::uint64_t value) noexcept
Definition coordinate_random.hpp:24
Definition beat_division.hpp:11
ProbabilityError
Definition coordinate_random.hpp:56
@ InvalidRatio
Definition coordinate_random.hpp:57
runtime::Result< bool, ProbabilityError > coordinate_chance(std::uint64_t seed, RandomCoordinate coordinate, std::uint64_t numerator, std::uint64_t denominator) noexcept
Definition coordinate_random.hpp:63
constexpr std::uint64_t coordinate_random(std::uint64_t seed, RandomCoordinate coordinate) noexcept
Definition coordinate_random.hpp:47
Result<T, E> — success / failure union for fallible operations.
Definition coordinate_random.hpp:14
std::uint64_t stream
Definition coordinate_random.hpp:18
TickPosition tick
Definition coordinate_random.hpp:15
std::uint64_t lane
Definition coordinate_random.hpp:16
std::uint64_t cycle
Definition coordinate_random.hpp:17
constexpr auto operator<=>(const RandomCoordinate &) const =default
Definition tick.hpp:61