Zrythm
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
midi.h
Go to the documentation of this file.
1// clang-format off
2// SPDX-FileCopyrightText: © 2018-2023 Alexandros Theodotou <alex@zrythm.org>
3// SPDX-License-Identifier: LicenseRef-ZrythmLicense
4/*
5 * This file incorporates work covered by the following copyright and
6 * permission notice:
7 *
8 * ---
9 *
10 * CHOC is (C)2021 Tracktion Corporation, and is offered under the terms of the ISC license:
11 *
12 * Permission to use, copy, modify, and/or distribute this software for any purpose with or
13 * without fee is hereby granted, provided that the above copyright notice and this permission
14 * notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
15 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
16 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 * ---
22 */
23// clang-format on
24
31#ifndef __AUDIO_MIDI_H__
32#define __AUDIO_MIDI_H__
33
34#include "zrythm-config.h"
35
36#include <stdint.h>
37#include <string.h>
38
39#include "utils/types.h"
40
41#include <gtk/gtk.h>
42
49/* see http://www.onicos.com/staff/iz/formats/midi-event.html */
50#define MIDI_CH1_NOTE_ON 0x90
51#define MIDI_CH1_NOTE_OFF 0x80
53#define MIDI_CH1_POLY_AFTERTOUCH 0xA0
54#define MIDI_CH1_CTRL_CHANGE 0xB0
55#define MIDI_CH1_PROG_CHANGE 0xC0
57#define MIDI_CH1_CHAN_AFTERTOUCH 0xD0
58#define MIDI_CH1_PITCH_WHEEL_RANGE 0xE0
59#define MIDI_ALL_NOTES_OFF 0x7B
60#define MIDI_ALL_SOUND_OFF 0x78
61#define MIDI_SYSTEM_MESSAGE 0xF0
62#define MIDI_SONG_POSITION 0xF2
63#define MIDI_CLOCK_START 0xFA
64#define MIDI_CLOCK_CONTINUE 0xFB
65#define MIDI_CLOCK_BEAT 0xF8
66#define MIDI_CLOCK_STOP 0xFC
67#define MIDI_META_EVENT 0xFF
68
72CONST
73const char *
75
83void
85 const uint32_t val,
86 midi_byte_t * lsb,
87 midi_byte_t * msb);
88
95int
97
102int
103midi_get_msg_length (const uint8_t status_byte);
104
109static inline float
110midi_note_number_to_frequency (const uint8_t note)
111{
112 return 440.f * powf (2.f, ((float) note - 69.f) * (1.f / 12.f));
113}
114
115static inline uint8_t
116midi_frequency_to_note_number (const float freq)
117{
118 return (uint8_t) round (
119 69.f + (12.f / logf (2.f)) * logf (freq * (1.0f / 440.f)));
120}
121
128static inline uint8_t
129midi_get_chromatic_scale_index (const uint8_t note)
130{
131 return note % 12;
132}
133
139static inline uint8_t
140midi_get_octave_number (const uint8_t note)
141{
142 const uint8_t octave_for_middle_c = 3;
143 return note / 12 + (uint8_t) (octave_for_middle_c - 5);
144}
145
150static inline bool
151midi_is_short_message_type (
152 const midi_byte_t short_msg[3],
153 const midi_byte_t type)
154{
155 return (short_msg[0] & 0xf0) == type;
156}
157
158static inline midi_byte_t
159midi_get_note_number (const midi_byte_t short_msg[3])
160{
161 return short_msg[1];
162}
163
164static inline midi_byte_t
165midi_get_velocity (const midi_byte_t short_msg[3])
166{
167 return short_msg[2];
168}
169
173CONST
174const char *
176
177void
178midi_get_note_name_with_octave (const midi_byte_t short_msg[3], char * buf);
179
180static inline bool
181midi_is_note_on (const midi_byte_t short_msg[3])
182{
183 return midi_is_short_message_type (short_msg, MIDI_CH1_NOTE_ON)
184 && midi_get_velocity (short_msg) != 0;
185}
186
187static inline bool
188midi_is_note_off (const midi_byte_t short_msg[3])
189{
190 return midi_is_short_message_type (short_msg, MIDI_CH1_NOTE_OFF)
191 || (midi_is_short_message_type (short_msg, MIDI_CH1_NOTE_ON) && midi_get_velocity (short_msg) == 0);
192}
193
194static inline bool
195midi_is_program_change (const midi_byte_t short_msg[3])
196{
197 return midi_is_short_message_type (short_msg, MIDI_CH1_PROG_CHANGE);
198}
199
200static inline midi_byte_t
201midi_get_program_change_number (const midi_byte_t short_msg[3])
202{
203 return short_msg[1];
204}
205
206static inline bool
207midi_is_pitch_wheel (const midi_byte_t short_msg[3])
208{
209 return midi_is_short_message_type (short_msg, MIDI_CH1_PITCH_WHEEL_RANGE);
210}
211
212static inline bool
213midi_is_aftertouch (const midi_byte_t short_msg[3])
214{
215 return midi_is_short_message_type (short_msg, MIDI_CH1_POLY_AFTERTOUCH);
216}
217
218static inline bool
219midi_is_channel_pressure (const midi_byte_t short_msg[3])
220{
221 return midi_is_short_message_type (short_msg, MIDI_CH1_CHAN_AFTERTOUCH);
222}
223
224static inline bool
225midi_is_controller (const midi_byte_t short_msg[3])
226{
227 return midi_is_short_message_type (short_msg, MIDI_CH1_CTRL_CHANGE);
228}
229
238static inline uint32_t
239midi_get_14_bit_value (const midi_byte_t short_msg[3])
240{
241 return short_msg[1] | ((uint32_t) short_msg[2] << 7);
242}
243
244static inline midi_byte_t
245midi_get_channel_0_to_15 (const midi_byte_t short_msg[3])
246{
247 return short_msg[0] & 0x0f;
248}
249
250static inline midi_byte_t
251midi_get_channel_1_to_16 (const midi_byte_t short_msg[3])
252{
253 return midi_get_channel_0_to_15 (short_msg) + 1u;
254}
255
256static inline uint32_t
257midi_get_pitchwheel_value (const midi_byte_t short_msg[3])
258{
259 return midi_get_14_bit_value (short_msg);
260}
261
262static inline midi_byte_t
263midi_get_aftertouch_value (const midi_byte_t short_msg[3])
264{
265 return short_msg[2];
266}
267
268static inline midi_byte_t
269midi_get_channel_pressure_value (const midi_byte_t short_msg[3])
270{
271 return short_msg[1];
272}
273
274static inline midi_byte_t
275midi_get_controller_number (const midi_byte_t short_msg[3])
276{
277 return short_msg[1];
278}
279
280static inline midi_byte_t
281midi_get_controller_value (const midi_byte_t short_msg[3])
282{
283 return short_msg[2];
284}
285
286static inline bool
287midi_is_all_notes_off (const midi_byte_t short_msg[3])
288{
289 return midi_is_controller (short_msg)
290 && midi_get_controller_number (short_msg) == 123;
291}
292
293static inline bool
294midi_is_all_sound_off (const midi_byte_t short_msg[3])
295{
296 return midi_is_controller (short_msg)
297 && midi_get_controller_number (short_msg) == 120;
298}
299
300static inline bool
301midi_is_quarter_frame (const midi_byte_t short_msg[3])
302{
303 return short_msg[0] == 0xf1;
304}
305
306static inline bool
307midi_is_clock (const midi_byte_t short_msg[3])
308{
309 return short_msg[0] == 0xf8;
310}
311
312static inline bool
313midi_is_start (const midi_byte_t short_msg[3])
314{
315 return short_msg[0] == 0xfa;
316}
317
318static inline bool
319midi_is_continue (const midi_byte_t short_msg[3])
320{
321 return short_msg[0] == 0xfb;
322}
323
324static inline bool
325midi_is_stop (const midi_byte_t short_msg[3])
326{
327 return short_msg[0] == 0xfc;
328}
329
330static inline bool
331midi_is_active_sense (const midi_byte_t short_msg[3])
332{
333 return short_msg[0] == 0xfe;
334}
335
336static inline bool
337midi_is_song_position_pointer (const midi_byte_t short_msg[3])
338{
339 return short_msg[0] == 0xf2;
340}
341
342static inline uint32_t
343midi_get_song_position_pointer_value (const midi_byte_t short_msg[3])
344{
345 return midi_get_14_bit_value (short_msg);
346}
347
348void
349midi_get_hex_str (const midi_byte_t * msg, const size_t msg_sz, char * buf);
350
351void
352midi_print_to_str (const midi_byte_t * msg, const size_t msg_sz, char * buf);
353
354void
355midi_print (const midi_byte_t * msg, const size_t msg_sz);
356
357static inline bool
358midi_is_short_msg (const midi_byte_t * msg, const size_t msg_sz)
359{
360 g_return_val_if_fail (msg_sz > 0, false);
361
362 if (msg_sz > 3)
363 return false;
364
365 return msg[0] != MIDI_SYSTEM_MESSAGE && msg[0] != MIDI_META_EVENT;
366}
367
368static inline bool
369midi_is_sysex (const midi_byte_t * msg, const size_t msg_sz)
370{
371 return msg_sz > 1 && msg[0] == MIDI_SYSTEM_MESSAGE;
372}
373
374static inline bool
375midi_is_meta_event (const midi_byte_t * msg, const size_t msg_sz)
376{
377 return msg_sz > 2 && msg[0] == MIDI_META_EVENT;
378}
379
380static inline bool
381midi_is_short_msg_meta_event (const midi_byte_t short_msg[3])
382{
383 return midi_is_meta_event (short_msg, 3);
384}
385
386static inline bool
387midi_is_meta_event_of_type (
388 const midi_byte_t * msg,
389 const size_t msg_sz,
390 const midi_byte_t type)
391{
392 return msg_sz > 2 && msg[1] == type && msg[0] == MIDI_META_EVENT;
393}
394
395static inline midi_byte_t
396midi_get_meta_event_type (const midi_byte_t * msg, const size_t msg_sz)
397{
398 g_return_val_if_fail (midi_is_meta_event (msg, msg_sz), 0);
399
400 return msg[1];
401}
402
403void
404midi_get_meta_event_type_name (char * buf, const midi_byte_t type);
405
417static inline size_t
418midi_get_meta_event_data (
419 const midi_byte_t ** data,
420 const midi_byte_t * msg,
421 const size_t msg_sz)
422{
423 g_return_val_if_fail (midi_is_meta_event (msg, msg_sz), 0);
424
425 /* malformed data */
426 if (msg_sz < 4)
427 return 0;
428
429 size_t content_len = 0;
430 size_t len_bytes = 0;
431 for (size_t i = 2; i < msg_sz; i++)
432 {
433 const midi_byte_t byte = msg[i];
434 len_bytes++;
435 content_len = (content_len << 7) | (byte & 0x7fu);
436
437 if (byte < 0x80)
438 break;
439
440 if (len_bytes == 4 || len_bytes + 2 == msg_sz)
441 return 0; /* malformed data */
442 }
443
444 size_t content_start = len_bytes + 2;
445
446 if (content_start + content_len > msg_sz)
447 return 0; /* malformed data */
448
449 *data = &msg[content_start];
450 return content_len;
451}
452
457#endif
void midi_get_bytes_from_combined(const uint32_t val, midi_byte_t *lsb, midi_byte_t *msb)
Used for MIDI controls whose values are split between MSB/LSB.
int midi_get_msg_length(const uint8_t status_byte)
Returns the length of the MIDI message based on the status byte.
CONST const char * midi_get_controller_name(const midi_byte_t cc)
Return the name of the given cc (0-127).
int midi_ctrl_change_get_ch_and_description(midi_byte_t *ctrl_change, char *buf)
Saves a string representation of the given control change event in the given buffer.
CONST const char * midi_get_note_name(const midi_byte_t note)
Returns the note name (eg, "C") for a value between 0 and 127.
#define MIDI_CH1_CHAN_AFTERTOUCH
Also known as Channel Pressure.
Definition midi.h:57
#define MIDI_CH1_POLY_AFTERTOUCH
Also known as Polyphonic Key Pressure.
Definition midi.h:53
uint8_t midi_byte_t
MIDI byte.
Definition types.h:32
String utilities.
Custom types.