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.

214 lines
5.2KB

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