1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 14 марта 2016 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef CORE_MIDI_H_
23 #define CORE_MIDI_H_
24 
25 #include <core/types.h>
26 
27 namespace lsp
28 {
29     // Generalized midi event structure
30     namespace midi
31     {
32     #pragma pack(push, 1)
33         typedef struct event_t
34         {
35             uint32_t        timestamp;      // Timestamp
36             uint8_t         type;           // Type of event
37             uint8_t         channel;        // ID of the MIDI channel
38             union
39             {
40                 uint8_t         bparams[2];     // Byte parameters
41 
42                 struct
43                 {
44                     uint8_t         pitch;         // Note key
45                     uint8_t         velocity;      // Note velocity
46                 } note;
47 
48                 struct
49                 {
50                     uint8_t         control;       // Control
51                     uint8_t         value;         // Value
52                 } ctl;
53 
54                 struct
55                 {
56                     uint8_t         pitch;          // Note key
57                     uint8_t         pressure;       // Note pressure
58                 } atouch;
59 
60                 struct
61                 {
62                     uint8_t         pressure;        // Channel pressure
63                 } chn;
64 
65                 uint8_t         program;         // program
66                 uint16_t        bend;
67 
68                 struct
69                 {
70                     uint8_t         type;
71                     uint8_t         value;
72                 } mtc;
73 
74                 uint16_t        beats;
75                 uint8_t         song;
76             };
77         } event_t;
78     #pragma pack(pop)
79 
80         enum message_t
81         {
82             MIDI_MSG_NOTE_OFF               = 0x80,
83             MIDI_MSG_NOTE_ON                = 0x90,
84             MIDI_MSG_NOTE_PRESSURE          = 0xa0,
85             MIDI_MSG_NOTE_CONTROLLER        = 0xb0,
86             MIDI_MSG_PROGRAM_CHANGE         = 0xc0,
87             MIDI_MSG_CHANNEL_PRESSURE       = 0xd0,
88             MIDI_MSG_PITCH_BEND             = 0xe0,
89             MIDI_MSG_SYSTEM_EXCLUSIVE       = 0xf0,
90             MIDI_MSG_MTC_QUARTER            = 0xf1,
91             MIDI_MSG_SONG_POS               = 0xf2,
92             MIDI_MSG_SONG_SELECT            = 0xf3,
93             MIDI_MSG_TUNE_REQUEST           = 0xf6,
94             MIDI_MSG_END_EXCLUSIVE          = 0xf7,
95             MIDI_MSG_CLOCK                  = 0xf8,
96             MIDI_MSG_START                  = 0xfa,
97             MIDI_MSG_CONTINUE               = 0xfb,
98             MIDI_MSG_STOP                   = 0xfc,
99             MIDI_MSG_ACTIVE_SENSING         = 0xfe,
100             MIDI_MSG_RESET                  = 0xff
101         };
102 
103         enum controller_t
104         {
105             MIDI_CTL_MSB_BANK               = 0x00,
106             MIDI_CTL_MSB_MODWHEEL           = 0x01,
107             MIDI_CTL_MSB_BREATH             = 0x02,
108             MIDI_CTL_MSB_FOOT               = 0x04,
109             MIDI_CTL_MSB_PORTAMENTO_TIME    = 0x05,
110             MIDI_CTL_MSB_DATA_ENTRY         = 0x06,
111             MIDI_CTL_MSB_MAIN_VOLUME        = 0x07,
112             MIDI_CTL_MSB_BALANCE            = 0x08,
113             MIDI_CTL_MSB_PAN                = 0x0a,
114             MIDI_CTL_MSB_EXPRESSION         = 0x0b,
115             MIDI_CTL_MSB_EFFECT1            = 0x0c,
116             MIDI_CTL_MSB_EFFECT2            = 0x0d,
117             MIDI_CTL_MSB_GENERAL_PURPOSE1   = 0x10,
118             MIDI_CTL_MSB_GENERAL_PURPOSE2   = 0x11,
119             MIDI_CTL_MSB_GENERAL_PURPOSE3   = 0x12,
120             MIDI_CTL_MSB_GENERAL_PURPOSE4   = 0x13,
121             MIDI_CTL_LSB_BANK               = 0x20,
122             MIDI_CTL_LSB_MODWHEEL           = 0x21,
123             MIDI_CTL_LSB_BREATH             = 0x22,
124             MIDI_CTL_LSB_FOOT               = 0x24,
125             MIDI_CTL_LSB_PORTAMENTO_TIME    = 0x25,
126             MIDI_CTL_LSB_DATA_ENTRY         = 0x26,
127             MIDI_CTL_LSB_MAIN_VOLUME        = 0x27,
128             MIDI_CTL_LSB_BALANCE            = 0x28,
129             MIDI_CTL_LSB_PAN                = 0x2a,
130             MIDI_CTL_LSB_EXPRESSION         = 0x2b,
131             MIDI_CTL_LSB_EFFECT1            = 0x2c,
132             MIDI_CTL_LSB_EFFECT2            = 0x2d,
133             MIDI_CTL_LSB_GENERAL_PURPOSE1   = 0x30,
134             MIDI_CTL_LSB_GENERAL_PURPOSE2   = 0x31,
135             MIDI_CTL_LSB_GENERAL_PURPOSE3   = 0x32,
136             MIDI_CTL_LSB_GENERAL_PURPOSE4   = 0x33,
137             MIDI_CTL_SUSTAIN                = 0x40,
138             MIDI_CTL_PORTAMENTO             = 0x41,
139             MIDI_CTL_SOSTENUTO              = 0x42,
140             MIDI_CTL_SOFT_PEDAL             = 0x43,
141             MIDI_CTL_LEGATO_FOOTSWITCH      = 0x44,
142             MIDI_CTL_HOLD2                  = 0x45,
143             MIDI_CTL_SC1_SOUND_VARIATION    = 0x46,
144             MIDI_CTL_SC2_TIMBRE             = 0x47,
145             MIDI_CTL_SC3_RELEASE_TIME       = 0x48,
146             MIDI_CTL_SC4_ATTACK_TIME        = 0x49,
147             MIDI_CTL_SC5_BRIGHTNESS         = 0x4a,
148             MIDI_CTL_SC6                    = 0x4b,
149             MIDI_CTL_SC7                    = 0x4c,
150             MIDI_CTL_SC8                    = 0x4d,
151             MIDI_CTL_SC9                    = 0x4e,
152             MIDI_CTL_SC10                   = 0x4f,
153             MIDI_CTL_GENERAL_PURPOSE5       = 0x50,
154             MIDI_CTL_GENERAL_PURPOSE6       = 0x51,
155             MIDI_CTL_GENERAL_PURPOSE7       = 0x52,
156             MIDI_CTL_GENERAL_PURPOSE8       = 0x53,
157             MIDI_CTL_PORTAMENTO_CONTROL     = 0x54,
158             MIDI_CTL_E1_REVERB_DEPTH        = 0x5b,
159             MIDI_CTL_E2_TREMOLO_DEPTH       = 0x5c,
160             MIDI_CTL_E3_CHORUS_DEPTH        = 0x5d,
161             MIDI_CTL_E4_DETUNE_DEPTH        = 0x5e,
162             MIDI_CTL_E5_PHASER_DEPTH        = 0x5f,
163             MIDI_CTL_DATA_INCREMENT         = 0x60,
164             MIDI_CTL_DATA_DECREMENT         = 0x61,
165             MIDI_CTL_NRPN_LSB               = 0x62,
166             MIDI_CTL_NRPN_MSB               = 0x63,
167             MIDI_CTL_RPN_LSB                = 0x64,
168             MIDI_CTL_RPN_MSB                = 0x65,
169             MIDI_CTL_ALL_SOUNDS_OFF         = 0x78,
170             MIDI_CTL_RESET_CONTROLLERS      = 0x79,
171             MIDI_CTL_LOCAL_CONTROL_SWITCH   = 0x7a,
172             MIDI_CTL_ALL_NOTES_OFF          = 0x7b,
173             MIDI_CTL_OMNI_OFF               = 0x7c,
174             MIDI_CTL_OMNI_ON                = 0x7d,
175             MIDI_CTL_MONO1                  = 0x7e,
176             MIDI_CTL_MONO2                  = 0x7f
177         };
178 
179         /**
180          * Decode MIDI message
181          * @param ev MIDI event structure to decode
182          * @param bytes buffer containing MIDI message
183          * @return number of bytes used for decodingm negative value on error, never zero
184          */
185         ssize_t decode(event_t *ev, const uint8_t *bytes);
186 
187         /**
188          * Encode MIDI message
189          * @param bytes buffer to store encoded MIDI message
190          * @param ev MIDI event to encode
191          * @return number of bytes used for encoding, negative value on error, never zero
192          */
193         ssize_t encode(uint8_t *bytes, const event_t *ev);
194 
195         /**
196          * Return number of bytes required for encoding
197          * @param ev MIDI event
198          * @return number of bytes required to encode MIDI event, negative value on error, never zero
199          */
200         ssize_t size_of(const event_t *ev);
201     }
202 
203     // Midi port structure
204     typedef struct midi_t
205     {
206         size_t          nEvents;
207         midi::event_t   vEvents[MIDI_EVENTS_MAX];
208 
pushmidi_t209         inline bool push(const midi::event_t *me)
210         {
211             if (nEvents >= MIDI_EVENTS_MAX)
212                 return false;
213             vEvents[nEvents++]      = *me;
214             return true;
215         }
216 
pushmidi_t217         inline bool push(const midi::event_t &me)
218         {
219             return push(&me);
220         }
221 
push_allmidi_t222         inline bool push_all(const midi_t *src)
223         {
224             size_t avail    = MIDI_EVENTS_MAX - nEvents;
225             size_t count    = (src->nEvents > avail) ? avail : src->nEvents;
226             if (count > 0)
227             {
228                 ::memcpy(&vEvents[nEvents], src->vEvents, count * sizeof(midi::event_t));
229                 nEvents        += count;
230             }
231 
232             return count >= src->nEvents;
233         }
234 
push_allmidi_t235         inline bool push_all(const midi_t &src)
236         {
237             return push_all(&src);
238         }
239 
copy_frommidi_t240         inline void copy_from(const midi_t *src)
241         {
242             nEvents     = src->nEvents;
243             if (nEvents > 0)
244                 ::memcpy(vEvents, src->vEvents, nEvents * sizeof(midi::event_t));
245         }
246 
copy_tomidi_t247         inline void copy_to(midi_t *dst) const
248         {
249             dst->copy_from(this);
250         }
251 
clearmidi_t252         inline void clear()
253         {
254             nEvents     = 0;
255         }
256 
257         void sort();
258     } midi_t;
259 }
260 
261 #endif /* CORE_MIDI_H_ */
262