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