sndio_midiport.cc 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright (c) 2012 Stefan Sperling <stsp@openbsd.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <cstdlib>
  17. #include <poll.h>
  18. #include <pbd/xml++.h>
  19. #include <midi++/sndio_midiport.h>
  20. #include <midi++/types.h>
  21. #include "i18n.h"
  22. using namespace std;
  23. using namespace MIDI;
  24. SndioMidi_MidiPort::SndioMidi_MidiPort(const XMLNode& node) : Port(node)
  25. {
  26. const char *dev;
  27. Descriptor desc(node);
  28. if (strcmp(desc.device.c_str(), "ardour") == 0)
  29. dev = NULL; /* default */
  30. else
  31. dev = desc.device.c_str();
  32. hdl = mio_open(dev, MIO_IN | MIO_OUT, 1);
  33. if (hdl) {
  34. pfd = new struct pollfd[mio_nfds(hdl)];
  35. _ok = true;
  36. }
  37. }
  38. SndioMidi_MidiPort::~SndioMidi_MidiPort()
  39. {
  40. if (hdl) {
  41. mio_close(hdl);
  42. delete[] pfd;
  43. }
  44. }
  45. int SndioMidi_MidiPort::poll(int event) const
  46. {
  47. int n = mio_pollfd(hdl, pfd, event);
  48. if (n == 0)
  49. return -1;
  50. if (::poll(pfd, n, 100) < 0)
  51. return -1;
  52. int revents = mio_revents(hdl, pfd);
  53. if (revents & event) {
  54. for (unsigned int i = 0; i < sizeof(pfd)/sizeof(pfd[0]); i++) {
  55. if (pfd[i].revents & event)
  56. return pfd[i].fd;
  57. }
  58. }
  59. return -1;
  60. }
  61. int SndioMidi_MidiPort::read(byte *buf, size_t max)
  62. {
  63. if (mio_eof(hdl)) {
  64. cerr << "sndio MIDI read error" << endl;
  65. return 0;
  66. }
  67. if (input_parser) {
  68. size_t n = mio_read(hdl, buf, max);
  69. if (n == 0)
  70. return 0;
  71. input_parser->raw_preparse(*input_parser, buf, n);
  72. for (unsigned int i = 0; i < n; i++)
  73. input_parser->scanner(buf[i]);
  74. input_parser->raw_postparse(*input_parser, buf, n);
  75. return (int)n;
  76. }
  77. return 0;
  78. }
  79. int SndioMidi_MidiPort::write(byte *buf, size_t len)
  80. {
  81. if (mio_eof(hdl)) {
  82. cerr << "sndio MIDI write error" << endl;
  83. return 0;
  84. }
  85. return (int)mio_write(hdl, buf, len);
  86. }
  87. int
  88. SndioMidi_MidiPort::selectable() const
  89. {
  90. return poll(POLLIN|POLLOUT);
  91. }
  92. int
  93. SndioMidi_MidiPort::discover(vector<PortSet>& ports)
  94. {
  95. int ret = 0;
  96. /* Try to find usable sndio midi ports.
  97. * Users can add additional ports manually. */
  98. for (int n = 0; n < 8; n++) {
  99. std::string dev_name = "rmidi/" + n;
  100. struct mio_hdl *hdl;
  101. hdl = mio_open(dev_name.c_str(), MIO_IN | MIO_OUT, 1);
  102. if (hdl) {
  103. mio_close(hdl);
  104. XMLNode node(X_("MIDI-port"));
  105. node.add_property("tag", "ardour");
  106. node.add_property("device", dev_name);
  107. node.add_property("type", "sndio");
  108. node.add_property("mode", "duplex");
  109. ports.back().ports.push_back(node);
  110. ret = 1;
  111. }
  112. }
  113. return ret;
  114. }