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.

121 lines
3.0KB

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