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.

119 lines
3.0KB

  1. #include "rtmidi.hpp"
  2. #include <map>
  3. namespace rack {
  4. static void midiInputCallback(double timeStamp, std::vector<unsigned char> *message, void *userData) {
  5. if (!message) return;
  6. if (!userData) return;
  7. RtMidiInputDevice *midiInputDevice = (RtMidiInputDevice*) userData;
  8. if (!midiInputDevice) return;
  9. MidiMessage msg;
  10. if (message->size() >= 1)
  11. msg.cmd = (*message)[0];
  12. if (message->size() >= 2)
  13. msg.data1 = (*message)[1];
  14. if (message->size() >= 3)
  15. msg.data2 = (*message)[2];
  16. midiInputDevice->onMessage(msg);
  17. }
  18. RtMidiInputDevice::RtMidiInputDevice(int driverId, int deviceId) {
  19. rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack");
  20. assert(rtMidiIn);
  21. rtMidiIn->ignoreTypes(false, false, false);
  22. rtMidiIn->setCallback(midiInputCallback, this);
  23. rtMidiIn->openPort(deviceId, "VCV Rack input");
  24. }
  25. RtMidiInputDevice::~RtMidiInputDevice() {
  26. rtMidiIn->closePort();
  27. delete rtMidiIn;
  28. }
  29. RtMidiDriver::RtMidiDriver(int driverId) {
  30. this->driverId = driverId;
  31. rtMidiIn = new RtMidiIn((RtMidi::Api) driverId);
  32. assert(rtMidiIn);
  33. rtMidiOut = new RtMidiOut((RtMidi::Api) driverId);
  34. assert(rtMidiOut);
  35. }
  36. RtMidiDriver::~RtMidiDriver() {
  37. delete rtMidiIn;
  38. delete rtMidiOut;
  39. }
  40. std::string RtMidiDriver::getName() {
  41. switch (driverId) {
  42. case RtMidi::UNSPECIFIED: return "Unspecified";
  43. case RtMidi::MACOSX_CORE: return "Core MIDI";
  44. case RtMidi::LINUX_ALSA: return "ALSA";
  45. case RtMidi::UNIX_JACK: return "JACK";
  46. case RtMidi::WINDOWS_MM: return "Windows MIDI";
  47. case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI";
  48. default: return "";
  49. }
  50. }
  51. std::vector<int> RtMidiDriver::getInputDeviceIds() {
  52. // TODO The IDs unfortunately jump around in RtMidi. Is there a way to keep them constant when a MIDI device is added/removed?
  53. int count = rtMidiIn->getPortCount();
  54. std::vector<int> deviceIds;
  55. for (int i = 0; i < count; i++)
  56. deviceIds.push_back(i);
  57. return deviceIds;
  58. }
  59. std::string RtMidiDriver::getInputDeviceName(int deviceId) {
  60. if (deviceId >= 0) {
  61. return rtMidiIn->getPortName(deviceId);
  62. }
  63. return "";
  64. }
  65. MidiInputDevice *RtMidiDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) {
  66. if (!(0 <= deviceId && deviceId < (int) rtMidiIn->getPortCount()))
  67. return NULL;
  68. RtMidiInputDevice *device = devices[deviceId];
  69. if (!device) {
  70. devices[deviceId] = device = new RtMidiInputDevice(driverId, deviceId);
  71. }
  72. device->subscribe(midiInput);
  73. return device;
  74. }
  75. void RtMidiDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) {
  76. auto it = devices.find(deviceId);
  77. if (it == devices.end())
  78. return;
  79. RtMidiInputDevice *device = it->second;
  80. device->unsubscribe(midiInput);
  81. // Destroy device if nothing is subscribed anymore
  82. if (device->subscribed.empty()) {
  83. devices.erase(it);
  84. delete device;
  85. }
  86. }
  87. void rtmidiInit() {
  88. std::vector<RtMidi::Api> rtApis;
  89. RtMidi::getCompiledApi(rtApis);
  90. for (RtMidi::Api api : rtApis) {
  91. int driverId = (int) api;
  92. MidiDriver *driver = new RtMidiDriver(driverId);
  93. midiDriverAdd(driverId, driver);
  94. }
  95. }
  96. } // namespace rack