Namespaces | |
| namespace | arpeggiator_detail |
| namespace | panic_detail |
| namespace | detail |
| namespace | routing_detail |
| namespace | step_player_detail |
| namespace | utility_detail |
Classes | |
| struct | ArpeggiatorGate |
| struct | ArpeggiatorSpec |
| struct | ArpeggiatorBlock |
| Block timing for one sample-accurate arpeggiator call. More... | |
| struct | ArpeggiatorCapacityContract |
| class | Arpeggiator |
| Fixed-capacity, sample-accurate MIDI arpeggiator. More... | |
| struct | BleMidiPeripheral |
| One BLE peripheral that advertises the BLE-MIDI service. More... | |
| class | BleMidiCentral |
| Cross-platform BLE MIDI central. More... | |
| struct | BleMidiUuids |
| The well-known service / characteristic UUIDs (16-byte big-endian). More... | |
| class | BleMidiPacketDecoder |
| Stateful decoder. More... | |
| class | BleMidiPortRegistry |
| Singleton bridge between BLE-MIDI centrals and the platform MidiSystem. More... | |
| class | MidiBuffer |
| Collection of timestamped MIDI events within a single audio buffer period. More... | |
| struct | ChordMemorySpec |
| class | ChordMemory |
| Bounded chord memory: capture a chord once, then play it from single notes. More... | |
| struct | ControllerMapRule |
| class | ControllerMapper |
| struct | ScaleAwareMpeSpec |
| class | ScaleAwareMpePitch |
| struct | MidiPortInfo |
| class | MidiInput |
| class | MidiOutput |
| class | MidiSystem |
| struct | HumanizeSpec |
| Seeded timing and velocity jitter over note attacks. More... | |
| class | Humanize |
| MaximumPendingAttacks bounds how many attacks can sit in the jitter window at once. More... | |
| class | MidiKeyboardState |
| Tracks the state of all 128 MIDI keys across 16 channels. More... | |
| struct | LatchSpec |
| class | Latch |
| Bounded note-retention kernel over a MIDI event stream. More... | |
| struct | MidiEvent |
| Timestamped MIDI event combining a choc::midi::ShortMessage with timing info. More... | |
| struct | TimestampedShortMessage |
| Timestamped MIDI event in the collector queue. More... | |
| struct | MidiMessageCollectorTelemetry |
| class | MidiMessageCollector |
| struct | MUID |
| MIDI-CI MUID (Message Unique Identifier) — 28-bit random ID. More... | |
| struct | CiDeviceInfo |
| CI device identity (from discovery). More... | |
| struct | ProfileId |
| CI Profile identifier (5 bytes). More... | |
| struct | ProfileState |
| CI Profile state. More... | |
| struct | FunctionBlockId |
| UMP Function Block identifier (MIDI 2.0 §A) — a Function Block is a logical grouping of UMP groups that share a single set of CI / Profile state. More... | |
| struct | FunctionBlockInfo |
| Description of a single Function Block as advertised by an endpoint. More... | |
| struct | ProfileDetails |
| Profile Details Inquiry/Reply payload (CI 1.2 §7.6) — per-profile metadata the responder publishes when asked for "more about profile X". More... | |
| class | CiDiscovery |
| MIDI-CI Discovery manager — handles CI message exchange. More... | |
| struct | PeChunk |
| A single PE chunk, after Mcoded7 decode of header + payload. More... | |
| class | PeReassembler |
| Reassemble a stream of incoming PeChunks for the same request_id. More... | |
| struct | PeSubscription |
| One active subscription state — owned by PeSubscriptionManager. More... | |
| class | PeSubscriptionManager |
| Authoritative subscription registry on the responder side. More... | |
| class | MidiControlBus |
| struct | TimedMidiEvent |
| struct | MidiTrack |
| struct | MidiFileData |
| struct | TimestampedMidiEvent |
| A MIDI event with timestamp (in seconds or samples). More... | |
| class | MidiMessageSequence |
| Ordered sequence of MIDI events with editing operations. More... | |
| class | MockMidiSystem |
| class | MonotonicMidiClock |
| Monotonic timestamp source for MIDI input events, measured in seconds from a base captured when the port opened. More... | |
| struct | MpeExpressionEvent |
| A single per-note expression event. More... | |
| class | MpeBuffer |
| A time-ordered list of per-note expression events for one block. More... | |
| struct | MpeMessageList |
| Fixed-capacity, allocation-free list of events returned by the builders. More... | |
| class | MpeSynthVoice |
| Abstract base for a single MPE voice. More... | |
| struct | MpeVoiceAllocatorTelemetry |
| struct | MpeVoiceAllocatorRuntimeBudgetReport |
| class | MpeGlideDetector |
| Glide/legato detector — observes MPE note-on events and reports when a new note on the same channel overlaps an existing held note. More... | |
| class | MpeVoiceAllocator |
| Routes MPE expression events to a pool of voices of type Voice (which must derive from MpeSynthVoice). More... | |
| struct | MpeNoteState |
| Per-note state maintained by MpeVoiceTracker. More... | |
| class | MpeVoiceTracker |
| Tracks MPE voice state across channels. More... | |
| struct | NoteDelaySpec |
| MIDI note delay / echo. More... | |
| class | NoteDelay |
| MaximumHeldSources bounds how many authored notes can have armed echoes at once. More... | |
| struct | NoteRepeatSpec |
| Clock-divided note repeat / retrigger. More... | |
| class | NoteRepeat |
| struct | NoteLengthSpec |
| class | NoteLengthShaper |
| struct | MonophonicSpec |
| struct | MonophonicPitchState |
| class | BasicMonophonicNoteSelector |
| struct | PanicScope |
| Which channels and which message kinds a panic covers. More... | |
| struct | PortListDiff |
| Ports that appeared and ports that went away between two snapshots. More... | |
| class | PortListTracker |
| Remembers the last snapshot and reports what changed since. More... | |
| class | PortChangePoller |
| Calls on_change from a background thread whenever the combined input and output list changes. More... | |
| struct | RawMidiParserState |
| struct | ChannelRouteSpec |
| class | ChannelRouter |
| struct | NoteRangeSpec |
| class | NoteRangeFilter |
| struct | KeyboardSplitSpec |
| class | KeyboardSplit |
| class | RpnParser |
| Parses RPN (Registered Parameter Number) and NRPN (Non-Registered Parameter Number) messages from a stream of MIDI CC events. More... | |
| class | RunningStatusParser |
| struct | StepPlayerStep |
| The authored data at one lane and step coordinate. More... | |
| struct | StepPlayerLaneSpec |
| struct | StepPlayerBlock |
| Block timing for one sample-accurate step-player call. More... | |
| struct | StepPlayerCapacityContract |
| struct | StepPlayerCoordinate |
| A lane's authored coordinate at one grid tick. More... | |
| class | StepPlayer |
| Fixed-capacity, sample-accurate multi-lane linear step player. More... | |
| struct | StrumSpec |
| Spread a near-simultaneous cluster of notes across time. More... | |
| class | Strum |
| struct | SynthesiserNote |
| Per-note metadata maintained by the Synthesiser when a voice is activated. More... | |
| struct | SynthesiserTelemetry |
| struct | SynthesiserRuntimeBudgetReport |
| class | SynthesiserVoice |
| Abstract base for one synth voice. More... | |
| struct | SynthesiserNoteOnPolicy |
| Constant note-on metadata for MIDI-buffer dispatch. More... | |
| class | Synthesiser |
| Polyphonic synth that routes plain-MIDI events into a pool of Voice instances. More... | |
| class | SysexAccumulator |
| class | SysexChunkAssembler |
| struct | TuningQueryResult |
| struct | TuningNoteResult |
| struct | TuningStatus |
| class | TuningProvider |
| class | EqualTemperamentTuningProvider |
| struct | UmpPacket |
| struct | MpeZone |
| struct | MpeConfig |
| struct | UmpEvent |
| One UMP packet with a block-relative sample offset. More... | |
| class | UmpBuffer |
| A time-ordered list of UMP events for one audio block. More... | |
| struct | Midi2ProgramChange |
| Decoded fields of a MIDI 2.0 Channel Voice Program Change (status 0xC). More... | |
| struct | UmpEndpointDirection |
| Direction the endpoint exposes. More... | |
| struct | UmpEndpointInfo |
| Static description of an endpoint discovered on the system or registered virtually. More... | |
| class | UmpEndpoint |
| Polymorphic endpoint handle. More... | |
| struct | UmpSessionConfig |
| Options for creating a session. More... | |
| class | UmpSession |
| class | UmpSysex7Reassembler |
| Reassembler state machine for UMP Type-0x3 sysex7 packet streams. More... | |
| struct | VirtualUmpEndpointConfig |
| Configuration for a newly-registered virtual endpoint. More... | |
| class | VirtualUmpEndpoint |
| struct | MidiUtilityContract |
| struct | MidiUtilityProcessReport |
Typedefs | |
| using | BleMidiScanCallback = std::function<void(const BleMidiPeripheral&)> |
| Callback fired each time the scanner observes a peripheral that advertises the BLE-MIDI service UUID. | |
| using | BleMidiStateCallback |
| Callback for connection-state changes against a specific peripheral id. | |
| using | ControllerCurve = float (*)(float normalized, float amount) noexcept |
| using | MidiInputCallback = std::function<void(const MidiEvent& event)> |
| using | MidiSysexCallback |
| using | PeNotifyCallback |
| Notify callback — fires when a Subscribe peer should be notified of a resource change. | |
| using | MpeNoteGeneration = std::uint64_t |
| Stable identity assigned to one accepted MPE note-on generation. | |
| using | MonophonicNoteSelector = BasicMonophonicNoteSelector<> |
| using | RawMidiShortCallback |
| using | RawMidiSysexCallback |
| using | ShortMessageSink = std::function<void(const MidiEvent&)> |
| Callback invoked for each complete short message. | |
| using | SysexSink = std::function<void(const uint8_t* data, std::size_t size)> |
| using | SysexEmitFn |
| Callback shape: receives the complete sysex payload (including the leading 0xF0 and trailing 0xF7) plus a flag indicating whether the message was properly terminated (true) or aborted by a new status byte (false). | |
| using | UmpReceiveCallback |
| Receive callback. | |
| using | Sysex7EmitFn |
| Callback shape: receives the complete UMP SysEx7 payload bytes, with no synthesised MIDI 1.0 F0/F7 framing. | |
Functions | |
| std::unique_ptr< BleMidiCentral > | create_ble_midi_central () |
| Create the BLE MIDI central for the current platform. | |
| std::vector< uint8_t > | encode_ble_midi_packet (const uint8_t *msg, std::size_t size, uint32_t timestamp_ms) |
| Encode a single MIDI message into a BLE-MIDI packet using timestamp timestamp_ms (truncated to 13 bits per the spec). | |
| void | clear_midi_block (MidiBuffer &block) noexcept |
| bool | midi_block_has_drops (const MidiBuffer &block) noexcept |
| bool | copy_midi_sidecars (const MidiBuffer &src, MidiBuffer &dst) noexcept |
| bool | copy_midi_block (const MidiBuffer &src, MidiBuffer &dst) noexcept |
| bool | copy_mpe_block (const MpeBuffer &src, MpeBuffer &dst) noexcept |
| bool | mpe_buffer_has_drops (const MpeBuffer &block) noexcept |
| float | linear_controller_curve (float normalized, float) noexcept |
| std::unique_ptr< MidiSystem > | create_midi_system () |
| std::vector< uint8_t > | mcoded7_encode (const uint8_t *data, std::size_t size) |
| Encode raw 8-bit bytes into Mcoded7. | |
| std::vector< uint8_t > | mcoded7_encode (const std::vector< uint8_t > &data) |
| std::vector< uint8_t > | mcoded7_decode (const uint8_t *data, std::size_t size) |
| Decode an Mcoded7-encoded stream back to raw 8-bit bytes. | |
| std::vector< uint8_t > | mcoded7_decode (const std::vector< uint8_t > &data) |
| std::vector< uint8_t > | pe_build_message (PeMessageType pe_type, uint8_t ci_version, MUID source, MUID destination, uint8_t request_id, std::string_view header_json, uint16_t total_chunks, uint16_t chunk_number, const uint8_t *payload, std::size_t payload_size) |
| Builder for PE message wire bytes. | |
| std::vector< uint8_t > | pe_build_message (PeMessageType pe_type, uint8_t ci_version, MUID source, MUID destination, uint8_t request_id, std::string_view header_json, uint16_t total_chunks, uint16_t chunk_number, const std::vector< uint8_t > &payload) |
| std::optional< PeChunk > | pe_parse_message (const uint8_t *data, std::size_t size) |
| Parse a single PE SysEx envelope into a PeChunk. | |
| std::vector< std::vector< uint8_t > > | pe_split_into_chunks (PeMessageType pe_type, uint8_t ci_version, MUID source, MUID destination, uint8_t request_id, std::string_view header_json, const uint8_t *payload, std::size_t payload_size, std::size_t max_payload_bytes) |
| Split a logical PE Get/Set into wire-ready chunks bounded by max_payload_bytes of decoded resource per chunk. | |
| std::optional< std::vector< uint8_t > > | pe_compress (const uint8_t *data, std::size_t size) |
| Compress a PE payload using zlib (RFC 1950). Returns nullopt on failure. | |
| std::optional< std::vector< uint8_t > > | pe_compress (const std::vector< uint8_t > &payload) |
| std::optional< std::vector< uint8_t > > | pe_decompress (const uint8_t *data, std::size_t size) |
| Decompress a zlib-wrapped PE payload. Returns nullopt on failure. | |
| std::optional< std::vector< uint8_t > > | pe_decompress (const std::vector< uint8_t > &blob) |
| std::string | pe_header_make (std::string_view resource, std::string_view command={}, int status=200) |
| Builds a minimal PE JSON header. | |
| bool | pe_header_parse (std::string_view json, std::string *resource, std::string *command, int *status) |
| Parse a PE JSON header. | |
| std::optional< MidiFileData > | read_midi_file (const std::string &path) |
| bool | write_midi_file (const std::string &path, const MidiFileData &data) |
| void | bind_tracker_to_buffer (MpeVoiceTracker &tracker, MpeBuffer &out, int32_t ¤t_sample_offset, bool *expression_event_dropped=nullptr) |
| Convenience: install tracker callbacks that forward events to out with the given sample offset. | |
| MpeMessageList< 3 > | mpe_configuration_message (uint8_t manager_channel, uint8_t member_count) |
| MPE Configuration Message: RPN 6 on a manager channel. | |
| MpeMessageList< 4 > | mpe_pitch_bend_range_message (uint8_t channel, float semitones) |
| Pitch-bend range (RPN 0) for one channel: whole semitones in Data Entry MSB and the remaining hundredths in Data Entry LSB. | |
| MpeMessageList< 6 > | mpe_zone_layout_messages (const MpeConfig &config) |
| Zone layout: one Configuration Message for each zone, lower first. | |
| MpeMessageList< 64 > | mpe_zone_pitch_bend_range_messages (const MpeZone &zone, float manager_semitones, float member_semitones) |
| Pitch-bend ranges for a whole zone: the manager channel gets manager_semitones and every member channel gets member_semitones. | |
| template<std::size_t N> | |
| void | send_mpe_messages (MidiOutput &output, const MpeMessageList< N > &list) |
| Send every event in list to output, in order. | |
| constexpr std::size_t | panic_message_count (const PanicScope &scope) |
| Number of events panic_messages() will write for scope. | |
| 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. | |
| template<typename Fn> | |
| 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, in channel then note order. | |
| std::size_t | 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 | 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 > | classify_panic_message (const MidiEvent &event) noexcept |
| Classify a message as one of the panic kinds, or nullopt for anything else. | |
| PortListDiff | diff_port_lists (const std::vector< MidiPortInfo > &before, const std::vector< MidiPortInfo > &after) |
| Compare two snapshots. | |
| void | parse_raw_midi_bytes (const uint8_t *buf, std::size_t n, RawMidiParserState &state, const RawMidiShortCallback &on_short, const RawMidiSysexCallback &on_sysex) |
| bool | is_valid_midi_note (int midi_note) noexcept |
| bool | is_valid_midi_channel (int midi_channel) noexcept |
| int | normalise_midi_channel (int midi_channel) noexcept |
| double | equal_temperament_frequency (int midi_note, double a4_hz=440.0) noexcept |
| int | equal_temperament_note_for_frequency (double frequency_hz, double a4_hz=440.0) noexcept |
| int | ump_words_for_message_type (uint8_t message_type) |
| Spec-complete UMP packet length, in 32-bit words, for a raw message-type nibble (bits 28-31 of word 0, values 0x0-0xF). | |
| template<typename Visitor> | |
| void | walk_ump_packet (const uint32_t *words, uint32_t word_count, Visitor &&visit) |
| Walk one UMP packet's contiguous word array, visiting each complete message in order. | |
| UtilityStatus | utility_status (const UmpPacket &p) |
| Extract the utility status nibble from a type-0 UMP packet (bits 20-23 of word 0). | |
| uint16_t | jr_value_16 (const UmpPacket &p) |
| Extract the 16-bit JR Clock / JR Timestamp value from a type-0 UMP packet (bits 0-15 of word 0). | |
| double | jr_value_seconds (uint16_t value) |
| double | jr_value_microseconds (uint16_t value) |
| UmpPacket | make_jr_clock (uint8_t group, uint16_t value) |
| Build a JR Clock utility packet (status 0x1). | |
| UmpPacket | make_jr_timestamp (uint8_t group, uint16_t value) |
| Build a JR Timestamp utility packet (status 0x2). | |
| uint16_t | scale_7_to_16 (uint8_t v7) |
| Scale a 7-bit value (0..127) to 16-bit (0..65535) per MIDI 2.0 spec. | |
| uint8_t | scale_16_to_7 (uint16_t v16) |
| Scale 16-bit (0..65535) down to 7-bit (0..127). | |
| uint32_t | scale_14_to_32 (uint16_t v14) |
| Scale a 14-bit value (0..16383, center 8192) to 32-bit (center 0x80000000) using MIDI 2.0 Min/Center/Max scaling so the midpoint is preserved exactly. | |
| uint16_t | scale_32_to_14 (uint32_t v32) |
| Scale a 32-bit value back to 14-bit (0..16383), inverse of scale_14_to_32. | |
| UmpPacket | midi1_event_to_ump2 (const MidiEvent &ev, uint8_t group=0) |
| Convert a single MIDI 1.0 event to a MIDI 2.0 Channel Voice UMP packet. | |
| void | midi1_to_ump (const MidiBuffer &src, UmpBuffer &dst, uint8_t group=0) |
| Append a MIDI 1.0 buffer to a UmpBuffer as MIDI 2.0 UMP packets. | |
| Midi2ProgramChange | ump_program_change_fields (const UmpPacket &p) |
| Decode a MIDI 2.0 Program Change packet's fields without converting it. | |
| bool | ump_to_midi1_event (const UmpPacket &p, MidiEvent &out) |
| Convert a UMP Channel Voice packet into a MIDI 1.0 event when possible. | |
| bool | ump_is_bank_valid_program_change (const UmpPacket &p) |
True when p is a MIDI 2.0 Program Change carrying a valid bank, i.e. | |
| void | ump_to_midi1 (const UmpBuffer &src, MidiBuffer &dst) |
| Flatten a UmpBuffer into a MidiBuffer. | |
| UmpSysex7Reassembler::Status | feed_collect (UmpSysex7Reassembler &r, std::uint32_t word0, std::uint32_t word1, std::vector< std::uint8_t > &out) |
| Convenience: feed a packet and collect the emitted payload (if any) into out. | |
Variables | |
| constexpr bool | kHasMtsEspTuning = static_cast<bool>( 0 ) |
| template<typename Serial> | |
| constexpr bool | monophonic_serial_capacity_supported |
| constexpr std::size_t | kMaxPanicMessages = 16u * 5u |
| Largest number of events panic_messages() can produce (16 channels x 5). | |
| constexpr std::size_t | kMaxNoteOffs = 16u * 128u |
| Largest number of events held_note_offs() / all_note_offs() can produce. | |
| constexpr std::size_t | kRawMidiSysexLimit = 64 * 1024 |
| constexpr bool | kHasScalaTuning = static_cast<bool>( 0 ) |
| constexpr int | kUnknownMidiChannel = -1 |
| constexpr double | kJrTicksPerSecond = 31250.0 |
| One JR Clock tick is 1/31250 of a second (~32 microseconds). | |
| constexpr uint8_t | kBankSelectMsbCc = 0 |
| MIDI 1.0 controller numbers carrying Bank Select for a program change. | |
| constexpr uint8_t | kBankSelectLsbCc = 32 |
| using pulp::midi::BleMidiScanCallback = std::function<void(const BleMidiPeripheral&)> |
Callback fired each time the scanner observes a peripheral that advertises the BLE-MIDI service UUID.
May be invoked from a backend thread; consumers post to the UI thread themselves.
Callback for connection-state changes against a specific peripheral id.
Drives the pairing UI (Connecting → Connected | Failed).
| using pulp::midi::ControllerCurve = float (*)(float normalized, float amount) noexcept |
| using pulp::midi::MidiInputCallback = std::function<void(const MidiEvent& event)> |
| using pulp::midi::MpeNoteGeneration = std::uint64_t |
Stable identity assigned to one accepted MPE note-on generation.
Zero is permanently reserved as "no generation".
Notify callback — fires when a Subscribe peer should be notified of a resource change.
subscriber_muid is the bound peer; header_json and payload echo the Notify PE message body. The transport layer (the caller of CiDiscovery) is responsible for actually building + sending the Notify wire bytes — this callback just tells you who.
| using pulp::midi::ShortMessageSink = std::function<void(const MidiEvent&)> |
Callback invoked for each complete short message.
SysEx payloads are delivered via a separate callback so callers can grow their own buffer.
| using pulp::midi::Sysex7EmitFn |
Callback shape: receives the complete UMP SysEx7 payload bytes, with no synthesised MIDI 1.0 F0/F7 framing.
UMP framing is implicit in the start/continue/end status nibble; callers crossing into MIDI 1.0 must add F0/F7 explicitly at that boundary.
The reassembler invokes this callback exactly once per logical sysex (either a single complete packet, or a start → continue* → end span), including a zero-byte payload. Orphaned continue/end packets (i.e. arrival without a preceding start) are dropped silently — corrupting the downstream sink with a partial payload is worse than dropping one malformed sysex.
| using pulp::midi::SysexEmitFn |
Callback shape: receives the complete sysex payload (including the leading 0xF0 and trailing 0xF7) plus a flag indicating whether the message was properly terminated (true) or aborted by a new status byte (false).
Callers typically ignore aborted messages or log them at debug level.
| using pulp::midi::SysexSink = std::function<void(const uint8_t* data, std::size_t size)> |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
Connection state for an attempted BLE pairing.
Reported on the callback registered with BleMidiCentral::set_state_callback().
| Enumerator | |
|---|---|
| Idle | |
| Scanning | |
| Connecting | |
| Connected | |
| Disconnected | |
| Failed | |
|
strong |
Backend-reported error code.
Backends translate platform errors (CBError, BlueZ D-Bus errors, WinRT HRESULT, etc.) into this neutral enum so cross-platform tests can assert without including per-OS headers.
|
strong |
How a captured chord is addressed when a single note triggers it.
|
strong |
MIDI-CI message types (sub-IDs).
Note: Pulp uses 0x24 / 0x25 / 0x26 / 0x27 for the Profile Inquiry family (existing contract; preserved for wire compatibility). The CI 1.2 Profile Details / Profile Specific Data / Set Profile On|Off values follow that block at 0x28 / 0x29 / 0x2F / 0x22 / 0x23. New values are appended only — old code paths keep their numeric IDs.
|
strong |
How a latch retains the notes a player releases.
Off is exact passthrough and owns no note. Hold retains every note of a phrase until the player lifts every key and starts the next phrase, which is the behaviour an arpeggiator hold pedal provides. Toggle makes each press flip one key's retention, so a second press on a latched key releases it.
| Enumerator | |
|---|---|
| Off | |
| Hold | |
| Toggle | |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
PE sub-IDs (MIDI-CI sub-ID #2 byte). Mirrors CiMessageType for PE.
| Enumerator | |
|---|---|
| GetInquiry | |
| GetReply | |
| SetInquiry | |
| SetReply | |
| SubscribeInquiry | |
| SubscribeReply | |
| Notify | |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
|
strong |
Utility message status codes (bits 20-23 of word 0 for type 0x0).
JR Clock / JR Timestamp carry a 16-bit value in bits 0-15 of word 0 measured in 1/31250-second units (~32 µs resolution). They let hosts schedule UMP events with sub-block timing accuracy. JR Clock is the "current time" reference; JR Timestamp is "this packet's event happens at this offset". See the MIDI 2.0 UMP spec § Utility.
| Enumerator | |
|---|---|
| Noop | |
| JrClock | |
| JrTimestamp | |
| DeltaClockstampTicksPerQuarter | |
| DeltaClockstamp | |
|
strong |
Voice-stealing strategy applied when note_on fires and no free voice is available.
|
inlinenoexcept |
Brute-force fallback: a note-off for every key on the channels in channel_mask, whether or not it was tracked as held.
For hosts and formats that bypass the tracker. Up to kMaxNoteOffs events.
|
inline |
Convenience: install tracker callbacks that forward events to out with the given sample offset.
When provided, expression_event_dropped is set if a bounded expression append fails so the owner can reconcile tracker and consumer state. Call once on the host thread during setup.
|
inlinenoexcept |
Classify a message as one of the panic kinds, or nullopt for anything else.
The value byte must be the one panic_messages() sends (0 for the CCs, centre for pitch bend): CC 123 with a nonzero value is not an All Notes Off.
|
inlinenoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
| std::unique_ptr< BleMidiCentral > pulp::midi::create_ble_midi_central | ( | ) |
Create the BLE MIDI central for the current platform.
Returns a scaffold central on platforms without a real backend; is_available() returns false on those builds so callers can degrade gracefully.
| std::unique_ptr< MidiSystem > pulp::midi::create_midi_system | ( | ) |
|
inline |
Compare two snapshots.
A port is identified by id, name and direction together. Backends that number ports by position (so removing one shifts the ids of the rest) therefore report the shifted ports as removed and added, which is the truth for anyone holding the old ids. Duplicate entries are matched one for one.
| std::vector< uint8_t > pulp::midi::encode_ble_midi_packet | ( | const uint8_t * | msg, |
| std::size_t | size, | ||
| uint32_t | timestamp_ms ) |
Encode a single MIDI message into a BLE-MIDI packet using timestamp timestamp_ms (truncated to 13 bits per the spec).
Returns the encoded bytes; appends header + timestamp + message. Sysex callers should chunk to MTU - 1 bytes per call.
|
noexcept |
|
noexcept |
|
inline |
Convenience: feed a packet and collect the emitted payload (if any) into out.
Returns the same Status as feed_packet. Useful for hosts that want a value-returning API rather than a callback. Not RT-safe (the lambda capture allocates) — for hot-path use, prefer the function-pointer feed_packet overload.
|
inlinenoexcept |
Call fn(channel, note) for every key keys reports as held on the channels in channel_mask, in channel then note order.
The allocation-free way to walk the held set when a caller writes straight into its own buffer instead of an intermediate span.
|
inlinenoexcept |
Note-off events for exactly the notes keys reports as held, on the channels in channel_mask, in channel then note order.
This is the precise form: nothing is sent for a key that is not down. Returns the count written (truncated at a whole event if out is too small).
|
noexcept |
|
noexcept |
|
inline |
Extract the 16-bit JR Clock / JR Timestamp value from a type-0 UMP packet (bits 0-15 of word 0).
Caller must check utility_status() first to know which kind of value this is. Returns 0 for non-JR utility messages.
|
inline |
|
inline |
|
inlinenoexcept |
|
inline |
Build a JR Clock utility packet (status 0x1).
|
inline |
Build a JR Timestamp utility packet (status 0x2).
|
inline |
| std::vector< uint8_t > pulp::midi::mcoded7_decode | ( | const uint8_t * | data, |
| std::size_t | size ) |
Decode an Mcoded7-encoded stream back to raw 8-bit bytes.
Returns an empty vector if the input is malformed (contains a byte with bit 7 set anywhere it must not, or a final group's high-bit byte references more low bytes than were actually transmitted).
|
inline |
| std::vector< uint8_t > pulp::midi::mcoded7_encode | ( | const uint8_t * | data, |
| std::size_t | size ) |
Encode raw 8-bit bytes into Mcoded7.
Output is ceil(input/7) * 8 - extra where extra trims trailing slots when the final group is short. The encoded stream contains only values <= 0x7F and is safe to embed in MIDI SysEx.
Convert a single MIDI 1.0 event to a MIDI 2.0 Channel Voice UMP packet.
Uses message type 0x4 so the host sees full MIDI 2.0 resolution. Group defaults to 0.
|
inline |
Append a MIDI 1.0 buffer to a UmpBuffer as MIDI 2.0 UMP packets.
|
inlinenoexcept |
|
inlinenoexcept |
|
inline |
MPE Configuration Message: RPN 6 on a manager channel.
manager_channel is 0 for the lower zone or 15 for the upper zone; member_count is 0-15 and 0 disables the zone.
|
inline |
Pitch-bend range (RPN 0) for one channel: whole semitones in Data Entry MSB and the remaining hundredths in Data Entry LSB.
Ranges above 127 semitones are clamped and negative ranges become zero.
|
inline |
Zone layout: one Configuration Message for each zone, lower first.
A zone with no members is sent with a count of zero so a device that had it enabled turns it off.
|
inline |
Pitch-bend ranges for a whole zone: the manager channel gets manager_semitones and every member channel gets member_semitones.
Send after the zone layout, because a Configuration Message resets ranges.
|
noexcept |
|
inlineconstexpr |
Number of events panic_messages() will write for scope.
|
inlinenoexcept |
Write the panic messages for scope into out, channel by channel.
Within a channel the order is: sustain off, All Notes Off, All Sound Off, Reset All Controllers, pitch bend centre. Sustain goes first so a pedal-held note is released before the notes message arrives; the controller reset and bend centre come last so they are not undone by anything earlier.
Every event carries sample_offset. Returns the number of events written, which is panic_message_count(scope) when out is large enough; if out is too small the output is cut at a whole-event boundary and the return value is the count actually written (compare with panic_message_count() to detect truncation).
|
inline |
|
inline |
| std::vector< uint8_t > pulp::midi::pe_build_message | ( | PeMessageType | pe_type, |
| uint8_t | ci_version, | ||
| MUID | source, | ||
| MUID | destination, | ||
| uint8_t | request_id, | ||
| std::string_view | header_json, | ||
| uint16_t | total_chunks, | ||
| uint16_t | chunk_number, | ||
| const uint8_t * | payload, | ||
| std::size_t | payload_size ) |
Builder for PE message wire bytes.
pe_type is one of the PE CiMessageType sub-IDs. header_json is plain UTF-8 JSON — the caller owns its schema (resource/, command/, status/, etc.).
Returns a complete SysEx envelope: F0 7E 7F 0D <sub-id> version src(4) dst(4) request_id hdr_len(2) hdr(Mcoded7) total(2) chunk_num(2) pay_len(2) pay(Mcoded7) F7.
NOT RT-safe — allocates the returned vector and the intermediate Mcoded7 encode buffers. SysEx is a main-thread protocol.
|
inline |
| std::optional< std::vector< uint8_t > > pulp::midi::pe_compress | ( | const uint8_t * | data, |
| std::size_t | size ) |
Compress a PE payload using zlib (RFC 1950). Returns nullopt on failure.
|
inline |
| std::optional< std::vector< uint8_t > > pulp::midi::pe_decompress | ( | const uint8_t * | data, |
| std::size_t | size ) |
Decompress a zlib-wrapped PE payload. Returns nullopt on failure.
| std::string pulp::midi::pe_header_make | ( | std::string_view | resource, |
| std::string_view | command = {}, | ||
| int | status = 200 ) |
Builds a minimal PE JSON header.
Plenty of producers will want to build their own, but this covers the common "resource + status" case and keeps tests from depending on a JSON library at the surface.
command is one of "start" / "end" / "partial" / "full" / "notify". Empty command is omitted.
NOT RT-safe — returns a heap-backed std::string built via std::ostringstream.
| bool pulp::midi::pe_header_parse | ( | std::string_view | json, |
| std::string * | resource, | ||
| std::string * | command, | ||
| int * | status ) |
Parse a PE JSON header.
Returns true on success and fills the out params; returns false if the header is not valid JSON. Only the fields used by the PE framing are extracted; everything else is considered application data and ignored here.
NOT RT-safe — populates out-param std::strings (allocations).
| std::optional< PeChunk > pulp::midi::pe_parse_message | ( | const uint8_t * | data, |
| std::size_t | size ) |
Parse a single PE SysEx envelope into a PeChunk.
Returns nullopt if the buffer is not a well-formed PE message or fails Mcoded7 decode. Caller is responsible for matching request_id and reassembling chunks.
NOT RT-safe — allocates the PeChunk's header_json and payload vectors, plus a transient Mcoded7 decode buffer.
| std::vector< std::vector< uint8_t > > pulp::midi::pe_split_into_chunks | ( | PeMessageType | pe_type, |
| uint8_t | ci_version, | ||
| MUID | source, | ||
| MUID | destination, | ||
| uint8_t | request_id, | ||
| std::string_view | header_json, | ||
| const uint8_t * | payload, | ||
| std::size_t | payload_size, | ||
| std::size_t | max_payload_bytes ) |
Split a logical PE Get/Set into wire-ready chunks bounded by max_payload_bytes of decoded resource per chunk.
The header is repeated verbatim in each chunk per the spec.
NOT RT-safe — allocates the outer vector and N inner SysEx buffers.
| std::optional< MidiFileData > pulp::midi::read_midi_file | ( | const std::string & | path | ) |
|
inline |
Scale a 14-bit value (0..16383, center 8192) to 32-bit (center 0x80000000) using MIDI 2.0 Min/Center/Max scaling so the midpoint is preserved exactly.
|
inline |
Scale 16-bit (0..65535) down to 7-bit (0..127).
|
inline |
Scale a 32-bit value back to 14-bit (0..16383), inverse of scale_14_to_32.
|
inline |
Scale a 7-bit value (0..127) to 16-bit (0..65535) per MIDI 2.0 spec.
Zero stays zero; 127 maps to 0xFFFF (no dead zone at the top).
| void pulp::midi::send_mpe_messages | ( | MidiOutput & | output, |
| const MpeMessageList< N > & | list ) |
Send every event in list to output, in order.
|
inline |
True when p is a MIDI 2.0 Program Change carrying a valid bank, i.e.
one whose faithful MIDI 1.0 rendering needs more than a single event.
|
inline |
Decode a MIDI 2.0 Program Change packet's fields without converting it.
Pure: depends only on p. Callers that need the complete MIDI 1.0 rendering of a bank-valid program change (CC 0, CC 32, then the program change) can build it from this, which ump_to_midi1_event alone cannot express through its single-event out-parameter.
|
inline |
Flatten a UmpBuffer into a MidiBuffer.
Packets that have no MIDI 1.0 equivalent are skipped; if you care about them, use the MPE sidecar.
One packet is not always one event: a MIDI 2.0 program change whose Bank Valid option flag is set expands to the three MIDI 1.0 messages that carry the same meaning — CC 0 (bank MSB), CC 32 (bank LSB), then the program change — all at the source packet's sample offset and in that order, because a MIDI 1.0 receiver latches the bank bytes and applies them on the following program change.
Convert a UMP Channel Voice packet into a MIDI 1.0 event when possible.
Returns true on success and writes to out. Returns false for packets that have no MIDI 1.0 equivalent (e.g. per-note pitch bend, per-note CC), which callers typically route via the MPE sidecar instead.
Emits at most one event. The one message whose faithful MIDI 1.0 rendering needs more than that is a bank-valid MIDI 2.0 program change (CC 0, CC 32, program change); here it converts to the program change alone. Use ump_program_change_fields to read the bank, or ump_to_midi1, which emits the complete sequence.
|
inline |
Spec-complete UMP packet length, in 32-bit words, for a raw message-type nibble (bits 28-31 of word 0, values 0x0-0xF).
Covers every message type the MIDI 2.0 UMP spec defines — including the reserved ranges and the 128-bit UMP-Stream type (0xF) — so a cursor walking a packet stream advances past an unrecognized message by its true length instead of re-reading its trailing words as a fresh header:
0x0,0x1,0x2,0x6,0x7 -> 1 word (32-bit) 0x3,0x4,0x8,0x9,0xA -> 2 words (64-bit) 0xB,0xC -> 3 words (96-bit) 0x5,0xD,0xE,0xF -> 4 words (128-bit)
|
inline |
Extract the utility status nibble from a type-0 UMP packet (bits 20-23 of word 0).
|
inline |
Walk one UMP packet's contiguous word array, visiting each complete message in order.
visit(mt, msg_words, msg_word_count) fires once per message, where mt is the message-type nibble, msg_words points at the message's first word, and msg_word_count is its spec length. The cursor advances by that spec length (see ump_words_for_message_type), so a multi-word message's trailing words are never re-read as a fresh header. A message whose declared length runs past word_count (a truncated packet) stops the walk without visiting that message, so the visitor may safely read all msg_word_count words. Pure and allocation-free — safe on the audio thread.
| bool pulp::midi::write_midi_file | ( | const std::string & | path, |
| const MidiFileData & | data ) |
|
inlineconstexpr |
|
inlineconstexpr |
MIDI 1.0 controller numbers carrying Bank Select for a program change.
|
inlineconstexpr |
|
inlineconstexpr |
|
constexpr |
One JR Clock tick is 1/31250 of a second (~32 microseconds).
Convenience accessors convert a 16-bit JR value to a time delta.
|
inlineconstexpr |
Largest number of events held_note_offs() / all_note_offs() can produce.
|
inlineconstexpr |
Largest number of events panic_messages() can produce (16 channels x 5).
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |