-
Notifications
You must be signed in to change notification settings - Fork 445
/
Copy pathmidi.hpp
300 lines (244 loc) · 6.95 KB
/
midi.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
#pragma once
#include <vector>
#include <set>
#include <jansson.h>
#include <common.hpp>
#include <context.hpp>
namespace rack {
/** Abstraction for all MIDI drivers in Rack */
namespace midi {
struct Message {
/** Initialized to 3 empty bytes. */
std::vector<uint8_t> bytes;
/** The Engine frame timestamp of the Message.
For output messages, the frame when the message was generated.
For input messages, the frame when it is intended to be processed.
-1 for undefined, to be sent or processed immediately.
*/
int64_t frame = -1;
Message() : bytes(3) {}
int getSize() const {
return bytes.size();
}
void setSize(int size) {
bytes.resize(size);
}
uint8_t getChannel() const {
if (bytes.size() < 1)
return 0;
return bytes[0] & 0xf;
}
void setChannel(uint8_t channel) {
if (bytes.size() < 1)
return;
bytes[0] = (bytes[0] & 0xf0) | (channel & 0xf);
}
uint8_t getStatus() const {
if (bytes.size() < 1)
return 0;
return bytes[0] >> 4;
}
void setStatus(uint8_t status) {
if (bytes.size() < 1)
return;
bytes[0] = (bytes[0] & 0xf) | (status << 4);
}
uint8_t getNote() const {
if (bytes.size() < 2)
return 0;
return bytes[1];
}
void setNote(uint8_t note) {
if (bytes.size() < 2)
return;
bytes[1] = note & 0x7f;
}
uint8_t getValue() const {
if (bytes.size() < 3)
return 0;
return bytes[2];
}
void setValue(uint8_t value) {
if (bytes.size() < 3)
return;
bytes[2] = value & 0x7f;
}
std::string toString() const;
int64_t getFrame() const {
return frame;
}
void setFrame(int64_t frame) {
this->frame = frame;
}
};
////////////////////
// Driver
////////////////////
struct InputDevice;
struct Input;
struct OutputDevice;
struct Output;
/** Wraps a MIDI driver API containing any number of MIDI devices.
*/
struct Driver {
virtual ~Driver() {}
/** Returns the name of the driver. E.g. "ALSA". */
virtual std::string getName() {
return "";
}
/** Returns a list of all input device IDs that can be subscribed to. */
virtual std::vector<int> getInputDeviceIds() {
return {};
}
/** Returns the default device to use when the driver is selected, or -1 for none. */
virtual int getDefaultInputDeviceId() {
return -1;
}
/** Returns the name of an input device without obtaining it. */
virtual std::string getInputDeviceName(int deviceId) {
return "";
}
/** Adds the given port as a reference holder of a device and returns the it.
Creates the Device if no ports are subscribed before calling.
*/
virtual InputDevice* subscribeInput(int deviceId, Input* input) {
return NULL;
}
/** Removes the give port as a reference holder of a device.
Deletes the Device if no ports are subscribed after calling.
*/
virtual void unsubscribeInput(int deviceId, Input* input) {}
// The following behave identically as the above methods except for outputs.
virtual std::vector<int> getOutputDeviceIds() {
return {};
}
virtual int getDefaultOutputDeviceId() {
return -1;
}
virtual std::string getOutputDeviceName(int deviceId) {
return "";
}
virtual OutputDevice* subscribeOutput(int deviceId, Output* output) {
return NULL;
}
virtual void unsubscribeOutput(int deviceId, Output* output) {}
};
////////////////////
// Device
////////////////////
/** A single MIDI device of a driver API.
Modules and the UI should not interact with this API directly. Use Port instead.
Methods throw `rack::Exception` if the driver API has an exception.
*/
struct Device {
virtual ~Device() {}
virtual std::string getName() {
return "";
}
};
struct InputDevice : Device {
std::set<Input*> subscribed;
/** Not public. Use Driver::subscribeInput(). */
void subscribe(Input* input);
/** Not public. Use Driver::unsubscribeInput(). */
void unsubscribe(Input* input);
/** Called when a MIDI message is received from the device. */
void onMessage(const Message& message);
};
struct OutputDevice : Device {
std::set<Output*> subscribed;
/** Not public. Use Driver::subscribeOutput(). */
void subscribe(Output* output);
/** Not public. Use Driver::unsubscribeOutput(). */
void unsubscribe(Output* output);
/** Sends a MIDI message to the device. */
virtual void sendMessage(const Message& message) {}
};
////////////////////
// Port
////////////////////
/** A handle to a Device, typically owned by modules to have shared access to a single Device.
All Port methods safely wrap Drivers methods.
That is, if the active Device throws a `rack::Exception`, it is caught and logged inside all Port methods, so they do not throw exceptions.
Use Input or Output subclasses in your module, not Port directly.
*/
struct Port {
/** For MIDI output, the channel to automatically set outbound messages.
If -1, the channel is not overwritten and must be set by MIDI generator.
For MIDI input, messages will be filtered by the channel.
If -1, all MIDI channels pass through.
*/
int channel = -1;
// private
int driverId = -1;
int deviceId = -1;
/** Not owned */
Driver* driver = NULL;
Device* device = NULL;
Context* context;
Port();
virtual ~Port();
Driver* getDriver();
int getDriverId();
void setDriverId(int driverId);
Device* getDevice();
virtual std::vector<int> getDeviceIds() = 0;
virtual int getDefaultDeviceId() = 0;
int getDeviceId();
virtual void setDeviceId(int deviceId) = 0;
virtual std::string getDeviceName(int deviceId) = 0;
virtual std::vector<int> getChannels() = 0;
int getChannel();
void setChannel(int channel);
std::string getChannelName(int channel);
json_t* toJson();
void fromJson(json_t* rootJ);
};
struct Input : Port {
/** Not owned */
InputDevice* inputDevice = NULL;
Input();
~Input();
void reset();
std::vector<int> getDeviceIds() override;
int getDefaultDeviceId() override;
void setDeviceId(int deviceId) override;
std::string getDeviceName(int deviceId) override;
std::vector<int> getChannels() override;
virtual void onMessage(const Message& message) {}
};
/** An Input port that stores incoming MIDI messages and releases them when ready according to their frame timestamp.
*/
struct InputQueue : Input {
struct Internal;
Internal* internal;
InputQueue();
~InputQueue();
void onMessage(const Message& message) override;
/** Pops and returns the next message (by setting `messageOut`) if its frame timestamp is `maxFrame` or earlier.
Returns whether a message was returned.
*/
bool tryPop(Message* messageOut, int64_t maxFrame);
size_t size();
};
struct Output : Port {
/** Not owned */
OutputDevice* outputDevice = NULL;
Output();
~Output();
void reset();
std::vector<int> getDeviceIds() override;
int getDefaultDeviceId() override;
void setDeviceId(int deviceId) override;
std::string getDeviceName(int deviceId) override;
std::vector<int> getChannels() override;
void sendMessage(const Message& message);
};
PRIVATE void init();
PRIVATE void destroy();
/** Registers a new MIDI driver. Takes pointer ownership. */
void addDriver(int driverId, Driver* driver);
std::vector<int> getDriverIds();
Driver* getDriver(int driverId);
} // namespace midi
} // namespace rack