78 const auto wanted =
static_cast<std::uint8_t
>(mode);
79 auto current = pending_.load(std::memory_order_relaxed);
80 while (current < wanted &&
81 !pending_.compare_exchange_weak(current, wanted, std::memory_order_acq_rel,
82 std::memory_order_relaxed)) {
88 const auto taken = pending_.exchange(0, std::memory_order_acq_rel);
97 return carry_.load(std::memory_order_acquire) != 0;
106 return deferred_total_.load(std::memory_order_relaxed);
110 return pending_.load(std::memory_order_acquire) != 0;
116 midi_out_.store(midi_out, std::memory_order_relaxed);
117 attached_.store(
true, std::memory_order_release);
120 attached_.store(
false, std::memory_order_release);
124 const bool attached = attached_.load(std::memory_order_acquire);
125 return {attached, attached && midi_out_.load(std::memory_order_relaxed)};
131 if (!midi_out_.load(std::memory_order_relaxed))
133 for (
const auto& event : midi_out)
134 emitted_.process(event);
149 std::int32_t sample_offset = 0) noexcept {
155 if (!full && out.
add(event)) {
165 event.sample_offset = sample_offset;
167 emitted_.process(event);
171 std::array<midi::MidiEvent, midi::kMaxPanicMessages> messages;
173 std::size_t next = message_cursor_;
174 for (; next < count; ++next) {
175 if (!put(messages[next]))
180 message_cursor_ =
static_cast<std::uint16_t
>(next < count ? next : 0);
183 const auto wanted =
static_cast<std::uint8_t
>(mode);
184 if (carry_.load(std::memory_order_relaxed) < wanted)
185 carry_.store(wanted, std::memory_order_release);
186 deferred_total_.fetch_add(outcome.
events_deferred, std::memory_order_relaxed);
188 carry_.store(0, std::memory_order_release);
196 const auto carried = carry_.load(std::memory_order_acquire);
209 std::atomic<std::uint8_t> pending_{0};
210 std::atomic<std::uint8_t> carry_{0};
211 std::atomic<std::uint64_t> deferred_total_{0};
212 std::uint16_t message_cursor_ = 0;
213 std::atomic<bool> attached_{
false};
214 std::atomic<bool> midi_out_{
false};
215 midi::MidiKeyboardState emitted_;
224template <
typename Proc>
226 std::int32_t sample_offset = 0) noexcept {
228 const bool fresh =
state.take(mode);
229 bool carried =
false;
231 if (!
state.take_carry(mode))
235 state.restart_messages();
239 if (
state.take_carry(carried_mode) &&
240 static_cast<std::uint8_t
>(carried_mode) >
static_cast<std::uint8_t
>(mode))
242 processor.on_panic(mode);
244 if (!
state.capabilities().midi_out) {
250 auto outcome =
state.emit_midi(mode, midi_out, sample_offset);
251 outcome.carried = carried;
Collection of timestamped MIDI events within a single audio buffer period.
Definition buffer.hpp:31
bool add(const MidiEvent &event)
Append a MIDI event to the buffer.
Definition buffer.hpp:98
Tracks the state of all 128 MIDI keys across 16 channels.
Definition keyboard_state.hpp:35
Polyphonic key tracking with velocity and listener callbacks.
Pure MIDI 1.0 "panic" message generation and classification.
std::size_t panic_messages(const PanicScope &scope, std::span< MidiEvent > out, std::int32_t sample_offset=0) noexcept
Write the panic messages for scope into out, channel by channel.
Definition panic.hpp:113
void for_each_held_note(const MidiKeyboardState &keys, std::uint16_t channel_mask, Fn &&fn) noexcept(noexcept(fn(std::uint8_t{}, std::uint8_t{})))
Call fn(channel, note) for every key keys reports as held on the channels in channel_mask,...
Definition panic.hpp:147
SequencerStateChannel is the audio-safe transport for a plugin's structured NON-parameter state: the ...
Definition audio_device_manager.hpp:48
Timestamped MIDI event combining a choc::midi::ShortMessage with timing info.
Definition message.hpp:32
static MidiEvent note_off(uint8_t channel, uint8_t note, uint8_t velocity=0)
Create a Note Off event.
Definition message.hpp:54
Which channels and which message kinds a panic covers.
Definition panic.hpp:48
static constexpr PanicScope release_only()
Panic that lets release tails ring out (no CC 120).
Definition panic.hpp:59