13 static_assert(MaximumActiveNotes < std::numeric_limits<std::uint32_t>::max());
21 return spec.length_samples > 0;
25 constexpr bool valid() const noexcept {
31 std::int32_t block_samples)
noexcept {
33 return {0, input.size(), 0,
false};
35 current_block_start_ = block_start.value;
36 const auto block_sample_count = std::max<std::int64_t>(0, block_samples);
39 account_unprocessed_input(input);
40 return {0, input.size(), 0,
false};
42 if (!valid_ || block_samples < 0) {
43 account_unprocessed_input(input);
44 return {0, input.size(), 0,
false};
46 if (!drain_release_debt(output, report)) {
47 account_unprocessed_input(input);
50 emit_due(output, report, block_start);
51 for (
const auto& event : input) {
54 emit_due(output, report, {absolute});
55 const bool is_attack =
event.is_note_on() &&
event.velocity() != 0;
56 const bool is_release =
event.is_note_off() ||
57 (
event.is_note_on() && event.velocity() == 0);
58 const bool is_note = is_attack || is_release;
61 if (is_note && quarantined_[event_key]) {
67 if (!release_matching(event.channel(), event.note(), event.sample_offset, output,
69 track_suppressed(event_key);
72 Slot* slot = free_slot();
73 if (slot ==
nullptr) {
75 if (!can_track_fail_open(key)) {
76 track_overflow_suppressed(key);
80 track_passthrough(key);
82 track_suppressed(key);
90 if (next_serial_ == std::numeric_limits<std::uint32_t>::max())
91 rebase_slot_serials();
92 *slot = {
event.channel(),
100 }
else if (is_release) {
101 const int key = event_key;
102 release_fail_open(key, event, output, report);
107 const auto last_sample = block_sample_count > 0 ? block_sample_count - 1 : 0;
108 emit_due(output, report,
119 return {0, 0, 0,
false};
120 if (!drain_release_debt(output, report))
122 for (
auto& slot : slots_) {
132 for (
int key = 0; key < 16 * 128; ++key) {
133 while (passthrough_depth_[key] != 0) {
136 static_cast<std::uint8_t
>(key % 128)),
142 --passthrough_depth_[key];
145 suppressed_depth_.fill(0);
146 overflow_suppressed_.fill(0);
147 ownership_run_size_ = 0;
148 quarantined_.fill(
false);
149 if (
empty() && pending_spec_) {
150 spec_ = *pending_spec_;
152 pending_spec_.reset();
159 return flush(output);
165 return {0, 0, 0,
false};
167 auto report =
flush(output);
168 if (report.complete) {
172 pending_spec_ = spec;
178 for (
const auto& slot : slots_)
181 for (
const auto debt : release_debt_)
184 for (
const auto depth : passthrough_depth_)
187 for (
const bool quarantined : quarantined_)
195 std::uint8_t channel = 0;
196 std::uint8_t note = 0;
197 std::uint8_t velocity = 0;
198 std::int64_t release_sample = 0;
199 std::int64_t activation_block_start = 0;
200 std::int32_t minimum_release_offset = 0;
201 std::uint32_t serial = 0;
205 struct FailOpenOwnershipRun {
206 std::uint16_t key = 0;
207 std::uint32_t count = 0;
208 bool forwarded =
false;
210 static constexpr std::size_t kMaxOwnershipRuns = 4096;
212 template <
typename Counter>
static bool increment_checked(Counter& value)
noexcept {
213 if (value != std::numeric_limits<Counter>::max()) {
220 void track_suppressed(
int key)
noexcept {
221 if (overflow_suppressed_[key] != 0 ||
222 ownership_run_size_ == ownership_runs_.size()) {
223 track_overflow_suppressed(key);
226 if (!increment_checked(suppressed_depth_[key]) ||
227 !append_ownership_run(key,
false))
228 quarantined_[key] =
true;
231 void track_passthrough(
int key)
noexcept {
232 if (!increment_checked(passthrough_depth_[key]) ||
233 !append_ownership_run(key,
true))
234 quarantined_[key] =
true;
237 bool can_track_fail_open(
int key)
const noexcept {
238 if (overflow_suppressed_[key] != 0)
return false;
239 if (passthrough_depth_[key] == std::numeric_limits<std::uint32_t>::max() ||
240 suppressed_depth_[key] == std::numeric_limits<std::uint32_t>::max())
242 return ownership_run_size_ < ownership_runs_.size();
245 void track_overflow_suppressed(
int key)
noexcept {
246 if (!increment_checked(overflow_suppressed_[key]))
247 quarantined_[key] =
true;
250 bool append_ownership_run(
int key,
bool forwarded)
noexcept {
251 for (std::size_t i = ownership_run_size_;
i != 0; --
i) {
252 auto& previous = ownership_runs_[
i - 1];
253 if (previous.key != key)
continue;
254 if (previous.forwarded == forwarded &&
255 previous.count != std::numeric_limits<std::uint32_t>::max()) {
261 if (ownership_run_size_ == ownership_runs_.size())
return false;
262 ownership_runs_[ownership_run_size_++] = {
263 static_cast<std::uint16_t
>(key), 1, forwarded};
267 void release_fail_open(
int key,
const MidiEvent& event, MidiBuffer& output,
268 MidiUtilityProcessReport& report)
noexcept {
269 release_fail_open_impl(key, [&](
bool forwarded) {
271 track_release_debt(key);
275 template <
typename Release>
276 void release_fail_open_impl(
int key, Release&& release)
noexcept {
277 for (std::size_t i = 0;
i < ownership_run_size_; ++
i) {
278 auto&
run = ownership_runs_[
i];
279 if (
run.key != key)
continue;
281 --passthrough_depth_[key];
283 --suppressed_depth_[key];
286 if (--
run.count == 0) erase_ownership_run(i);
289 if (overflow_suppressed_[key] != 0)
290 --overflow_suppressed_[key];
293 void erase_ownership_run(std::size_t index)
noexcept {
294 for (std::size_t i = index + 1;
i < ownership_run_size_; ++
i)
295 ownership_runs_[i - 1] = ownership_runs_[i];
296 --ownership_run_size_;
299 void track_release_debt(
int key)
noexcept {
300 if (!increment_checked(release_debt_[key]))
301 quarantined_[key] =
true;
304 Slot* free_slot() noexcept {
305 for (
auto& slot : slots_)
311 void rebase_slot_serials() noexcept {
312 std::array<std::uint32_t, MaximumActiveNotes> rebased{};
313 std::uint32_t rank = 1;
315 std::size_t oldest_index = MaximumActiveNotes;
316 for (std::size_t i = 0;
i < MaximumActiveNotes; ++
i) {
317 if (!slots_[i].active || rebased[i] != 0)
319 if (oldest_index == MaximumActiveNotes ||
320 slots_[i].serial < slots_[oldest_index].serial)
323 if (oldest_index == MaximumActiveNotes)
325 rebased[oldest_index] = rank++;
327 for (std::size_t i = 0;
i < MaximumActiveNotes; ++
i)
328 slots_[i].serial = rebased[i];
332 bool release_matching(std::uint8_t channel, std::uint8_t note, std::int32_t offset,
333 MidiBuffer& output, MidiUtilityProcessReport& report)
noexcept {
336 for (
auto& slot : slots_) {
337 if (slot.active && slot.channel == channel && slot.note == note &&
338 (oldest ==
nullptr || slot.serial <
oldest->serial))
341 if (oldest ==
nullptr)
350 void emit_due(MidiBuffer& output, MidiUtilityProcessReport& report,
351 timebase::SamplePosition until)
noexcept {
354 for (
auto& slot : slots_) {
355 if (!slot.active || slot.release_sample > until.value)
357 if (due ==
nullptr || slot.release_sample < due->release_sample ||
358 (slot.release_sample == due->release_sample && slot.serial < due->serial))
363 std::int32_t offset = release_offset(*due);
371 if (
empty() && pending_spec_) {
372 spec_ = *pending_spec_;
374 pending_spec_.reset();
378 std::int32_t release_offset(
const Slot& slot)
const noexcept {
379 std::uint64_t distance = 0;
380 if (slot.release_sample > current_block_start_) {
381 distance =
static_cast<std::uint64_t
>(slot.release_sample) -
382 static_cast<std::uint64_t
>(current_block_start_);
384 auto offset =
static_cast<std::int32_t
>(std::min<std::uint64_t>(
385 distance,
static_cast<std::uint64_t
>(std::numeric_limits<std::int32_t>::max())));
386 if (slot.activation_block_start == current_block_start_)
387 offset = std::max(offset, slot.minimum_release_offset);
391 bool drain_release_debt(MidiBuffer& output, MidiUtilityProcessReport& report)
noexcept {
392 for (
int key = 0; key < 16 * 128; ++key) {
393 while (release_debt_[key] != 0) {
396 static_cast<std::uint8_t
>(key % 128)),
401 --release_debt_[key];
407 void account_unprocessed_input(
const MidiBuffer& input)
noexcept {
408 for (
const auto& event : input) {
409 const bool is_attack =
event.is_note_on() &&
event.velocity() != 0;
410 const bool is_release =
event.is_note_off() ||
411 (
event.is_note_on() && event.velocity() == 0);
412 if (!is_attack && !is_release)
415 if (quarantined_[key])
418 track_suppressed(key);
419 }
else if (is_release) {
420 release_fail_open_impl(key, [&](
bool forwarded) {
421 if (forwarded) track_release_debt(key);
427 NoteLengthSpec spec_{};
429 std::optional<NoteLengthSpec> pending_spec_;
430 std::array<Slot, MaximumActiveNotes> slots_{};
431 std::array<std::uint32_t, 16 * 128> passthrough_depth_{};
432 std::array<std::uint32_t, 16 * 128> suppressed_depth_{};
433 std::array<std::uint32_t, 16 * 128> release_debt_{};
434 std::array<std::uint32_t, 16 * 128> overflow_suppressed_{};
435 std::array<bool, 16 * 128> quarantined_{};
436 std::array<FailOpenOwnershipRun, kMaxOwnershipRuns> ownership_runs_{};
437 std::size_t ownership_run_size_ = 0;
438 std::uint32_t next_serial_ = 1;
439 std::int64_t current_block_start_ = 0;
469 "Serial must represent every held MIDI key plus the next-order sentinel");
477 : spec_(sanitize(spec)) {}
481 return {0, input.size(), 0,
false};
485 return {0, input.size(), 0,
false};
486 reconcile(0, output, report);
487 for (
const auto& event : input) {
488 const bool is_attack =
event.is_note_on() &&
event.velocity() != 0;
489 const bool is_release =
event.is_note_off() ||
490 (
event.is_note_on() && event.velocity() == 0);
493 if (held_depth_[key] != std::numeric_limits<std::uint32_t>::max())
495 velocity_[key] =
event.velocity();
496 if (next_serial_ == std::numeric_limits<Serial>::max())
498 serial_[key] = next_serial_++;
499 reconcile(event.sample_offset, output, report);
500 }
else if (is_release) {
502 if (held_depth_[key] != 0)
504 reconcile(event.sample_offset, output, report);
515 if (!pitch_.active || !pitch_.glide_active)
517 if (spec_.glide_seconds <= 0.0 || sample_rate <= 0.0 || !std::isfinite(sample_rate)) {
518 pitch_.current_note = pitch_.target_note;
519 pitch_.glide_active =
false;
522 const double coefficient =
523 std::exp(-
static_cast<double>(samples) / (sample_rate * spec_.glide_seconds));
524 pitch_.current_note =
static_cast<float>(
525 pitch_.target_note + (pitch_.current_note - pitch_.target_note) * coefficient);
526 if (std::abs(pitch_.current_note - pitch_.target_note) < 1.0e-5f) {
527 pitch_.current_note = pitch_.target_note;
528 pitch_.glide_active =
false;
536 return {0, 0, 0,
false};
548 spec_ = *pending_spec_;
549 pending_spec_.reset();
555 return flush(output);
559 auto report =
flush(output);
561 spec_ = sanitize(spec);
563 pending_spec_ = sanitize(spec);
573 if (!(spec.glide_seconds >= 0.0) || !std::isfinite(spec.glide_seconds))
574 spec.glide_seconds = 0.0;
578 int selected_key() const noexcept {
580 for (
int key = 0; key < 16 * 128; ++key) {
581 if (held_depth_[key] == 0)
587 const int note = key % 128;
588 const int selected_note = selected % 128;
597 void rebase_serials() noexcept {
598 std::array<Serial, 16 * 128> rebased{};
602 for (
int key = 0; key < 16 * 128; ++key) {
603 if (held_depth_[key] == 0 || rebased[key] != 0)
605 if (oldest < 0 || serial_[key] < serial_[oldest] ||
606 (serial_[key] == serial_[oldest] && key < oldest))
617 void reconcile(std::int32_t offset, MidiBuffer& output,
618 MidiUtilityProcessReport& report)
noexcept {
619 const int next = selected_key();
624 const bool overlapping = pitch_.active && next >= 0;
625 const float previous_pitch = pitch_.current_note;
632 pitch_.active =
false;
638 const auto channel =
static_cast<std::uint8_t
>(next / 128);
639 const auto note =
static_cast<std::uint8_t
>(next % 128);
645 pitch_.active =
true;
646 pitch_.legato = overlapping && spec_.legato;
647 pitch_.channel = channel;
649 pitch_.target_note =
static_cast<float>(note);
650 pitch_.current_note = pitch_.legato ? previous_pitch : pitch_.target_note;
651 pitch_.glide_active = pitch_.legato && spec_.glide_seconds > 0.0;
654 MonophonicSpec spec_{};
655 std::optional<MonophonicSpec> pending_spec_;
656 std::array<std::uint32_t, 16 * 128> held_depth_{};
657 std::array<std::uint8_t, 16 * 128> velocity_{};
658 std::array<Serial, 16 * 128> serial_{};
659 Serial next_serial_ = 1;
660 MonophonicPitchState pitch_{};