Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
midi_message_sequence.hpp
Go to the documentation of this file.
1#pragma once
2
3// MidiMessageSequence — ordered, timestamped MIDI event list.
4// Complement to MidiBuffer: MidiBuffer is for real-time process callbacks,
5// MidiMessageSequence is for editing, file I/O, and offline processing.
6
7#include <vector>
8#include <string>
9#include <cstdint>
10#include <algorithm>
11#include <optional>
12
13namespace pulp::midi {
14
17 double timestamp = 0; // Seconds (or samples, depending on context)
18 uint8_t status = 0;
19 uint8_t data1 = 0;
20 uint8_t data2 = 0;
21 std::vector<uint8_t> sysex; // For SysEx messages
22
23 bool is_note_on() const { return (status & 0xF0) == 0x90 && data2 > 0; }
24 bool is_note_off() const { return (status & 0xF0) == 0x80 || ((status & 0xF0) == 0x90 && data2 == 0); }
25 bool is_cc() const { return (status & 0xF0) == 0xB0; }
26 bool is_sysex() const { return status == 0xF0; }
27 int channel() const { return status & 0x0F; }
28 int note() const { return data1; }
29 int velocity() const { return data2; }
30};
31
34public:
36
38 void add_event(const TimestampedMidiEvent& event) {
39 auto it = std::upper_bound(events_.begin(), events_.end(), event,
40 [](const TimestampedMidiEvent& a, const TimestampedMidiEvent& b) {
41 return a.timestamp < b.timestamp;
42 });
43 events_.insert(it, event);
44 }
45
47 void add_note_on(double timestamp, int channel, int note, int velocity) {
49 e.timestamp = timestamp;
50 e.status = static_cast<uint8_t>(0x90 | (channel & 0x0F));
51 e.data1 = static_cast<uint8_t>(note & 0x7F);
52 e.data2 = static_cast<uint8_t>(velocity & 0x7F);
53 add_event(e);
54 }
55
57 void add_note_off(double timestamp, int channel, int note) {
59 e.timestamp = timestamp;
60 e.status = static_cast<uint8_t>(0x80 | (channel & 0x0F));
61 e.data1 = static_cast<uint8_t>(note & 0x7F);
62 e.data2 = 0;
63 add_event(e);
64 }
65
67 void add_cc(double timestamp, int channel, int cc, int value) {
69 e.timestamp = timestamp;
70 e.status = static_cast<uint8_t>(0xB0 | (channel & 0x0F));
71 e.data1 = static_cast<uint8_t>(cc & 0x7F);
72 e.data2 = static_cast<uint8_t>(value & 0x7F);
73 add_event(e);
74 }
75
77 int size() const { return static_cast<int>(events_.size()); }
78
80 const TimestampedMidiEvent& operator[](int i) const { return events_[static_cast<size_t>(i)]; }
81
83 void clear() { events_.clear(); }
84
86 double duration() const { return events_.empty() ? 0 : events_.back().timestamp; }
87
89 std::vector<const TimestampedMidiEvent*> events_in_range(double start, double end) const {
90 std::vector<const TimestampedMidiEvent*> result;
91 for (auto& e : events_)
92 if (e.timestamp >= start && e.timestamp < end)
93 result.push_back(&e);
94 return result;
95 }
96
98 std::optional<int> find_note_off(int note_on_index) const {
99 if (note_on_index < 0 || note_on_index >= size()) return std::nullopt;
100 auto& on = events_[static_cast<size_t>(note_on_index)];
101 if (!on.is_note_on()) return std::nullopt;
102
103 for (int i = note_on_index + 1; i < size(); ++i) {
104 auto& e = events_[static_cast<size_t>(i)];
105 if (e.is_note_off() && e.note() == on.note() && e.channel() == on.channel())
106 return i;
107 }
108 return std::nullopt;
109 }
110
112 void offset_timestamps(double offset) {
113 for (auto& e : events_)
114 e.timestamp += offset;
115 }
116
118 const std::vector<TimestampedMidiEvent>& events() const { return events_; }
119
121 auto begin() const { return events_.begin(); }
122 auto end() const { return events_.end(); }
123
124private:
125 std::vector<TimestampedMidiEvent> events_;
126};
127
128} // namespace pulp::midi
std::vector< const TimestampedMidiEvent * > events_in_range(double start, double end) const
Find events in a time range [start, end).
Definition midi_message_sequence.hpp:89
void add_cc(double timestamp, int channel, int cc, int value)
Add a CC event.
Definition midi_message_sequence.hpp:67
void add_event(const TimestampedMidiEvent &event)
Add an event (maintains sorted order by timestamp).
Definition midi_message_sequence.hpp:38
void offset_timestamps(double offset)
Shift all timestamps by an offset.
Definition midi_message_sequence.hpp:112
std::optional< int > find_note_off(int note_on_index) const
Find matching note-off for a note-on event.
Definition midi_message_sequence.hpp:98
auto begin() const
Iterator support.
Definition midi_message_sequence.hpp:121
double duration() const
Duration (timestamp of last event).
Definition midi_message_sequence.hpp:86
void add_note_off(double timestamp, int channel, int note)
Add a note-off event.
Definition midi_message_sequence.hpp:57
int size() const
Number of events.
Definition midi_message_sequence.hpp:77
void clear()
Clear all events.
Definition midi_message_sequence.hpp:83
const std::vector< TimestampedMidiEvent > & events() const
Get all events (const).
Definition midi_message_sequence.hpp:118
auto end() const
Definition midi_message_sequence.hpp:122
void add_note_on(double timestamp, int channel, int note, int velocity)
Add a note-on event.
Definition midi_message_sequence.hpp:47
const TimestampedMidiEvent & operator[](int i) const
Access event by index.
Definition midi_message_sequence.hpp:80
Definition custom_node_events.hpp:26
A MIDI event with timestamp (in seconds or samples).
Definition midi_message_sequence.hpp:16
int velocity() const
Definition midi_message_sequence.hpp:29
uint8_t data1
Definition midi_message_sequence.hpp:19
uint8_t status
Definition midi_message_sequence.hpp:18
uint8_t data2
Definition midi_message_sequence.hpp:20
int channel() const
Definition midi_message_sequence.hpp:27
bool is_note_on() const
Definition midi_message_sequence.hpp:23
bool is_note_off() const
Definition midi_message_sequence.hpp:24
bool is_sysex() const
Definition midi_message_sequence.hpp:26
std::vector< uint8_t > sysex
Definition midi_message_sequence.hpp:21
int note() const
Definition midi_message_sequence.hpp:28
double timestamp
Definition midi_message_sequence.hpp:17
bool is_cc() const
Definition midi_message_sequence.hpp:25