3#include <pulp/music/detail/random_range.hpp>
24template <std::
size_t MaxSteps = 64>
27 static_assert(MaxSteps > 0,
"BinaryPattern capacity must be positive");
28 static constexpr std::size_t
capacity = MaxSteps;
31 bool fill =
false) noexcept {
36 for (std::size_t index = 0; index < size_; ++index)
37 values_[index] =
static_cast<std::uint8_t
>(
fill);
42 assign(std::span<const std::uint8_t> values)
noexcept {
43 if (values.size() > MaxSteps)
46 size_ = values.size();
47 for (std::size_t index = 0; index < size_; ++index)
48 values_[index] =
static_cast<std::uint8_t
>(values[index] != 0);
52 constexpr std::size_t
size() const noexcept {
return size_; }
53 constexpr bool empty() const noexcept {
return size_ == 0; }
55 [[nodiscard]]
constexpr std::optional<bool>
at(std::size_t index)
const noexcept {
58 return values_[index] != 0;
61 [[nodiscard]]
constexpr bool set(std::size_t index,
bool value)
noexcept {
64 values_[index] =
static_cast<std::uint8_t
>(value);
69 std::size_t result = 0;
70 for (std::size_t index = 0; index < size_; ++index)
71 result += values_[index] != 0;
78 std::array<std::uint8_t, MaxSteps> values_{};
79 std::size_t size_ = 0;
82template <std::
size_t MaxSteps = 64>
86 constexpr explicit operator bool() const noexcept {
95template <std::
size_t MaxSteps = 64>
96[[nodiscard]]
constexpr PatternResult<MaxSteps>
98 std::int64_t rotation = 0) noexcept {
104 if (steps > MaxSteps) {
108 if (pulses > steps) {
112 (void)result.
pattern.resize(steps);
116 std::size_t bucket = steps - pulses;
117 for (std::size_t step = 0; step < steps; ++step) {
119 if (bucket >= steps) {
121 (void)result.
pattern.set(step,
true);
124 const auto signed_steps =
static_cast<std::int64_t
>(steps);
125 auto normalized_rotation = rotation % signed_steps;
126 if (normalized_rotation < 0)
127 normalized_rotation += signed_steps;
128 if (normalized_rotation != 0) {
129 const auto shift =
static_cast<std::size_t
>(normalized_rotation);
130 const auto canonical = result.
pattern;
131 for (std::size_t destination = 0; destination < steps; ++destination) {
132 const auto source = (destination + steps - shift) % steps;
133 (void)result.
pattern.set(destination, *canonical.at(source));
153template <std::
size_t MaxSteps = 64>
171template <std::
size_t MaxSteps = 64>
174 static_assert(MaxSteps > 0,
"PatternWalker capacity must be positive");
203 [[nodiscard]]
constexpr std::optional<std::size_t>
207 return next_deterministic();
210 [[nodiscard]]
constexpr std::optional<std::size_t>
211 next(std::uint64_t random_word)
noexcept {
215 return static_cast<std::size_t
>(
216 detail::reduce_random_word(random_word, length_));
217 return next_deterministic();
220 constexpr std::size_t
length() const noexcept {
return length_; }
224 constexpr std::size_t next_deterministic() noexcept {
225 const auto result = cursor_;
228 cursor_ = (cursor_ + 1) % length_;
231 cursor_ = cursor_ == 0 ? length_ - 1 : cursor_ - 1;
242 constexpr void advance_ping_pong() noexcept {
245 if (direction_ > 0 && cursor_ + 1 == length_) {
248 }
else if (direction_ < 0 && cursor_ == 0) {
251 }
else if (direction_ > 0) {
258 std::size_t length_ = 0;
259 std::size_t cursor_ = 0;
269template <std::
size_t MaxSteps = 64>
270[[nodiscard]]
constexpr PatternResult<MaxSteps>
282 (void)result.
pattern.resize(input.size());
283 for (std::size_t index = 0; index < input.size(); ++index) {
284 const bool center = *input.at(index);
285 const bool left = index > 0 ? *input.at(index - 1)
287 ? *input.at(input.size() - 1)
289 const bool right = index + 1 < input.size() ? *input.at(index + 1)
293 const auto neighborhood =
static_cast<unsigned>((left ? 4u : 0u)
295 | (right ? 1u : 0u));
296 (void)result.
pattern.set(index, ((rule >> neighborhood) & 1u) != 0);
306template <std::
size_t MaxSteps = 64>
312 constexpr explicit operator bool() const noexcept {
319template <std::
size_t MaxSteps = 64>
320[[nodiscard]]
constexpr ShiftRegisterResult<MaxSteps>
322 std::uint64_t random_word)
noexcept {
329 if (chance.denominator == 0 || chance.numerator > chance.denominator) {
334 result.
output = *input.at(input.size() - 1);
335 if (chance.numerator != 0) {
336 result.
mutated = chance.numerator == chance.denominator
337 || detail::reduce_random_word(random_word, chance.denominator)
340 for (std::size_t index = input.size() - 1; index > 0; --index)
341 (void)result.
pattern.set(index, *input.at(index - 1));
Definition pattern.hpp:25
constexpr PatternError assign(std::span< const std::uint8_t > values) noexcept
Definition pattern.hpp:42
constexpr auto operator<=>(const BinaryPattern &) const =default
constexpr std::optional< bool > at(std::size_t index) const noexcept
Definition pattern.hpp:55
static constexpr std::size_t capacity
Definition pattern.hpp:28
constexpr bool set(std::size_t index, bool value) noexcept
Definition pattern.hpp:61
constexpr std::size_t size() const noexcept
Definition pattern.hpp:52
constexpr PatternError resize(std::size_t size, bool fill=false) noexcept
Definition pattern.hpp:30
constexpr bool empty() const noexcept
Definition pattern.hpp:53
constexpr std::size_t onset_count() const noexcept
Definition pattern.hpp:68
Definition pattern.hpp:172
constexpr std::optional< std::size_t > next() noexcept
Definition pattern.hpp:204
constexpr std::optional< std::size_t > next(std::uint64_t random_word) noexcept
Definition pattern.hpp:211
constexpr PatternWalkerMode mode() const noexcept
Definition pattern.hpp:221
constexpr PatternError configure(std::size_t length, PatternWalkerMode mode) noexcept
Definition pattern.hpp:177
constexpr void reset() noexcept
Definition pattern.hpp:198
constexpr std::size_t length() const noexcept
Definition pattern.hpp:220
constexpr PatternResult< MaxSteps > euclidean_pattern(std::size_t steps, std::size_t pulses, std::int64_t rotation=0) noexcept
Definition pattern.hpp:97
constexpr PatternResult< MaxSteps > cellular_evolve(const BinaryPattern< MaxSteps > &input, std::uint8_t rule, CellularBoundary boundary=CellularBoundary::wrap) noexcept
Definition pattern.hpp:271
PatternWalkerMode
Definition pattern.hpp:164
@ reverse
Definition pattern.hpp:166
@ random
Definition pattern.hpp:168
@ forward
Definition pattern.hpp:165
@ ping_pong
Definition pattern.hpp:167
@ fill
Event intended to supply regional variation.
Definition pattern_development.hpp:26
constexpr ShiftRegisterResult< MaxSteps > looping_shift_register(const BinaryPattern< MaxSteps > &input, MutationChance chance, std::uint64_t random_word) noexcept
Definition pattern.hpp:321
PatternError
Definition pattern.hpp:14
@ unsupported_recipe_version
Definition pattern.hpp:21
@ none
Definition pattern.hpp:15
@ invalid_mode
Definition pattern.hpp:20
@ capacity_exceeded
Definition pattern.hpp:17
@ pulses_exceed_steps
Definition pattern.hpp:18
@ invalid_probability
Definition pattern.hpp:19
@ empty_pattern
Definition pattern.hpp:16
@ none
Definition markov.hpp:15
@ capacity_exceeded
Definition markov.hpp:17
constexpr PatternResult< MaxSteps > materialize_pattern(EuclideanPatternRecipe recipe) noexcept
Definition pattern.hpp:155
constexpr std::uint16_t euclidean_pattern_recipe_version
Definition pattern.hpp:139
CellularBoundary
Definition pattern.hpp:264
@ fixed_off
Definition pattern.hpp:265
@ wrap
Definition pattern.hpp:266
Definition pattern.hpp:144
std::uint16_t version
Definition pattern.hpp:145
constexpr auto operator<=>(const EuclideanPatternRecipe &) const =default
std::int64_t rotation
Definition pattern.hpp:148
std::uint16_t steps
Definition pattern.hpp:146
std::uint16_t pulses
Definition pattern.hpp:147
Definition pattern.hpp:301
std::uint32_t denominator
Definition pattern.hpp:303
std::uint32_t numerator
Definition pattern.hpp:302
Definition pattern.hpp:83
PatternError error
Definition pattern.hpp:85
BinaryPattern< MaxSteps > pattern
Definition pattern.hpp:84
Definition pattern.hpp:307
PatternError error
Definition pattern.hpp:309
bool mutated
Definition pattern.hpp:311
BinaryPattern< MaxSteps > pattern
Definition pattern.hpp:308
bool output
Definition pattern.hpp:310