1 #include <string.h>
2 #include <stdlib.h>
3 #include "rtmidi_c.h"
4 #include "RtMidi.h"
5
6 /* Compile-time assertions that will break if the enums are changed in
7 * the future without synchronizing them properly. If you get (g++)
8 * "error: ‘StaticAssert<b>::StaticAssert() [with bool b = false]’ is
9 * private within this context", it means enums are not aligned. */
StaticAssert()10 template<bool b> class StaticAssert { private: StaticAssert() {} };
StaticAssert()11 template<> class StaticAssert<true>{ public: StaticAssert() {} };
12 #define ENUM_EQUAL(x,y) StaticAssert<(int)x==(int)y>()
StaticAssertions()13 class StaticAssertions { StaticAssertions() {
14 ENUM_EQUAL( RTMIDI_API_UNSPECIFIED, RtMidi::UNSPECIFIED );
15 ENUM_EQUAL( RTMIDI_API_MACOSX_CORE, RtMidi::MACOSX_CORE );
16 ENUM_EQUAL( RTMIDI_API_LINUX_ALSA, RtMidi::LINUX_ALSA );
17 ENUM_EQUAL( RTMIDI_API_UNIX_JACK, RtMidi::UNIX_JACK );
18 ENUM_EQUAL( RTMIDI_API_WINDOWS_MM, RtMidi::WINDOWS_MM );
19 ENUM_EQUAL( RTMIDI_API_RTMIDI_DUMMY, RtMidi::RTMIDI_DUMMY );
20
21 ENUM_EQUAL( RTMIDI_ERROR_WARNING, RtMidiError::WARNING );
22 ENUM_EQUAL( RTMIDI_ERROR_DEBUG_WARNING, RtMidiError::DEBUG_WARNING );
23 ENUM_EQUAL( RTMIDI_ERROR_UNSPECIFIED, RtMidiError::UNSPECIFIED );
24 ENUM_EQUAL( RTMIDI_ERROR_NO_DEVICES_FOUND, RtMidiError::NO_DEVICES_FOUND );
25 ENUM_EQUAL( RTMIDI_ERROR_INVALID_DEVICE, RtMidiError::INVALID_DEVICE );
26 ENUM_EQUAL( RTMIDI_ERROR_MEMORY_ERROR, RtMidiError::MEMORY_ERROR );
27 ENUM_EQUAL( RTMIDI_ERROR_INVALID_PARAMETER, RtMidiError::INVALID_PARAMETER );
28 ENUM_EQUAL( RTMIDI_ERROR_INVALID_USE, RtMidiError::INVALID_USE );
29 ENUM_EQUAL( RTMIDI_ERROR_DRIVER_ERROR, RtMidiError::DRIVER_ERROR );
30 ENUM_EQUAL( RTMIDI_ERROR_SYSTEM_ERROR, RtMidiError::SYSTEM_ERROR );
31 ENUM_EQUAL( RTMIDI_ERROR_THREAD_ERROR, RtMidiError::THREAD_ERROR );
32 }};
33
34 class CallbackProxyUserData
35 {
36 public:
CallbackProxyUserData(RtMidiCCallback cCallback,void * userData)37 CallbackProxyUserData (RtMidiCCallback cCallback, void *userData)
38 : c_callback (cCallback), user_data (userData)
39 {
40 }
41 RtMidiCCallback c_callback;
42 void *user_data;
43 };
44
45 extern "C" const enum RtMidiApi rtmidi_compiled_apis[]; // casting from RtMidi::Api[]
46 extern "C" const unsigned int rtmidi_num_compiled_apis;
47
48 /* RtMidi API */
rtmidi_get_compiled_api(enum RtMidiApi * apis,unsigned int apis_size)49 int rtmidi_get_compiled_api (enum RtMidiApi *apis, unsigned int apis_size)
50 {
51 unsigned num = rtmidi_num_compiled_apis;
52 if (apis) {
53 num = (num < apis_size) ? num : apis_size;
54 memcpy(apis, rtmidi_compiled_apis, num * sizeof(enum RtMidiApi));
55 }
56 return (int)num;
57 }
58
59 extern "C" const char* rtmidi_api_names[][2];
rtmidi_api_name(enum RtMidiApi api)60 const char *rtmidi_api_name(enum RtMidiApi api) {
61 if (api < 0 || api >= RTMIDI_API_NUM)
62 return NULL;
63 return rtmidi_api_names[api][0];
64 }
65
rtmidi_api_display_name(enum RtMidiApi api)66 const char *rtmidi_api_display_name(enum RtMidiApi api)
67 {
68 if (api < 0 || api >= RTMIDI_API_NUM)
69 return "Unknown";
70 return rtmidi_api_names[api][1];
71 }
72
rtmidi_compiled_api_by_name(const char * name)73 enum RtMidiApi rtmidi_compiled_api_by_name(const char *name) {
74 RtMidi::Api api = RtMidi::UNSPECIFIED;
75 if (name) {
76 api = RtMidi::getCompiledApiByName(name);
77 }
78 return (enum RtMidiApi)api;
79 }
80
rtmidi_error(MidiApi * api,enum RtMidiErrorType type,const char * errorString)81 void rtmidi_error (MidiApi *api, enum RtMidiErrorType type, const char* errorString)
82 {
83 std::string msg = errorString;
84 api->error ((RtMidiError::Type) type, msg);
85 }
86
rtmidi_open_port(RtMidiPtr device,unsigned int portNumber,const char * portName)87 void rtmidi_open_port (RtMidiPtr device, unsigned int portNumber, const char *portName)
88 {
89 std::string name = portName;
90 try {
91 ((RtMidi*) device->ptr)->openPort (portNumber, name);
92
93 } catch (const RtMidiError & err) {
94 device->ok = false;
95 device->msg = err.what ();
96 }
97 }
98
rtmidi_open_virtual_port(RtMidiPtr device,const char * portName)99 void rtmidi_open_virtual_port (RtMidiPtr device, const char *portName)
100 {
101 std::string name = portName;
102 try {
103 ((RtMidi*) device->ptr)->openVirtualPort (name);
104
105 } catch (const RtMidiError & err) {
106 device->ok = false;
107 device->msg = err.what ();
108 }
109
110 }
111
rtmidi_close_port(RtMidiPtr device)112 void rtmidi_close_port (RtMidiPtr device)
113 {
114 try {
115 ((RtMidi*) device->ptr)->closePort ();
116
117 } catch (const RtMidiError & err) {
118 device->ok = false;
119 device->msg = err.what ();
120 }
121 }
122
rtmidi_get_port_count(RtMidiPtr device)123 unsigned int rtmidi_get_port_count (RtMidiPtr device)
124 {
125 try {
126 return ((RtMidi*) device->ptr)->getPortCount ();
127
128 } catch (const RtMidiError & err) {
129 device->ok = false;
130 device->msg = err.what ();
131 return -1;
132 }
133 }
134
rtmidi_get_port_name(RtMidiPtr device,unsigned int portNumber)135 const char* rtmidi_get_port_name (RtMidiPtr device, unsigned int portNumber)
136 {
137 try {
138 std::string name = ((RtMidi*) device->ptr)->getPortName (portNumber);
139 return strdup (name.c_str ());
140
141 } catch (const RtMidiError & err) {
142 device->ok = false;
143 device->msg = err.what ();
144 return "";
145 }
146 }
147
148 /* RtMidiIn API */
rtmidi_in_create_default()149 RtMidiInPtr rtmidi_in_create_default ()
150 {
151 RtMidiWrapper* wrp = new RtMidiWrapper;
152
153 try {
154 RtMidiIn* rIn = new RtMidiIn ();
155
156 wrp->ptr = (void*) rIn;
157 wrp->data = 0;
158 wrp->ok = true;
159 wrp->msg = "";
160
161 } catch (const RtMidiError & err) {
162 wrp->ptr = 0;
163 wrp->data = 0;
164 wrp->ok = false;
165 wrp->msg = err.what ();
166 }
167
168 return wrp;
169 }
170
rtmidi_in_create(enum RtMidiApi api,const char * clientName,unsigned int queueSizeLimit)171 RtMidiInPtr rtmidi_in_create (enum RtMidiApi api, const char *clientName, unsigned int queueSizeLimit)
172 {
173 std::string name = clientName;
174 RtMidiWrapper* wrp = new RtMidiWrapper;
175
176 try {
177 RtMidiIn* rIn = new RtMidiIn ((RtMidi::Api) api, name, queueSizeLimit);
178
179 wrp->ptr = (void*) rIn;
180 wrp->data = 0;
181 wrp->ok = true;
182 wrp->msg = "";
183
184 } catch (const RtMidiError & err) {
185 wrp->ptr = 0;
186 wrp->data = 0;
187 wrp->ok = false;
188 wrp->msg = err.what ();
189 }
190
191 return wrp;
192 }
193
rtmidi_in_free(RtMidiInPtr device)194 void rtmidi_in_free (RtMidiInPtr device)
195 {
196 if (device->data)
197 delete (CallbackProxyUserData*) device->data;
198 delete (RtMidiIn*) device->ptr;
199 delete device;
200 }
201
rtmidi_in_get_current_api(RtMidiPtr device)202 enum RtMidiApi rtmidi_in_get_current_api (RtMidiPtr device)
203 {
204 try {
205 return (RtMidiApi) ((RtMidiIn*) device->ptr)->getCurrentApi ();
206
207 } catch (const RtMidiError & err) {
208 device->ok = false;
209 device->msg = err.what ();
210
211 return RTMIDI_API_UNSPECIFIED;
212 }
213 }
214
215 static
callback_proxy(double timeStamp,std::vector<unsigned char> * message,void * userData)216 void callback_proxy (double timeStamp, std::vector<unsigned char> *message, void *userData)
217 {
218 CallbackProxyUserData* data = reinterpret_cast<CallbackProxyUserData*> (userData);
219 data->c_callback (timeStamp, message->data (), message->size (), data->user_data);
220 }
221
rtmidi_in_set_callback(RtMidiInPtr device,RtMidiCCallback callback,void * userData)222 void rtmidi_in_set_callback (RtMidiInPtr device, RtMidiCCallback callback, void *userData)
223 {
224 device->data = (void*) new CallbackProxyUserData (callback, userData);
225 try {
226 ((RtMidiIn*) device->ptr)->setCallback (callback_proxy, device->data);
227 } catch (const RtMidiError & err) {
228 device->ok = false;
229 device->msg = err.what ();
230 delete (CallbackProxyUserData*) device->data;
231 device->data = 0;
232 }
233 }
234
rtmidi_in_cancel_callback(RtMidiInPtr device)235 void rtmidi_in_cancel_callback (RtMidiInPtr device)
236 {
237 try {
238 ((RtMidiIn*) device->ptr)->cancelCallback ();
239 delete (CallbackProxyUserData*) device->data;
240 device->data = 0;
241 } catch (const RtMidiError & err) {
242 device->ok = false;
243 device->msg = err.what ();
244 }
245 }
246
rtmidi_in_ignore_types(RtMidiInPtr device,bool midiSysex,bool midiTime,bool midiSense)247 void rtmidi_in_ignore_types (RtMidiInPtr device, bool midiSysex, bool midiTime, bool midiSense)
248 {
249 ((RtMidiIn*) device->ptr)->ignoreTypes (midiSysex, midiTime, midiSense);
250 }
251
rtmidi_in_get_message(RtMidiInPtr device,unsigned char * message,size_t * size)252 double rtmidi_in_get_message (RtMidiInPtr device,
253 unsigned char *message,
254 size_t *size)
255 {
256 try {
257 // FIXME: use allocator to achieve efficient buffering
258 std::vector<unsigned char> v;
259 double ret = ((RtMidiIn*) device->ptr)->getMessage (&v);
260
261 if (v.size () > 0 && v.size() <= *size) {
262 memcpy (message, v.data (), (int) v.size ());
263 }
264
265 *size = v.size();
266 return ret;
267 }
268 catch (const RtMidiError & err) {
269 device->ok = false;
270 device->msg = err.what ();
271 return -1;
272 }
273 catch (...) {
274 device->ok = false;
275 device->msg = "Unknown error";
276 return -1;
277 }
278 }
279
280 /* RtMidiOut API */
rtmidi_out_create_default()281 RtMidiOutPtr rtmidi_out_create_default ()
282 {
283 RtMidiWrapper* wrp = new RtMidiWrapper;
284
285 try {
286 RtMidiOut* rOut = new RtMidiOut ();
287
288 wrp->ptr = (void*) rOut;
289 wrp->data = 0;
290 wrp->ok = true;
291 wrp->msg = "";
292
293 } catch (const RtMidiError & err) {
294 wrp->ptr = 0;
295 wrp->data = 0;
296 wrp->ok = false;
297 wrp->msg = err.what ();
298 }
299
300 return wrp;
301 }
302
rtmidi_out_create(enum RtMidiApi api,const char * clientName)303 RtMidiOutPtr rtmidi_out_create (enum RtMidiApi api, const char *clientName)
304 {
305 RtMidiWrapper* wrp = new RtMidiWrapper;
306 std::string name = clientName;
307
308 try {
309 RtMidiOut* rOut = new RtMidiOut ((RtMidi::Api) api, name);
310
311 wrp->ptr = (void*) rOut;
312 wrp->data = 0;
313 wrp->ok = true;
314 wrp->msg = "";
315
316 } catch (const RtMidiError & err) {
317 wrp->ptr = 0;
318 wrp->data = 0;
319 wrp->ok = false;
320 wrp->msg = err.what ();
321 }
322
323
324 return wrp;
325 }
326
rtmidi_out_free(RtMidiOutPtr device)327 void rtmidi_out_free (RtMidiOutPtr device)
328 {
329 delete (RtMidiOut*) device->ptr;
330 delete device;
331 }
332
rtmidi_out_get_current_api(RtMidiPtr device)333 enum RtMidiApi rtmidi_out_get_current_api (RtMidiPtr device)
334 {
335 try {
336 return (RtMidiApi) ((RtMidiOut*) device->ptr)->getCurrentApi ();
337
338 } catch (const RtMidiError & err) {
339 device->ok = false;
340 device->msg = err.what ();
341
342 return RTMIDI_API_UNSPECIFIED;
343 }
344 }
345
rtmidi_out_send_message(RtMidiOutPtr device,const unsigned char * message,int length)346 int rtmidi_out_send_message (RtMidiOutPtr device, const unsigned char *message, int length)
347 {
348 try {
349 ((RtMidiOut*) device->ptr)->sendMessage (message, length);
350 return 0;
351 }
352 catch (const RtMidiError & err) {
353 device->ok = false;
354 device->msg = err.what ();
355 return -1;
356 }
357 catch (...) {
358 device->ok = false;
359 device->msg = "Unknown error";
360 return -1;
361 }
362 }
363