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.

486 lines
9.8KB

  1. #include <map>
  2. #include <utility>
  3. #include <queue>
  4. #include <midi.hpp>
  5. #include <string.hpp>
  6. #include <system.hpp>
  7. #include <context.hpp>
  8. #include <engine/Engine.hpp>
  9. namespace rack {
  10. namespace midi {
  11. static std::vector<std::pair<int, Driver*>> drivers;
  12. std::string Message::toString() const {
  13. std::string s;
  14. for (size_t i = 0; i < bytes.size(); i++) {
  15. if (i > 0)
  16. s += " ";
  17. uint8_t b = bytes[i];
  18. // We could use string::f() here, but use faster method instead.
  19. // s += string::f("%02x", b);
  20. uint8_t b1 = (b & 0x0f) >> 0;
  21. uint8_t b2 = (b & 0xf0) >> 4;
  22. s += b2 < 0xa ? ('0' + b2) : ('a' + b2 - 0xa);
  23. s += b1 < 0xa ? ('0' + b1) : ('a' + b1 - 0xa);
  24. }
  25. return s;
  26. }
  27. ////////////////////
  28. // Device
  29. ////////////////////
  30. void InputDevice::subscribe(Input* input) {
  31. subscribed.insert(input);
  32. }
  33. void InputDevice::unsubscribe(Input* input) {
  34. // Remove Input from subscriptions
  35. auto it = subscribed.find(input);
  36. if (it != subscribed.end())
  37. subscribed.erase(it);
  38. }
  39. void InputDevice::onMessage(const Message& message) {
  40. for (Input* input : subscribed) {
  41. // Filter channel if message is not a system MIDI message
  42. if (message.getStatus() != 0xf && input->channel >= 0 && message.getChannel() != input->channel)
  43. continue;
  44. // We're probably in the MIDI driver's thread, so set the Rack context.
  45. contextSet(input->context);
  46. // Set timestamp to now if unset
  47. if (message.getFrame() < 0) {
  48. Message msg = message;
  49. double deltaTime = system::getTime() - APP->engine->getBlockTime();
  50. int64_t deltaFrames = std::floor(deltaTime * APP->engine->getSampleRate());
  51. // Delay message by current Engine block size
  52. deltaFrames += APP->engine->getBlockFrames();
  53. msg.setFrame(APP->engine->getBlockFrame() + deltaFrames);
  54. // Pass message to Input port
  55. input->onMessage(msg);
  56. }
  57. else {
  58. // Pass message to Input port
  59. input->onMessage(message);
  60. }
  61. }
  62. }
  63. void OutputDevice::subscribe(Output* output) {
  64. subscribed.insert(output);
  65. }
  66. void OutputDevice::unsubscribe(Output* output) {
  67. auto it = subscribed.find(output);
  68. if (it != subscribed.end())
  69. subscribed.erase(it);
  70. }
  71. ////////////////////
  72. // Port
  73. ////////////////////
  74. Port::Port() {
  75. context = contextGet();
  76. }
  77. Port::~Port() {
  78. }
  79. Driver* Port::getDriver() {
  80. return driver;
  81. }
  82. int Port::getDriverId() {
  83. return driverId;
  84. }
  85. void Port::setDriverId(int driverId) {
  86. // Unset device and driver
  87. setDeviceId(-1);
  88. driver = NULL;
  89. this->driverId = -1;
  90. // Find driver by ID
  91. driver = midi::getDriver(driverId);
  92. if (driver) {
  93. this->driverId = driverId;
  94. }
  95. else if (!drivers.empty()) {
  96. // Set first driver as default
  97. driver = drivers[0].second;
  98. this->driverId = drivers[0].first;
  99. }
  100. else {
  101. // No fallback drivers
  102. return;
  103. }
  104. // Set default device if exists
  105. int defaultDeviceId = getDefaultDeviceId();
  106. if (defaultDeviceId >= 0)
  107. setDeviceId(defaultDeviceId);
  108. }
  109. Device* Port::getDevice() {
  110. return device;
  111. }
  112. int Port::getDeviceId() {
  113. return deviceId;
  114. }
  115. int Port::getChannel() {
  116. return channel;
  117. }
  118. void Port::setChannel(int channel) {
  119. this->channel = channel;
  120. }
  121. std::string Port::getChannelName(int channel) {
  122. if (channel < 0)
  123. return "All channels";
  124. else
  125. return string::f("Channel %d", channel + 1);
  126. }
  127. json_t* Port::toJson() {
  128. json_t* rootJ = json_object();
  129. json_object_set_new(rootJ, "driver", json_integer(getDriverId()));
  130. if (device) {
  131. std::string deviceName = device->getName();
  132. if (!deviceName.empty())
  133. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  134. }
  135. json_object_set_new(rootJ, "channel", json_integer(getChannel()));
  136. return rootJ;
  137. }
  138. void Port::fromJson(json_t* rootJ) {
  139. setDriverId(-1);
  140. json_t* driverJ = json_object_get(rootJ, "driver");
  141. if (driverJ)
  142. setDriverId(json_integer_value(driverJ));
  143. if (driver) {
  144. json_t* deviceNameJ = json_object_get(rootJ, "deviceName");
  145. if (deviceNameJ) {
  146. std::string deviceName = json_string_value(deviceNameJ);
  147. // Search for device ID with equal name
  148. for (int deviceId : getDeviceIds()) {
  149. if (getDeviceName(deviceId) == deviceName) {
  150. setDeviceId(deviceId);
  151. break;
  152. }
  153. }
  154. }
  155. }
  156. json_t* channelJ = json_object_get(rootJ, "channel");
  157. if (channelJ)
  158. channel = json_integer_value(channelJ);
  159. }
  160. ////////////////////
  161. // Input
  162. ////////////////////
  163. Input::Input() {
  164. reset();
  165. }
  166. Input::~Input() {
  167. setDeviceId(-1);
  168. }
  169. void Input::reset() {
  170. setDriverId(-1);
  171. channel = -1;
  172. }
  173. std::vector<int> Input::getDeviceIds() {
  174. if (!driver)
  175. return {};
  176. try {
  177. return driver->getInputDeviceIds();
  178. }
  179. catch (Exception& e) {
  180. WARN("MIDI port could not get input device IDs: %s", e.what());
  181. return {};
  182. }
  183. }
  184. int Input::getDefaultDeviceId() {
  185. if (!driver)
  186. return -1;
  187. return driver->getDefaultInputDeviceId();
  188. }
  189. void Input::setDeviceId(int deviceId) {
  190. // Destroy device
  191. if (driver && this->deviceId >= 0) {
  192. try {
  193. driver->unsubscribeInput(this->deviceId, this);
  194. }
  195. catch (Exception& e) {
  196. WARN("MIDI port could not unsubscribe from input: %s", e.what());
  197. }
  198. }
  199. device = inputDevice = NULL;
  200. this->deviceId = -1;
  201. // Create device
  202. if (driver && deviceId >= 0) {
  203. try {
  204. device = inputDevice = driver->subscribeInput(deviceId, this);
  205. if (device) {
  206. this->deviceId = deviceId;
  207. }
  208. }
  209. catch (Exception& e) {
  210. WARN("MIDI port could not subscribe to input: %s", e.what());
  211. }
  212. }
  213. }
  214. std::string Input::getDeviceName(int deviceId) {
  215. if (!driver)
  216. return "";
  217. try {
  218. return driver->getInputDeviceName(deviceId);
  219. }
  220. catch (Exception& e) {
  221. WARN("MIDI port could not get input device name: %s", e.what());
  222. return "";
  223. }
  224. }
  225. std::vector<int> Input::getChannels() {
  226. std::vector<int> channels;
  227. for (int c = -1; c < 16; c++) {
  228. channels.push_back(c);
  229. }
  230. return channels;
  231. }
  232. ////////////////////
  233. // InputQueue
  234. ////////////////////
  235. static const size_t InputQueue_maxSize = 8192;
  236. struct InputQueue_Compare {
  237. bool operator()(const Message& a, const Message& b) {
  238. return a.getFrame() > b.getFrame();
  239. }
  240. };
  241. struct InputQueue_Queue : std::priority_queue<Message, std::vector<Message>, InputQueue_Compare> {
  242. void reserve(size_t capacity) {
  243. c.reserve(capacity);
  244. }
  245. void clear() {
  246. // Messing with the protected container is dangerous, but completely clearing it should be fine.
  247. c.clear();
  248. }
  249. };
  250. struct InputQueue::Internal {
  251. InputQueue_Queue queue;
  252. };
  253. InputQueue::InputQueue() {
  254. internal = new Internal;
  255. internal->queue.reserve(InputQueue_maxSize);
  256. }
  257. InputQueue::~InputQueue() {
  258. delete internal;
  259. }
  260. void InputQueue::onMessage(const Message& message) {
  261. if (internal->queue.size() >= InputQueue_maxSize)
  262. return;
  263. // Push to queue
  264. internal->queue.push(message);
  265. }
  266. bool InputQueue::tryPop(Message* messageOut, int64_t maxFrame) {
  267. if (!internal->queue.empty()) {
  268. const Message& msg = internal->queue.top();
  269. if (msg.getFrame() <= maxFrame) {
  270. *messageOut = msg;
  271. internal->queue.pop();
  272. return true;
  273. }
  274. // If next MIDI message is too far in the future, clear the queue.
  275. // This solves the issue of unconsumed messages getting stuck in the future when a DAW rewinds the engine frame.
  276. int futureFrames = 2 * APP->engine->getBlockFrames();
  277. if (msg.getFrame() - maxFrame > futureFrames) {
  278. internal->queue.clear();
  279. }
  280. }
  281. return false;
  282. }
  283. size_t InputQueue::size() {
  284. return internal->queue.size();
  285. }
  286. ////////////////////
  287. // Output
  288. ////////////////////
  289. Output::Output() {
  290. reset();
  291. }
  292. Output::~Output() {
  293. setDeviceId(-1);
  294. }
  295. void Output::reset() {
  296. setDriverId(-1);
  297. channel = 0;
  298. }
  299. std::vector<int> Output::getDeviceIds() {
  300. if (!driver)
  301. return {};
  302. try {
  303. return driver->getOutputDeviceIds();
  304. }
  305. catch (Exception& e) {
  306. WARN("MIDI port could not get output device IDs: %s", e.what());
  307. return {};
  308. }
  309. }
  310. void Output::setDeviceId(int deviceId) {
  311. // Destroy device
  312. if (driver && this->deviceId >= 0) {
  313. try {
  314. driver->unsubscribeOutput(this->deviceId, this);
  315. }
  316. catch (Exception& e) {
  317. WARN("MIDI port could not unsubscribe from output: %s", e.what());
  318. }
  319. }
  320. device = outputDevice = NULL;
  321. this->deviceId = -1;
  322. // Create device
  323. if (driver && deviceId >= 0) {
  324. try {
  325. device = outputDevice = driver->subscribeOutput(deviceId, this);
  326. if (device) {
  327. this->deviceId = deviceId;
  328. }
  329. }
  330. catch (Exception& e) {
  331. WARN("MIDI port could not subscribe to output: %s", e.what());
  332. }
  333. }
  334. }
  335. int Output::getDefaultDeviceId() {
  336. if (!driver)
  337. return -1;
  338. return driver->getDefaultOutputDeviceId();
  339. }
  340. std::string Output::getDeviceName(int deviceId) {
  341. if (!driver)
  342. return "";
  343. try {
  344. return driver->getOutputDeviceName(deviceId);
  345. }
  346. catch (Exception& e) {
  347. WARN("MIDI port could not get output device name: %s", e.what());
  348. return "";
  349. }
  350. }
  351. std::vector<int> Output::getChannels() {
  352. std::vector<int> channels;
  353. for (int c = 0; c < 16; c++) {
  354. channels.push_back(c);
  355. }
  356. return channels;
  357. }
  358. void Output::sendMessage(const Message& message) {
  359. if (!outputDevice)
  360. return;
  361. // Set channel if message is not a system MIDI message
  362. Message msg = message;
  363. if (msg.getStatus() != 0xf && channel >= 0) {
  364. msg.setChannel(channel);
  365. }
  366. // DEBUG("sendMessage %02x %02x %02x", msg.cmd, msg.data1, msg.data2);
  367. try {
  368. outputDevice->sendMessage(msg);
  369. }
  370. catch (Exception& e) {
  371. // Don't log error because it could flood the log.
  372. // WARN("MIDI port could not be sent MIDI message: %s", e.what());
  373. // TODO Perhaps `setDevice(-1)` if sending message fails?
  374. }
  375. }
  376. ////////////////////
  377. // midi
  378. ////////////////////
  379. void init() {
  380. }
  381. void destroy() {
  382. for (auto& pair : drivers) {
  383. delete pair.second;
  384. }
  385. drivers.clear();
  386. }
  387. void addDriver(int driverId, Driver* driver) {
  388. assert(driver);
  389. drivers.push_back(std::make_pair(driverId, driver));
  390. }
  391. std::vector<int> getDriverIds() {
  392. std::vector<int> driverIds;
  393. for (auto& pair : drivers) {
  394. driverIds.push_back(pair.first);
  395. }
  396. return driverIds;
  397. }
  398. Driver* getDriver(int driverId) {
  399. // Search for driver by ID
  400. for (auto& pair : drivers) {
  401. if (pair.first == driverId)
  402. return pair.second;
  403. }
  404. return NULL;
  405. }
  406. } // namespace midi
  407. } // namespace rack