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.

149 lines
5.1KB

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