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