Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
panic.hpp File Reference

Pure MIDI 1.0 "panic" message generation and classification. More...

#include <pulp/midi/keyboard_state.hpp>
#include <pulp/midi/message.hpp>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <span>

Go to the source code of this file.

Classes

struct  pulp::midi::PanicScope
 Which channels and which message kinds a panic covers. More...

Namespaces

namespace  pulp
namespace  pulp::midi
namespace  pulp::midi::panic_detail

Enumerations

enum class  pulp::midi::PanicMessageKind : std::uint8_t {
  pulp::midi::all_sound_off , pulp::midi::all_notes_off , pulp::midi::reset_all_controllers , pulp::midi::sustain_off ,
  pulp::midi::pitch_bend_centre
}
 One kind of message a panic can contain. More...

Functions

constexpr std::size_t pulp::midi::panic_detail::kind_count (const PanicScope &scope)
constexpr unsigned pulp::midi::panic_detail::popcount16 (std::uint16_t mask)
constexpr std::size_t pulp::midi::panic_message_count (const PanicScope &scope)
 Number of events panic_messages() will write for scope.
std::size_t pulp::midi::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.
template<typename Fn>
void pulp::midi::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, in channel then note order.
std::size_t pulp::midi::held_note_offs (const MidiKeyboardState &keys, std::span< MidiEvent > out, std::uint16_t channel_mask=0xFFFFu, std::int32_t sample_offset=0) noexcept
 Note-off events for exactly the notes keys reports as held, on the channels in channel_mask, in channel then note order.
std::size_t pulp::midi::all_note_offs (std::span< MidiEvent > out, std::uint16_t channel_mask=0xFFFFu, std::int32_t sample_offset=0) noexcept
 Brute-force fallback: a note-off for every key on the channels in channel_mask, whether or not it was tracked as held.
std::optional< PanicMessageKind > pulp::midi::classify_panic_message (const MidiEvent &event) noexcept
 Classify a message as one of the panic kinds, or nullopt for anything else.

Variables

constexpr std::size_t pulp::midi::kMaxPanicMessages = 16u * 5u
 Largest number of events panic_messages() can produce (16 channels x 5).
constexpr std::size_t pulp::midi::kMaxNoteOffs = 16u * 128u
 Largest number of events held_note_offs() / all_note_offs() can produce.
constexpr std::uint8_t pulp::midi::panic_detail::kCcSustain = 64
constexpr std::uint8_t pulp::midi::panic_detail::kCcResetAllControllers = 121
constexpr std::uint8_t pulp::midi::panic_detail::kCcAllSoundOff = 120
constexpr std::uint8_t pulp::midi::panic_detail::kCcAllNotesOff = 123
constexpr std::uint16_t pulp::midi::panic_detail::kPitchBendCentre = 8192

Detailed Description

Pure MIDI 1.0 "panic" message generation and classification.

A panic silences a receiver: it ends sounding notes, drops sustain, and puts the controllers it may have left displaced back at rest. Everything here is a plain function over caller-owned storage — no allocation, no locks, no state — so it is safe on the audio thread and can be unit tested without a host. The held-note source of truth is MidiKeyboardState; this header only turns its contents (or, as a fallback, "every key") into note-off events.

The messages used are the channel mode and controller messages the MIDI 1.0 specification defines for this purpose:

Message Meaning Receiver behaviour
CC 120 value 0 All Sound Off stop sounding immediately, release tails included
CC 123 value 0 All Notes Off release held notes through the normal release
CC 121 value 0 Reset All Controllers controllers return to their defaults
CC 64 value 0 Damper (sustain) off release notes the pedal was holding
Pitch bend 8192 Pitch wheel centre undo a bend left displaced

CC 120 and CC 123 are deliberately different: sending both is the safe panic (the immediate stop covers receivers that implement only one of them), and a "release-only" panic omits CC 120 so tails ring out.