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.

131 lines
2.4KB

  1. #include <gamepad.hpp>
  2. #include <midi.hpp>
  3. #include <string.hpp>
  4. #include <window.hpp>
  5. namespace rack {
  6. namespace gamepad {
  7. struct Driver;
  8. static const int DRIVER = -10;
  9. static Driver* driver = NULL;
  10. struct InputDevice : midi::InputDevice {
  11. int deviceId;
  12. int8_t ccs[128] = {};
  13. void step() {
  14. if (!glfwJoystickPresent(deviceId))
  15. return;
  16. // Get gamepad state
  17. int numAxes;
  18. const float* axes = glfwGetJoystickAxes(deviceId, &numAxes);
  19. int numButtons;
  20. const unsigned char* buttons = glfwGetJoystickButtons(deviceId, &numButtons);
  21. // Convert axes and buttons to MIDI CC
  22. int numCcs = std::min(numAxes + numButtons, 128);
  23. for (int i = 0; i < numCcs; i++) {
  24. // Allow CC value to go negative, but clamp at -127 instead of -128 for symmetry
  25. int8_t cc;
  26. if (i < numAxes) {
  27. // Axis
  28. cc = math::clamp((int) std::round(axes[i] * 127), -127, 127);
  29. }
  30. else {
  31. // Button
  32. cc = buttons[i - numAxes] ? 127 : 0;
  33. }
  34. if (cc == ccs[i])
  35. continue;
  36. ccs[i] = cc;
  37. // Send MIDI message
  38. midi::Message msg;
  39. msg.setStatus(0xb);
  40. msg.setNote(i);
  41. // Allow 8th bit to be set
  42. msg.bytes[2] = cc;
  43. onMessage(msg);
  44. }
  45. }
  46. };
  47. struct Driver : midi::Driver {
  48. InputDevice devices[16];
  49. Driver() {
  50. for (int i = 0; i < 16; i++) {
  51. devices[i].deviceId = i;
  52. }
  53. }
  54. std::string getName() override {
  55. return "Gamepad";
  56. }
  57. std::vector<int> getInputDeviceIds() override {
  58. std::vector<int> deviceIds;
  59. for (int i = 0; i < 16; i++) {
  60. if (glfwJoystickPresent(i)) {
  61. deviceIds.push_back(i);
  62. }
  63. }
  64. return deviceIds;
  65. }
  66. std::string getInputDeviceName(int deviceId) override {
  67. if (!(0 <= deviceId && deviceId < 16))
  68. return "";
  69. const char* name = glfwGetJoystickName(deviceId);
  70. if (name) {
  71. return name;
  72. }
  73. return string::f(" %d (unavailable)", deviceId + 1);
  74. }
  75. midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override {
  76. if (!(0 <= deviceId && deviceId < 16))
  77. return NULL;
  78. devices[deviceId].subscribe(input);
  79. return &devices[deviceId];
  80. }
  81. void unsubscribeInput(int deviceId, midi::Input* input) override {
  82. if (!(0 <= deviceId && deviceId < 16))
  83. return;
  84. devices[deviceId].unsubscribe(input);
  85. }
  86. };
  87. void init() {
  88. driver = new Driver;
  89. midi::addDriver(DRIVER, driver);
  90. }
  91. void step() {
  92. if (!driver)
  93. return;
  94. for (int i = 0; i < 16; i++) {
  95. if (glfwJoystickPresent(i)) {
  96. driver->devices[i].step();
  97. }
  98. }
  99. }
  100. } // namespace gamepad
  101. } // namespace rack