Init engine fields, cleanup.
[jack2.git] / common / JackPhysicalMidiInput.cpp
blob311dad0b39862c1a2a3385ccf2032fc4571aab91
1 /*
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.
20 #include <cassert>
21 #include <cstring>
22 #include <new>
24 #include "JackError.h"
25 #include "JackPhysicalMidiInput.h"
27 namespace Jack {
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);
34 if (! input_ring) {
35 throw std::bad_alloc();
37 jack_ringbuffer_mlock(input_ring);
38 Clear();
39 expected_data_bytes = 0;
40 status_byte = 0;
43 JackPhysicalMidiInput::~JackPhysicalMidiInput()
45 jack_ringbuffer_free(input_ring);
48 void
49 JackPhysicalMidiInput::Clear()
51 jack_ringbuffer_reset(input_ring);
52 buffered_bytes = 0;
53 unbuffered_bytes = 0;
56 void
57 JackPhysicalMidiInput::HandleBufferFailure(size_t unbuffered_bytes,
58 size_t total_bytes)
60 jack_error("%d MIDI byte(s) of a %d byte message could not be buffered - "
61 "message dropped", unbuffered_bytes, total_bytes);
64 void
65 JackPhysicalMidiInput::HandleIncompleteMessage(size_t bytes)
67 jack_error("Discarding %d MIDI byte(s) - incomplete message (cable "
68 "unplugged?)", bytes);
71 void
72 JackPhysicalMidiInput::HandleInvalidStatusByte(jack_midi_data_t status)
74 jack_error("Dropping invalid MIDI status byte '%x'",
75 (unsigned int) status);
78 void
79 JackPhysicalMidiInput::HandleUnexpectedSysexEnd(size_t bytes)
81 jack_error("Discarding %d MIDI byte(s) - received sysex end without sysex "
82 "start (cable unplugged?)", bytes);
85 void
86 JackPhysicalMidiInput::HandleWriteFailure(size_t bytes)
88 jack_error("Failed to write a %d byte MIDI message to the port buffer",
89 bytes);
92 void
93 JackPhysicalMidiInput::Process(jack_nframes_t frames)
95 assert(port_buffer);
96 port_buffer->Reset(frames);
97 jack_nframes_t current_frame = 0;
98 size_t datum_size = sizeof(jack_midi_data_t);
99 for (;;) {
100 jack_midi_data_t datum;
101 current_frame = Receive(&datum, current_frame, frames);
102 if (current_frame >= frames) {
103 break;
106 jack_log("JackPhysicalMidiInput::Process (%d) - Received '%x' byte",
107 current_frame, (unsigned int) datum);
109 if (datum >= 0xf8) {
110 // Realtime
111 if (datum == 0xfd) {
112 HandleInvalidStatusByte(datum);
113 } else {
115 jack_log("JackPhysicalMidiInput::Process - Writing realtime "
116 "event.");
118 WriteByteEvent(current_frame, datum);
120 continue;
122 if (datum == 0xf7) {
123 // Sysex end
124 if (status_byte != 0xf0) {
125 HandleUnexpectedSysexEnd(buffered_bytes + unbuffered_bytes);
126 Clear();
127 expected_data_bytes = 0;
128 status_byte = 0;
129 } else {
131 jack_log("JackPhysicalMidiInput::Process - Writing sysex "
132 "event.");
134 WriteBufferedSysexEvent(current_frame);
136 continue;
138 if (datum >= 0x80) {
140 // We're handling a non-realtime status byte
142 jack_log("JackPhysicalMidiInput::Process - Handling non-realtime "
143 "status byte.");
145 if (buffered_bytes || unbuffered_bytes) {
146 HandleIncompleteMessage(buffered_bytes + unbuffered_bytes + 1);
147 Clear();
149 status_byte = datum;
150 switch (datum & 0xf0) {
151 case 0x80:
152 case 0x90:
153 case 0xa0:
154 case 0xb0:
155 case 0xe0:
156 // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
157 expected_data_bytes = 2;
158 break;
159 case 0xc0:
160 case 0xd0:
161 // Program Change, Channel Pressure
162 expected_data_bytes = 1;
163 break;
164 case 0xf0:
165 switch (datum) {
166 case 0xf0:
167 // Sysex message
168 expected_data_bytes = 0;
169 break;
170 case 0xf1:
171 case 0xf3:
172 // MTC Quarter frame, Song Select
173 expected_data_bytes = 1;
174 break;
175 case 0xf2:
176 // Song Position
177 expected_data_bytes = 2;
178 break;
179 case 0xf4:
180 case 0xf5:
181 // Undefined
182 HandleInvalidStatusByte(datum);
183 expected_data_bytes = 0;
184 status_byte = 0;
185 break;
186 case 0xf6:
187 // Tune Request
188 WriteByteEvent(current_frame, datum);
189 expected_data_bytes = 0;
190 status_byte = 0;
192 break;
194 continue;
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) {
203 buffered_bytes++;
204 } else {
205 unbuffered_bytes++;
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 "
214 "event.");
216 WriteBufferedEvent(current_frame);
217 } else {
218 HandleBufferFailure(unbuffered_bytes, total_bytes);
219 Clear();
221 if (status_byte >= 0xf0) {
222 expected_data_bytes = 0;
223 status_byte = 0;
229 void
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);
235 if (event) {
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;
242 if (data_length_2) {
243 memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
245 } else {
246 HandleWriteFailure(space + 1);
248 Clear();
251 void
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);
257 if (event) {
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;
264 if (data_length_2) {
265 memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
267 event[data_length_1 + data_length_2 + 1] = 0xf7;
268 } else {
269 HandleWriteFailure(space + 2);
271 Clear();
274 void
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);
280 if (event) {
281 event[0] = datum;
282 } else {
283 HandleWriteFailure(1);