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.

120 lines
3.0KB

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