Jack2  1.9.13
JackALSARawMidiOutputPort.cpp
1 /*
2 Copyright (C) 2011 Devin Anderson
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <cassert>
21 #include <memory>
22 
23 #include "JackALSARawMidiOutputPort.h"
24 #include "JackError.h"
25 
27 
28 JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(const char* client_name,
29  snd_rawmidi_info_t *info,
30  size_t index,
31  size_t max_bytes_per_poll,
32  size_t max_bytes,
33  size_t max_messages):
34  JackALSARawMidiPort(client_name, info, index, POLLOUT)
35 {
36  alsa_event = 0;
37  read_queue = new JackMidiBufferReadQueue();
38  std::unique_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
39  send_queue = new JackALSARawMidiSendQueue(rawmidi, max_bytes_per_poll);
40  std::unique_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
41  thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
42  std::unique_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
43  raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
44  max_messages, max_messages);
45  thread_ptr.release();
46  send_ptr.release();
47  read_ptr.release();
48 }
49 
50 JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
51 {
52  delete raw_queue;
53  delete read_queue;
54  delete send_queue;
55  delete thread_queue;
56 }
57 
58 bool
59 JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
60  jack_nframes_t frames)
61 {
62  read_queue->ResetMidiBuffer(port_buffer);
63  bool enqueued = false;
64  for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
65  event = read_queue->DequeueEvent()) {
66  switch (thread_queue->EnqueueEvent(event, frames)) {
67  case JackMidiWriteQueue::BUFFER_FULL:
68  jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
69  "queue doesn't have enough room to enqueue a %d-byte "
70  "event. Dropping event.", event->size);
71  continue;
72  case JackMidiWriteQueue::BUFFER_TOO_SMALL:
73  jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
74  "queue is too small to enqueue a %d-byte event. "
75  "Dropping event.", event->size);
76  continue;
77  default:
78  enqueued = true;
79  }
80  }
81  return enqueued ? TriggerQueueEvent() : true;
82 }
83 
84 bool
85 JackALSARawMidiOutputPort::ProcessPollEvents(bool handle_output, bool timeout,
86  jack_nframes_t *frame)
87 {
88  int io_event;
89  int queue_event;
90  send_queue->ResetPollByteCount();
91  if (! handle_output) {
92  assert(timeout);
93  goto process_raw_queue;
94  }
95  io_event = GetIOPollEvent();
96  if (io_event == -1) {
97  return false;
98  }
99  queue_event = GetQueuePollEvent();
100  if (queue_event == -1) {
101  return false;
102  }
103  if (io_event || timeout) {
104  process_raw_queue:
105  // We call the 'Process' event early because there are events waiting
106  // to be processed that either need to be sent now, or before now.
107  raw_queue->Process();
108  } else if (! queue_event) {
109  return true;
110  }
111  if (! alsa_event) {
112  alsa_event = thread_queue->DequeueEvent();
113  }
114  for (; alsa_event; alsa_event = thread_queue->DequeueEvent()) {
115  switch (raw_queue->EnqueueEvent(alsa_event)) {
116  case JackMidiWriteQueue::BUFFER_TOO_SMALL:
117  jack_error("JackALSARawMidiOutputPort::ProcessQueues - The raw "
118  "output queue couldn't enqueue a %d-byte event. "
119  "Dropping event.", alsa_event->size);
120  // Fallthrough on purpose.
121  case JackMidiWriteQueue::OK:
122  continue;
123  default:
124  ;
125  }
126 
127  // Try to free up some space by processing events early.
128  *frame = raw_queue->Process();
129 
130  switch (raw_queue->EnqueueEvent(alsa_event)) {
131  case JackMidiWriteQueue::BUFFER_FULL:
132  goto set_io_events;
133  case JackMidiWriteQueue::BUFFER_TOO_SMALL:
134  // This shouldn't happen.
135  assert(false);
136  default:
137  ;
138  }
139  }
140  *frame = raw_queue->Process();
141  set_io_events:
142  bool blocked = send_queue->IsBlocked();
143  SetIOEventsEnabled(blocked);
144  if (blocked) {
145  *frame = 0;
146  }
147  return true;
148 }
void ResetMidiBuffer(JackMidiBuffer *buffer)
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)
jack_nframes_t Process(jack_nframes_t boundary_frame=0)
virtual jack_midi_event_t * DequeueEvent()
virtual EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer)