rtmidi_c.cpp 10.0 KB

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