2 Copyright (C) 2009 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 "JackError.h"
25 #include "JackPhysicalMidiInput.h"
29 JackPhysicalMidiInput::JackPhysicalMidiInput(size_t buffer_size
)
31 size_t datum_size
= sizeof(jack_midi_data_t
);
32 assert(buffer_size
> 0);
33 input_ring
= jack_ringbuffer_create((buffer_size
+ 1) * datum_size
);
35 throw std::bad_alloc();
37 jack_ringbuffer_mlock(input_ring
);
39 expected_data_bytes
= 0;
43 JackPhysicalMidiInput::~JackPhysicalMidiInput()
45 jack_ringbuffer_free(input_ring
);
49 JackPhysicalMidiInput::Clear()
51 jack_ringbuffer_reset(input_ring
);
57 JackPhysicalMidiInput::HandleBufferFailure(size_t unbuffered_bytes
,
60 jack_error("%d MIDI byte(s) of a %d byte message could not be buffered - "
61 "message dropped", unbuffered_bytes
, total_bytes
);
65 JackPhysicalMidiInput::HandleIncompleteMessage(size_t bytes
)
67 jack_error("Discarding %d MIDI byte(s) - incomplete message (cable "
68 "unplugged?)", bytes
);
72 JackPhysicalMidiInput::HandleInvalidStatusByte(jack_midi_data_t status
)
74 jack_error("Dropping invalid MIDI status byte '%x'",
75 (unsigned int) status
);
79 JackPhysicalMidiInput::HandleUnexpectedSysexEnd(size_t bytes
)
81 jack_error("Discarding %d MIDI byte(s) - received sysex end without sysex "
82 "start (cable unplugged?)", bytes
);
86 JackPhysicalMidiInput::HandleWriteFailure(size_t bytes
)
88 jack_error("Failed to write a %d byte MIDI message to the port buffer",
93 JackPhysicalMidiInput::Process(jack_nframes_t frames
)
96 port_buffer
->Reset(frames
);
97 jack_nframes_t current_frame
= 0;
98 size_t datum_size
= sizeof(jack_midi_data_t
);
100 jack_midi_data_t datum
;
101 current_frame
= Receive(&datum
, current_frame
, frames
);
102 if (current_frame
>= frames
) {
106 jack_log("JackPhysicalMidiInput::Process (%d) - Received '%x' byte",
107 current_frame
, (unsigned int) datum
);
112 HandleInvalidStatusByte(datum
);
115 jack_log("JackPhysicalMidiInput::Process - Writing realtime "
118 WriteByteEvent(current_frame
, datum
);
124 if (status_byte
!= 0xf0) {
125 HandleUnexpectedSysexEnd(buffered_bytes
+ unbuffered_bytes
);
127 expected_data_bytes
= 0;
131 jack_log("JackPhysicalMidiInput::Process - Writing sysex "
134 WriteBufferedSysexEvent(current_frame
);
140 // We're handling a non-realtime status byte
142 jack_log("JackPhysicalMidiInput::Process - Handling non-realtime "
145 if (buffered_bytes
|| unbuffered_bytes
) {
146 HandleIncompleteMessage(buffered_bytes
+ unbuffered_bytes
+ 1);
150 switch (datum
& 0xf0) {
156 // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
157 expected_data_bytes
= 2;
161 // Program Change, Channel Pressure
162 expected_data_bytes
= 1;
168 expected_data_bytes
= 0;
172 // MTC Quarter frame, Song Select
173 expected_data_bytes
= 1;
177 expected_data_bytes
= 2;
182 HandleInvalidStatusByte(datum
);
183 expected_data_bytes
= 0;
188 WriteByteEvent(current_frame
, datum
);
189 expected_data_bytes
= 0;
197 // We're handling a data byte
199 jack_log("JackPhysicalMidiInput::Process - Buffering data byte.");
201 if (jack_ringbuffer_write(input_ring
, (const char *) &datum
,
202 datum_size
) == datum_size
) {
207 unsigned long total_bytes
= buffered_bytes
+ unbuffered_bytes
;
208 assert((! expected_data_bytes
) ||
209 (total_bytes
<= expected_data_bytes
));
210 if (total_bytes
== expected_data_bytes
) {
211 if (! unbuffered_bytes
) {
213 jack_log("JackPhysicalMidiInput::Process - Writing buffered "
216 WriteBufferedEvent(current_frame
);
218 HandleBufferFailure(unbuffered_bytes
, total_bytes
);
221 if (status_byte
>= 0xf0) {
222 expected_data_bytes
= 0;
230 JackPhysicalMidiInput::WriteBufferedEvent(jack_nframes_t frame
)
232 assert(port_buffer
&& port_buffer
->IsValid());
233 size_t space
= jack_ringbuffer_read_space(input_ring
);
234 jack_midi_data_t
*event
= port_buffer
->ReserveEvent(frame
, space
+ 1);
236 jack_ringbuffer_data_t vector
[2];
237 jack_ringbuffer_get_read_vector(input_ring
, vector
);
238 event
[0] = status_byte
;
239 size_t data_length_1
= vector
[0].len
;
240 memcpy(event
+ 1, vector
[0].buf
, data_length_1
);
241 size_t data_length_2
= vector
[1].len
;
243 memcpy(event
+ data_length_1
+ 1, vector
[1].buf
, data_length_2
);
246 HandleWriteFailure(space
+ 1);
252 JackPhysicalMidiInput::WriteBufferedSysexEvent(jack_nframes_t frame
)
254 assert(port_buffer
&& port_buffer
->IsValid());
255 size_t space
= jack_ringbuffer_read_space(input_ring
);
256 jack_midi_data_t
*event
= port_buffer
->ReserveEvent(frame
, space
+ 2);
258 jack_ringbuffer_data_t vector
[2];
259 jack_ringbuffer_get_read_vector(input_ring
, vector
);
260 event
[0] = status_byte
;
261 size_t data_length_1
= vector
[0].len
;
262 memcpy(event
+ 1, vector
[0].buf
, data_length_1
);
263 size_t data_length_2
= vector
[1].len
;
265 memcpy(event
+ data_length_1
+ 1, vector
[1].buf
, data_length_2
);
267 event
[data_length_1
+ data_length_2
+ 1] = 0xf7;
269 HandleWriteFailure(space
+ 2);
275 JackPhysicalMidiInput::WriteByteEvent(jack_nframes_t frame
,
276 jack_midi_data_t datum
)
278 assert(port_buffer
&& port_buffer
->IsValid());
279 jack_midi_data_t
*event
= port_buffer
->ReserveEvent(frame
, 1);
283 HandleWriteFailure(1);