50 SampleType
value = SampleType{0};
59 static_assert(std::is_floating_point_v<SampleType>);
60 static_assert(MaxPoints >= 2);
69 static constexpr std::uint32_t
kLoopForever = std::numeric_limits<std::uint32_t>::max();
73 points_[1] = {1.0, SampleType{1}, {}};
75 rebuild_sample_positions_();
84 rebuild_sample_positions_();
94 if (
points.size() > MaxPoints)
97 double previous_time = 0.0;
98 for (std::size_t
i = 0;
i <
points.size(); ++
i) {
100 if (!std::isfinite(point.time_ms) || point.time_ms < 0.0 ||
103 if (
i == 0 && point.time_ms != 0.0)
105 if (
i > 0 && point.time_ms < previous_time)
107 if (!std::isfinite(
static_cast<double>(point.value)))
109 previous_time = point.time_ms;
112 std::array<Point, MaxPoints> replacement{};
113 for (std::size_t
i = 0;
i <
points.size(); ++
i) {
117 points_ = replacement;
118 point_count_ =
points.size();
119 loop_enabled_ =
false;
120 loop_repeat_count_ = 0;
121 rebuild_sample_positions_();
129 std::uint32_t repeat_count)
noexcept {
130 if (repeat_count == 0) {
131 loop_enabled_ =
false;
132 loop_repeat_count_ = 0;
135 if (first_point >= last_point || last_point >= point_count_)
137 loop_first_point_ = first_point;
138 loop_last_point_ = last_point;
139 loop_repeat_count_ = repeat_count;
140 loop_enabled_ =
true;
145 loop_enabled_ =
false;
146 loop_repeat_count_ = 0;
151 pending_loop_restart_ =
false;
152 current_segment_ = 0;
153 segment_position_ = 0;
154 loops_completed_ = 0;
155 value_ = points_[0].value;
156 skip_zero_length_segments_();
161 pending_loop_restart_ =
false;
162 current_segment_ = 0;
163 segment_position_ = 0;
164 loops_completed_ = 0;
165 value_ = points_[0].value;
171 if (pending_loop_restart_) {
173 skip_zero_length_segments_();
178 const std::uint64_t length = segment_length_samples_(current_segment_);
180 const SampleType
progress = length == 0 ? SampleType{1}
181 :
static_cast<SampleType
>(segment_position_) /
182 static_cast<SampleType
>(length);
184 points_[current_segment_ + 1].value,
progress,
185 points_[current_segment_].curve_to_next);
186 if (segment_position_ >= length) {
188 if (active_ && !pending_loop_restart_)
189 skip_zero_length_segments_();
194 void process(std::span<SampleType> output)
noexcept {
195 for (
auto& sample : output)
209 return current_segment_;
212 return segment_position_;
215 return loops_completed_;
220 std::span<const Point>
points() const noexcept {
221 return {points_.data(), point_count_};
225 std::uint64_t time_to_samples_(
double time_ms)
const noexcept {
226 const long double samples =
227 static_cast<long double>(time_ms) *
static_cast<long double>(sample_rate_) / 1000.0L;
228 return static_cast<std::uint64_t
>(std::llround(samples));
231 void rebuild_sample_positions_() noexcept {
232 for (std::size_t
i = 0;
i < point_count_; ++
i)
233 point_samples_[
i] = time_to_samples_(points_[
i].time_ms);
236 std::uint64_t segment_length_samples_(std::size_t segment)
const noexcept {
237 return point_samples_[segment + 1] - point_samples_[segment];
240 bool should_repeat_loop_() const noexcept {
241 return loop_enabled_ && current_segment_ + 1 == loop_last_point_ &&
242 (loop_repeat_count_ ==
kLoopForever || loops_completed_ < loop_repeat_count_);
245 void finish_segment_() noexcept {
246 if (should_repeat_loop_()) {
249 pending_loop_restart_ =
true;
254 segment_position_ = 0;
255 if (current_segment_ + 1 >= point_count_) {
257 current_segment_ = point_count_ - 1;
262 void restart_loop_() noexcept {
263 pending_loop_restart_ =
false;
264 current_segment_ = loop_first_point_;
265 segment_position_ = 0;
266 value_ = points_[loop_first_point_].value;
269 void skip_zero_length_segments_() noexcept {
270 for (std::size_t visited = 0; active_ && visited < MaxPoints; ++visited) {
271 if (current_segment_ + 1 >= point_count_) {
273 current_segment_ = point_count_ - 1;
274 value_ = points_[point_count_ - 1].value;
277 if (segment_length_samples_(current_segment_) != 0)
279 value_ = points_[current_segment_ + 1].value;
281 if (pending_loop_restart_)
288 pending_loop_restart_ =
false;
292 std::array<Point, MaxPoints> points_{};
293 std::array<std::uint64_t, MaxPoints> point_samples_{};
294 std::size_t point_count_ = 0;
295 std::size_t current_segment_ = 0;
296 std::size_t loop_first_point_ = 0;
297 std::size_t loop_last_point_ = 1;
298 std::uint64_t segment_position_ = 0;
299 std::uint32_t loop_repeat_count_ = 0;
300 std::uint32_t loops_completed_ = 0;
302 SampleType value_ = SampleType{0};
303 bool active_ =
false;
304 bool loop_enabled_ =
false;
305 bool pending_loop_restart_ =
false;
Definition breakpoint_envelope.hpp:58
SampleType current() const noexcept
Definition breakpoint_envelope.hpp:199
std::size_t point_count() const noexcept
Definition breakpoint_envelope.hpp:205
double sample_rate() const noexcept
Definition breakpoint_envelope.hpp:217
void trigger() noexcept
Definition breakpoint_envelope.hpp:149
BreakpointEnvelopeStatus configure(std::span< const Point > points) noexcept
Replaces the complete program transactionally.
Definition breakpoint_envelope.hpp:91
static constexpr double kDefaultSampleRate
Definition breakpoint_envelope.hpp:65
std::uint64_t segment_position_samples() const noexcept
Definition breakpoint_envelope.hpp:211
bool active() const noexcept
Definition breakpoint_envelope.hpp:202
static constexpr double kMaxProgramTimeMs
Definition breakpoint_envelope.hpp:68
void clear_loop() noexcept
Definition breakpoint_envelope.hpp:144
void process(std::span< SampleType > output) noexcept
Definition breakpoint_envelope.hpp:194
BreakpointEnvelopeStatus set_loop(std::size_t first_point, std::size_t last_point, std::uint32_t repeat_count) noexcept
Repeats the range from first_point through last_point.
Definition breakpoint_envelope.hpp:128
SampleType next() noexcept
Definition breakpoint_envelope.hpp:168
BreakpointEnvelopeT() noexcept
Definition breakpoint_envelope.hpp:71
std::size_t current_segment() const noexcept
Definition breakpoint_envelope.hpp:208
BreakpointEnvelopeStatus prepare(double sample_rate) noexcept
Definition breakpoint_envelope.hpp:79
static constexpr double kMinSampleRate
Definition breakpoint_envelope.hpp:66
static constexpr std::uint32_t kLoopForever
Definition breakpoint_envelope.hpp:69
static constexpr double kMaxSampleRate
Definition breakpoint_envelope.hpp:67
std::uint32_t loops_completed() const noexcept
Definition breakpoint_envelope.hpp:214
std::span< const Point > points() const noexcept
Definition breakpoint_envelope.hpp:220
BreakpointEnvelopePointT< SampleType > Point
Definition breakpoint_envelope.hpp:63
void reset() noexcept
Definition breakpoint_envelope.hpp:159
A shared, allocation-free curve vocabulary for modulation segments.
Definition additive_bank.hpp:218
SampleType interpolate_modulation_curve(SampleType start, SampleType end, ProgressType progress, ModulationCurve curve={}) noexcept
Definition modulation_curve.hpp:97
ModulationCurve sanitize_modulation_curve(ModulationCurve curve) noexcept
Definition modulation_curve.hpp:42
@ invalid_sample_rate
Definition auto_ducked_send.hpp:18
@ i
Definition formant_filter_bank.hpp:20
BreakpointEnvelopeT< float > BreakpointEnvelope
Definition breakpoint_envelope.hpp:308
BreakpointEnvelopePointT< double > BreakpointEnvelopePoint64
Definition breakpoint_envelope.hpp:56
BreakpointEnvelopeT< double > BreakpointEnvelope64
Definition breakpoint_envelope.hpp:309
BreakpointEnvelopeStatus
Definition breakpoint_envelope.hpp:35
@ invalid_time
Definition breakpoint_envelope.hpp:39
@ invalid_value
Definition breakpoint_envelope.hpp:41
@ ok
Definition breakpoint_envelope.hpp:36
@ invalid_sample_rate
Definition breakpoint_envelope.hpp:42
@ too_few_points
Definition breakpoint_envelope.hpp:37
@ invalid_loop
Definition breakpoint_envelope.hpp:43
@ times_not_ordered
Definition breakpoint_envelope.hpp:40
@ too_many_points
Definition breakpoint_envelope.hpp:38
BreakpointEnvelopePointT< float > BreakpointEnvelopePoint
Definition breakpoint_envelope.hpp:55
@ progress
Definition finite_stretch_builder.hpp:30
Definition breakpoint_envelope.hpp:46
ModulationCurve curve_to_next
Definition breakpoint_envelope.hpp:52
float value
Definition breakpoint_envelope.hpp:50
double time_ms
Definition breakpoint_envelope.hpp:48
Curve strength is dimensionless and legal in [0, 1].
Definition modulation_curve.hpp:37