jack2 codebase
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.

192 lines
5.5KB

  1. /*
  2. Copyright (C) 2011 Devin Anderson
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <stdexcept>
  16. #include <string>
  17. #include "JackALSARawMidiPort.h"
  18. #include "JackError.h"
  19. using Jack::JackALSARawMidiPort;
  20. JackALSARawMidiPort::JackALSARawMidiPort(snd_rawmidi_info_t *info,
  21. size_t index)
  22. {
  23. int card = snd_rawmidi_info_get_card(info);
  24. unsigned int device = snd_rawmidi_info_get_device(info);
  25. unsigned int subdevice = snd_rawmidi_info_get_subdevice(info);
  26. char device_id[32];
  27. snprintf(device_id, sizeof(device_id), "hw:%d,%d,%d", card, device,
  28. subdevice);
  29. const char *alias_prefix;
  30. const char *error_message;
  31. snd_rawmidi_t **in;
  32. snd_rawmidi_t **out;
  33. const char *name_suffix;
  34. if (snd_rawmidi_info_get_stream(info) == SND_RAWMIDI_STREAM_OUTPUT) {
  35. alias_prefix = "system:midi_playback_";
  36. in = 0;
  37. name_suffix = "out";
  38. out = &rawmidi;
  39. } else {
  40. alias_prefix = "system:midi_capture_";
  41. in = &rawmidi;
  42. name_suffix = "in";
  43. out = 0;
  44. }
  45. const char *device_name;
  46. const char *func;
  47. int code = snd_rawmidi_open(in, out, device_id, SND_RAWMIDI_NONBLOCK);
  48. if (code) {
  49. error_message = snd_strerror(code);
  50. func = "snd_rawmidi_open";
  51. goto handle_error;
  52. }
  53. snd_rawmidi_params_t *params;
  54. code = snd_rawmidi_params_malloc(&params);
  55. if (code) {
  56. error_message = snd_strerror(code);
  57. func = "snd_rawmidi_params_malloc";
  58. goto close;
  59. }
  60. code = snd_rawmidi_params_current(rawmidi, params);
  61. if (code) {
  62. error_message = snd_strerror(code);
  63. func = "snd_rawmidi_params_current";
  64. goto free_params;
  65. }
  66. code = snd_rawmidi_params_set_avail_min(rawmidi, params, 1);
  67. if (code) {
  68. error_message = snd_strerror(code);
  69. func = "snd_rawmidi_params_set_avail_min";
  70. goto free_params;
  71. }
  72. // Smallest valid buffer size.
  73. code = snd_rawmidi_params_set_buffer_size(rawmidi, params, 32);
  74. if (code) {
  75. error_message = snd_strerror(code);
  76. func = "snd_rawmidi_params_set_buffer_size";
  77. goto free_params;
  78. }
  79. code = snd_rawmidi_params_set_no_active_sensing(rawmidi, params, 1);
  80. if (code) {
  81. error_message = snd_strerror(code);
  82. func = "snd_rawmidi_params_set_no_active_sensing";
  83. goto free_params;
  84. }
  85. code = snd_rawmidi_params(rawmidi, params);
  86. if (code) {
  87. error_message = snd_strerror(code);
  88. func = "snd_rawmidi_params";
  89. goto free_params;
  90. }
  91. snd_rawmidi_params_free(params);
  92. num_fds = snd_rawmidi_poll_descriptors_count(rawmidi);
  93. if (! num_fds) {
  94. error_message = "returned '0' count for poll descriptors";
  95. func = "snd_rawmidi_poll_descriptors_count";
  96. goto close;
  97. }
  98. snprintf(alias, sizeof(alias), "%s%d", alias_prefix, index + 1);
  99. snprintf(name, sizeof(name), "system:%d-%d %s %d %s", card + 1, device + 1,
  100. snd_rawmidi_info_get_name(info), subdevice + 1, name_suffix);
  101. return;
  102. free_params:
  103. snd_rawmidi_params_free(params);
  104. close:
  105. snd_rawmidi_close(rawmidi);
  106. handle_error:
  107. throw std::runtime_error(std::string(func) + ": " + error_message);
  108. }
  109. JackALSARawMidiPort::~JackALSARawMidiPort()
  110. {
  111. if (rawmidi) {
  112. int code = snd_rawmidi_close(rawmidi);
  113. if (code) {
  114. jack_error("JackALSARawMidiPort::~JackALSARawMidiPort - "
  115. "snd_rawmidi_close: %s", snd_strerror(code));
  116. }
  117. rawmidi = 0;
  118. }
  119. }
  120. const char *
  121. JackALSARawMidiPort::GetAlias()
  122. {
  123. return alias;
  124. }
  125. const char *
  126. JackALSARawMidiPort::GetName()
  127. {
  128. return name;
  129. }
  130. int
  131. JackALSARawMidiPort::GetPollDescriptorCount()
  132. {
  133. return num_fds;
  134. }
  135. bool
  136. JackALSARawMidiPort::PopulatePollDescriptors(struct pollfd *poll_fd)
  137. {
  138. bool result = snd_rawmidi_poll_descriptors(rawmidi, poll_fd, num_fds) ==
  139. num_fds;
  140. if (result) {
  141. poll_fds = poll_fd;
  142. }
  143. return result;
  144. }
  145. bool
  146. JackALSARawMidiPort::ProcessPollEvents(unsigned short *revents)
  147. {
  148. int code = snd_rawmidi_poll_descriptors_revents(rawmidi, poll_fds, num_fds,
  149. revents);
  150. if (code) {
  151. jack_error("JackALSARawMidiPort::ProcessPollEvents - "
  152. "snd_rawmidi_poll_descriptors_revents: %s",
  153. snd_strerror(code));
  154. return false;
  155. }
  156. if ((*revents) & POLLNVAL) {
  157. jack_error("JackALSARawMidiPort::ProcessPollEvents - the file "
  158. "descriptor is invalid.");
  159. return false;
  160. }
  161. if ((*revents) & POLLERR) {
  162. jack_error("JackALSARawMidiPort::ProcessPollEvents - an error has "
  163. "occurred on the device or stream.");
  164. return false;
  165. }
  166. return true;
  167. }
  168. void
  169. JackALSARawMidiPort::SetPollEventMask(unsigned short events)
  170. {
  171. for (int i = 0; i < num_fds; i++) {
  172. (poll_fds + i)->events = events;
  173. }
  174. }