You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
5.4KB

  1. #include <rtmidi.hpp>
  2. #include <midi.hpp>
  3. #include <map>
  4. #pragma GCC diagnostic push
  5. #ifndef __clang__
  6. #pragma GCC diagnostic ignored "-Wsuggest-override"
  7. #endif
  8. #include <rtmidi/RtMidi.h>
  9. #pragma GCC diagnostic pop
  10. namespace rack {
  11. struct RtMidiInputDevice : midi::InputDevice {
  12. RtMidiIn* rtMidiIn;
  13. std::string name;
  14. RtMidiInputDevice(int driverId, int deviceId) {
  15. rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack");
  16. assert(rtMidiIn);
  17. rtMidiIn->ignoreTypes(false, false, false);
  18. rtMidiIn->setCallback(midiInputCallback, this);
  19. name = rtMidiIn->getPortName(deviceId);
  20. rtMidiIn->openPort(deviceId, "VCV Rack input");
  21. }
  22. ~RtMidiInputDevice() {
  23. rtMidiIn->closePort();
  24. delete rtMidiIn;
  25. }
  26. std::string getName() override {
  27. return name;
  28. }
  29. static void midiInputCallback(double timeStamp, std::vector<unsigned char>* message, void* userData) {
  30. if (!message)
  31. return;
  32. if (!userData)
  33. return;
  34. RtMidiInputDevice* midiInputDevice = (RtMidiInputDevice*) userData;
  35. if (!midiInputDevice)
  36. return;
  37. // Users have reported that some MIDI devices can send messages >3 bytes. I don't know how this is possible, so just reject the message.
  38. if (message->size() > 3)
  39. return;
  40. midi::Message msg;
  41. msg.size = message->size();
  42. for (int i = 0; i < msg.size; i++) {
  43. msg.bytes[i] = (*message)[i];
  44. }
  45. midiInputDevice->onMessage(msg);
  46. }
  47. };
  48. struct RtMidiOutputDevice : midi::OutputDevice {
  49. RtMidiOut* rtMidiOut;
  50. std::string name;
  51. RtMidiOutputDevice(int driverId, int deviceId) {
  52. rtMidiOut = new RtMidiOut((RtMidi::Api) driverId, "VCV Rack");
  53. assert(rtMidiOut);
  54. name = rtMidiOut->getPortName(deviceId);
  55. rtMidiOut->openPort(deviceId, "VCV Rack output");
  56. }
  57. ~RtMidiOutputDevice() {
  58. rtMidiOut->closePort();
  59. delete rtMidiOut;
  60. }
  61. std::string getName() override {
  62. return name;
  63. }
  64. void sendMessage(midi::Message message) override {
  65. rtMidiOut->sendMessage(message.bytes, message.size);
  66. }
  67. };
  68. struct RtMidiDriver : midi::Driver {
  69. int driverId;
  70. /** Just for querying MIDI driver information */
  71. RtMidiIn* rtMidiIn;
  72. RtMidiOut* rtMidiOut;
  73. std::map<int, RtMidiInputDevice*> inputDevices;
  74. std::map<int, RtMidiOutputDevice*> outputDevices;
  75. RtMidiDriver(int driverId) {
  76. this->driverId = driverId;
  77. rtMidiIn = new RtMidiIn((RtMidi::Api) driverId);
  78. assert(rtMidiIn);
  79. rtMidiOut = new RtMidiOut((RtMidi::Api) driverId);
  80. assert(rtMidiOut);
  81. }
  82. ~RtMidiDriver() {
  83. assert(inputDevices.empty());
  84. assert(outputDevices.empty());
  85. delete rtMidiIn;
  86. delete rtMidiOut;
  87. }
  88. std::string getName() override {
  89. switch (driverId) {
  90. case RtMidi::UNSPECIFIED: return "Unspecified";
  91. case RtMidi::MACOSX_CORE: return "Core MIDI";
  92. case RtMidi::LINUX_ALSA: return "ALSA";
  93. case RtMidi::UNIX_JACK: return "JACK";
  94. case RtMidi::WINDOWS_MM: return "Windows MIDI";
  95. case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI";
  96. default: return "";
  97. }
  98. }
  99. std::vector<int> getInputDeviceIds() override {
  100. // TODO The IDs unfortunately jump around in RtMidi. Is there a way to keep them constant when a MIDI device is added/removed?
  101. int count = rtMidiIn->getPortCount();
  102. std::vector<int> deviceIds;
  103. for (int i = 0; i < count; i++)
  104. deviceIds.push_back(i);
  105. return deviceIds;
  106. }
  107. std::string getInputDeviceName(int deviceId) override {
  108. if (deviceId >= 0) {
  109. return rtMidiIn->getPortName(deviceId);
  110. }
  111. return "";
  112. }
  113. midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override {
  114. if (!(0 <= deviceId && deviceId < (int) rtMidiIn->getPortCount()))
  115. return NULL;
  116. RtMidiInputDevice* device = inputDevices[deviceId];
  117. if (!device) {
  118. inputDevices[deviceId] = device = new RtMidiInputDevice(driverId, deviceId);
  119. }
  120. device->subscribe(input);
  121. return device;
  122. }
  123. void unsubscribeInput(int deviceId, midi::Input* input) override {
  124. auto it = inputDevices.find(deviceId);
  125. if (it == inputDevices.end())
  126. return;
  127. RtMidiInputDevice* device = it->second;
  128. device->unsubscribe(input);
  129. // Destroy device if nothing is subscribed anymore
  130. if (device->subscribed.empty()) {
  131. inputDevices.erase(it);
  132. delete device;
  133. }
  134. }
  135. std::vector<int> getOutputDeviceIds() override {
  136. int count = rtMidiOut->getPortCount();
  137. std::vector<int> deviceIds;
  138. for (int i = 0; i < count; i++)
  139. deviceIds.push_back(i);
  140. return deviceIds;
  141. }
  142. std::string getOutputDeviceName(int deviceId) override {
  143. if (deviceId >= 0) {
  144. return rtMidiOut->getPortName(deviceId);
  145. }
  146. return "";
  147. }
  148. midi::OutputDevice* subscribeOutput(int deviceId, midi::Output* output) override {
  149. if (!(0 <= deviceId && deviceId < (int) rtMidiOut->getPortCount()))
  150. return NULL;
  151. RtMidiOutputDevice* device = outputDevices[deviceId];
  152. if (!device) {
  153. outputDevices[deviceId] = device = new RtMidiOutputDevice(driverId, deviceId);
  154. }
  155. device->subscribe(output);
  156. return device;
  157. }
  158. void unsubscribeOutput(int deviceId, midi::Output* output) override {
  159. auto it = outputDevices.find(deviceId);
  160. if (it == outputDevices.end())
  161. return;
  162. RtMidiOutputDevice* device = it->second;
  163. device->unsubscribe(output);
  164. // Destroy device if nothing is subscribed anymore
  165. if (device->subscribed.empty()) {
  166. outputDevices.erase(it);
  167. delete device;
  168. }
  169. }
  170. };
  171. void rtmidiInit() {
  172. std::vector<RtMidi::Api> rtApis;
  173. RtMidi::getCompiledApi(rtApis);
  174. for (RtMidi::Api api : rtApis) {
  175. int driverId = (int) api;
  176. midi::Driver* driver = new RtMidiDriver(driverId);
  177. midi::addDriver(driverId, driver);
  178. }
  179. }
  180. } // namespace rack