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.

148 lines
5.0KB

  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 <cassert>
  16. #include <memory>
  17. #include "JackALSARawMidiOutputPort.h"
  18. #include "JackError.h"
  19. using Jack::JackALSARawMidiOutputPort;
  20. JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
  21. size_t index,
  22. size_t max_bytes_per_poll,
  23. size_t max_bytes,
  24. size_t max_messages):
  25. JackALSARawMidiPort(info, index, POLLOUT)
  26. {
  27. alsa_event = 0;
  28. read_queue = new JackMidiBufferReadQueue();
  29. std::unique_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
  30. send_queue = new JackALSARawMidiSendQueue(rawmidi, max_bytes_per_poll);
  31. std::unique_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
  32. thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
  33. std::unique_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
  34. raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
  35. max_messages, max_messages);
  36. thread_ptr.release();
  37. send_ptr.release();
  38. read_ptr.release();
  39. }
  40. JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
  41. {
  42. delete raw_queue;
  43. delete read_queue;
  44. delete send_queue;
  45. delete thread_queue;
  46. }
  47. bool
  48. JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
  49. jack_nframes_t frames)
  50. {
  51. read_queue->ResetMidiBuffer(port_buffer);
  52. bool enqueued = false;
  53. for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
  54. event = read_queue->DequeueEvent()) {
  55. switch (thread_queue->EnqueueEvent(event, frames)) {
  56. case JackMidiWriteQueue::BUFFER_FULL:
  57. jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
  58. "queue doesn't have enough room to enqueue a %d-byte "
  59. "event. Dropping event.", event->size);
  60. continue;
  61. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  62. jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
  63. "queue is too small to enqueue a %d-byte event. "
  64. "Dropping event.", event->size);
  65. continue;
  66. default:
  67. enqueued = true;
  68. }
  69. }
  70. return enqueued ? TriggerQueueEvent() : true;
  71. }
  72. bool
  73. JackALSARawMidiOutputPort::ProcessPollEvents(bool handle_output, bool timeout,
  74. jack_nframes_t *frame)
  75. {
  76. int io_event;
  77. int queue_event;
  78. send_queue->ResetPollByteCount();
  79. if (! handle_output) {
  80. assert(timeout);
  81. goto process_raw_queue;
  82. }
  83. io_event = GetIOPollEvent();
  84. if (io_event == -1) {
  85. return false;
  86. }
  87. queue_event = GetQueuePollEvent();
  88. if (queue_event == -1) {
  89. return false;
  90. }
  91. if (io_event || timeout) {
  92. process_raw_queue:
  93. // We call the 'Process' event early because there are events waiting
  94. // to be processed that either need to be sent now, or before now.
  95. raw_queue->Process();
  96. } else if (! queue_event) {
  97. return true;
  98. }
  99. if (! alsa_event) {
  100. alsa_event = thread_queue->DequeueEvent();
  101. }
  102. for (; alsa_event; alsa_event = thread_queue->DequeueEvent()) {
  103. switch (raw_queue->EnqueueEvent(alsa_event)) {
  104. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  105. jack_error("JackALSARawMidiOutputPort::ProcessQueues - The raw "
  106. "output queue couldn't enqueue a %d-byte event. "
  107. "Dropping event.", alsa_event->size);
  108. // Fallthrough on purpose.
  109. case JackMidiWriteQueue::OK:
  110. continue;
  111. default:
  112. ;
  113. }
  114. // Try to free up some space by processing events early.
  115. *frame = raw_queue->Process();
  116. switch (raw_queue->EnqueueEvent(alsa_event)) {
  117. case JackMidiWriteQueue::BUFFER_FULL:
  118. goto set_io_events;
  119. case JackMidiWriteQueue::BUFFER_TOO_SMALL:
  120. // This shouldn't happen.
  121. assert(false);
  122. default:
  123. ;
  124. }
  125. }
  126. *frame = raw_queue->Process();
  127. set_io_events:
  128. bool blocked = send_queue->IsBlocked();
  129. SetIOEventsEnabled(blocked);
  130. if (blocked) {
  131. *frame = 0;
  132. }
  133. return true;
  134. }