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.
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
];
38 event_pending
= false;
39 input_buffer_size
= max_packet_data
;
42 this->write_queue
= write_queue
;
43 packet_queue_ptr
.release();
46 JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue()
48 delete[] input_buffer
;
53 JackMidiRawInputWriteQueue::Clear()
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
);
67 JackMidiRawInputWriteQueue::GetAvailableSpace()
69 return packet_queue
->GetAvailableSpace();
73 JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_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
);
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
);
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
);
99 JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte
)
101 jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - "
102 "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte
);
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
);
115 JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time
)
117 bool result
= ! unbuffered_bytes
;
119 HandleBufferFailure(unbuffered_bytes
, total_bytes
);
121 PrepareEvent(time
, total_bytes
, input_buffer
);
124 if (status_byte
>= 0xf0) {
132 JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time
,
133 jack_midi_data_t byte
)
136 PrepareEvent(time
, 1, &event_byte
);
141 JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time
, size_t size
,
142 jack_midi_data_t
*buffer
)
144 event
.buffer
= buffer
;
147 event_pending
= true;
151 JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame
)
154 if (! WriteEvent(boundary_frame
)) {
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
)) {
176 JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time
,
177 jack_midi_data_t byte
)
182 HandleInvalidStatusByte(byte
);
185 return PrepareByteEvent(time
, byte
);
189 if (status_byte
== 0xf0) {
191 return PrepareBufferedEvent(time
);
193 HandleUnexpectedSysexEnd(total_bytes
);
200 // Non-realtime status byte
202 HandleIncompleteMessage(total_bytes
);
206 switch (byte
& 0xf0) {
212 // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
217 // Program Change, Channel Pressure
228 // MTC Quarter Frame, Song Select
238 HandleInvalidStatusByte(byte
);
244 bool result
= PrepareByteEvent(time
, byte
);
257 // Data bytes without a status will be discarded.
263 // Apply running status.
264 RecordByte(status_byte
);
267 return (total_bytes
== expected_bytes
) ? PrepareBufferedEvent(time
) :
272 JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte
)
274 if (total_bytes
< input_buffer_size
) {
275 input_buffer
[total_bytes
] = byte
;
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
291 event_pending
= false;
294 // This is here to stop compilers from warning us about not
295 // handling enumeration values.