Correct netjack2 components help.
[jack2.git] / common / JackMidiRawInputWriteQueue.cpp
blob5c76f8b4b372b3d77037cf16de4a6a511ba3f662
1 /*
2 Copyright (C) 2010 Devin Anderson
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <cassert>
21 #include <memory>
22 #include <new>
24 #include "JackMidiRawInputWriteQueue.h"
25 #include "JackError.h"
27 using Jack::JackMidiRawInputWriteQueue;
29 JackMidiRawInputWriteQueue::
30 JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue,
31 size_t max_packet_data, size_t max_packets)
33 packet_queue = new JackMidiAsyncQueue(max_packet_data, max_packets);
34 std::auto_ptr<JackMidiAsyncQueue> packet_queue_ptr(packet_queue);
35 input_buffer = new jack_midi_data_t[max_packet_data];
36 Clear();
37 expected_bytes = 0;
38 event_pending = false;
39 input_buffer_size = max_packet_data;
40 packet = 0;
41 status_byte = 0;
42 this->write_queue = write_queue;
43 packet_queue_ptr.release();
46 JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue()
48 delete[] input_buffer;
49 delete packet_queue;
52 void
53 JackMidiRawInputWriteQueue::Clear()
55 total_bytes = 0;
56 unbuffered_bytes = 0;
59 Jack::JackMidiWriteQueue::EnqueueResult
60 JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
61 jack_midi_data_t *buffer)
63 return packet_queue->EnqueueEvent(time, size, buffer);
66 size_t
67 JackMidiRawInputWriteQueue::GetAvailableSpace()
69 return packet_queue->GetAvailableSpace();
72 void
73 JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
74 size_t total_bytes)
76 jack_error("JackMidiRawInputWriteQueue::HandleBufferFailure - %d MIDI "
77 "byte(s) of a %d byte message could not be buffered. The "
78 "message has been dropped.", unbuffered_bytes, total_bytes);
81 void
82 JackMidiRawInputWriteQueue::HandleEventLoss(jack_midi_event_t *event)
84 jack_error("JackMidiRawInputWriteQueue::HandleEventLoss - A %d byte MIDI "
85 "event scheduled for frame '%d' could not be processed because "
86 "the write queue cannot accomodate an event of that size. The "
87 "event has been discarded.", event->size, event->time);
90 void
91 JackMidiRawInputWriteQueue::HandleIncompleteMessage(size_t total_bytes)
93 jack_error("JackMidiRawInputWriteQueue::HandleIncompleteMessage - "
94 "Discarding %d MIDI byte(s) of an incomplete message. The "
95 "MIDI cable may have been unplugged.", total_bytes);
98 void
99 JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte)
101 jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - "
102 "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte);
105 void
106 JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd(size_t total_bytes)
108 jack_error("JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd - "
109 "Received a sysex end byte without first receiving a sysex "
110 "start byte. Discarding %d MIDI byte(s). The cable may have "
111 "been unplugged.", total_bytes);
114 bool
115 JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time)
117 bool result = ! unbuffered_bytes;
118 if (! result) {
119 HandleBufferFailure(unbuffered_bytes, total_bytes);
120 } else {
121 PrepareEvent(time, total_bytes, input_buffer);
123 Clear();
124 if (status_byte >= 0xf0) {
125 expected_bytes = 0;
126 status_byte = 0;
128 return result;
131 bool
132 JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time,
133 jack_midi_data_t byte)
135 event_byte = byte;
136 PrepareEvent(time, 1, &event_byte);
137 return true;
140 void
141 JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time, size_t size,
142 jack_midi_data_t *buffer)
144 event.buffer = buffer;
145 event.size = size;
146 event.time = time;
147 event_pending = true;
150 jack_nframes_t
151 JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame)
153 if (event_pending) {
154 if (! WriteEvent(boundary_frame)) {
155 return event.time;
158 if (! packet) {
159 packet = packet_queue->DequeueEvent();
161 for (; packet; packet = packet_queue->DequeueEvent()) {
162 for (; packet->size; (packet->buffer)++, (packet->size)--) {
163 if (ProcessByte(packet->time, *(packet->buffer))) {
164 if (! WriteEvent(boundary_frame)) {
165 (packet->buffer)++;
166 (packet->size)--;
167 return event.time;
172 return 0;
175 bool
176 JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time,
177 jack_midi_data_t byte)
179 if (byte >= 0xf8) {
180 // Realtime
181 if (byte == 0xfd) {
182 HandleInvalidStatusByte(byte);
183 return false;
185 return PrepareByteEvent(time, byte);
187 if (byte == 0xf7) {
188 // Sysex end
189 if (status_byte == 0xf0) {
190 RecordByte(byte);
191 return PrepareBufferedEvent(time);
193 HandleUnexpectedSysexEnd(total_bytes);
194 Clear();
195 expected_bytes = 0;
196 status_byte = 0;
197 return false;
199 if (byte >= 0x80) {
200 // Non-realtime status byte
201 if (total_bytes) {
202 HandleIncompleteMessage(total_bytes);
203 Clear();
205 status_byte = byte;
206 switch (byte & 0xf0) {
207 case 0x80:
208 case 0x90:
209 case 0xa0:
210 case 0xb0:
211 case 0xe0:
212 // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
213 expected_bytes = 3;
214 break;
215 case 0xc0:
216 case 0xd0:
217 // Program Change, Channel Pressure
218 expected_bytes = 2;
219 break;
220 case 0xf0:
221 switch (byte) {
222 case 0xf0:
223 // Sysex
224 expected_bytes = 0;
225 break;
226 case 0xf1:
227 case 0xf3:
228 // MTC Quarter Frame, Song Select
229 expected_bytes = 2;
230 break;
231 case 0xf2:
232 // Song Position
233 expected_bytes = 3;
234 break;
235 case 0xf4:
236 case 0xf5:
237 // Undefined
238 HandleInvalidStatusByte(byte);
239 expected_bytes = 0;
240 status_byte = 0;
241 return false;
242 case 0xf6:
243 // Tune Request
244 bool result = PrepareByteEvent(time, byte);
245 if (result) {
246 expected_bytes = 0;
247 status_byte = 0;
249 return result;
252 RecordByte(byte);
253 return false;
255 // Data byte
256 if (! status_byte) {
257 // Data bytes without a status will be discarded.
258 total_bytes++;
259 unbuffered_bytes++;
260 return false;
262 if (! total_bytes) {
263 // Apply running status.
264 RecordByte(status_byte);
266 RecordByte(byte);
267 return (total_bytes == expected_bytes) ? PrepareBufferedEvent(time) :
268 false;
271 void
272 JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte)
274 if (total_bytes < input_buffer_size) {
275 input_buffer[total_bytes] = byte;
276 } else {
277 unbuffered_bytes++;
279 total_bytes++;
282 bool
283 JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame)
285 if ((! boundary_frame) || (event.time < boundary_frame)) {
286 switch (write_queue->EnqueueEvent(&event)) {
287 case BUFFER_TOO_SMALL:
288 HandleEventLoss(&event);
289 // Fallthrough on purpose
290 case OK:
291 event_pending = false;
292 return true;
293 default:
294 // This is here to stop compilers from warning us about not
295 // handling enumeration values.
299 return false;