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