|
- /*
- Copyright (C) 2009 Devin Anderson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- */
-
- #include <cassert>
- #include <cstring>
- #include <new>
-
- #include "JackError.h"
- #include "JackPhysicalMidiInput.h"
-
- namespace Jack {
-
- JackPhysicalMidiInput::JackPhysicalMidiInput(size_t buffer_size)
- {
- size_t datum_size = sizeof(jack_midi_data_t);
- assert(buffer_size > 0);
- input_ring = jack_ringbuffer_create((buffer_size + 1) * datum_size);
- if (! input_ring) {
- throw std::bad_alloc();
- }
- jack_ringbuffer_mlock(input_ring);
- Clear();
- expected_data_bytes = 0;
- status_byte = 0;
- }
-
- JackPhysicalMidiInput::~JackPhysicalMidiInput()
- {
- jack_ringbuffer_free(input_ring);
- }
-
- void
- JackPhysicalMidiInput::Clear()
- {
- jack_ringbuffer_reset(input_ring);
- buffered_bytes = 0;
- unbuffered_bytes = 0;
- }
-
- void
- JackPhysicalMidiInput::HandleBufferFailure(size_t unbuffered_bytes,
- size_t total_bytes)
- {
- jack_error("%d MIDI byte(s) of a %d byte message could not be buffered - "
- "message dropped", unbuffered_bytes, total_bytes);
- }
-
- void
- JackPhysicalMidiInput::HandleIncompleteMessage(size_t bytes)
- {
- jack_error("Discarding %d MIDI byte(s) - incomplete message (cable "
- "unplugged?)", bytes);
- }
-
- void
- JackPhysicalMidiInput::HandleInvalidStatusByte(jack_midi_data_t status)
- {
- jack_error("Dropping invalid MIDI status byte '%x'",
- (unsigned int) status);
- }
-
- void
- JackPhysicalMidiInput::HandleUnexpectedSysexEnd(size_t bytes)
- {
- jack_error("Discarding %d MIDI byte(s) - received sysex end without sysex "
- "start (cable unplugged?)", bytes);
- }
-
- void
- JackPhysicalMidiInput::HandleWriteFailure(size_t bytes)
- {
- jack_error("Failed to write a %d byte MIDI message to the port buffer",
- bytes);
- }
-
- void
- JackPhysicalMidiInput::Process(jack_nframes_t frames)
- {
- assert(port_buffer);
- port_buffer->Reset(frames);
- jack_nframes_t current_frame = 0;
- size_t datum_size = sizeof(jack_midi_data_t);
- for (;;) {
- jack_midi_data_t datum;
- current_frame = Receive(&datum, current_frame, frames);
- if (current_frame >= frames) {
- break;
- }
-
- jack_log("JackPhysicalMidiInput::Process (%d) - Received '%x' byte",
- current_frame, (unsigned int) datum);
-
- if (datum >= 0xf8) {
- // Realtime
- if (datum == 0xfd) {
- HandleInvalidStatusByte(datum);
- } else {
-
- jack_log("JackPhysicalMidiInput::Process - Writing realtime "
- "event.");
-
- WriteByteEvent(current_frame, datum);
- }
- continue;
- }
- if (datum == 0xf7) {
- // Sysex end
- if (status_byte != 0xf0) {
- HandleUnexpectedSysexEnd(buffered_bytes + unbuffered_bytes);
- Clear();
- expected_data_bytes = 0;
- status_byte = 0;
- } else {
-
- jack_log("JackPhysicalMidiInput::Process - Writing sysex "
- "event.");
-
- WriteBufferedSysexEvent(current_frame);
- }
- continue;
- }
- if (datum >= 0x80) {
-
- // We're handling a non-realtime status byte
-
- jack_log("JackPhysicalMidiInput::Process - Handling non-realtime "
- "status byte.");
-
- if (buffered_bytes || unbuffered_bytes) {
- HandleIncompleteMessage(buffered_bytes + unbuffered_bytes + 1);
- Clear();
- }
- status_byte = datum;
- switch (datum & 0xf0) {
- case 0x80:
- case 0x90:
- case 0xa0:
- case 0xb0:
- case 0xe0:
- // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
- expected_data_bytes = 2;
- break;
- case 0xc0:
- case 0xd0:
- // Program Change, Channel Pressure
- expected_data_bytes = 1;
- break;
- case 0xf0:
- switch (datum) {
- case 0xf0:
- // Sysex message
- expected_data_bytes = 0;
- break;
- case 0xf1:
- case 0xf3:
- // MTC Quarter frame, Song Select
- expected_data_bytes = 1;
- break;
- case 0xf2:
- // Song Position
- expected_data_bytes = 2;
- break;
- case 0xf4:
- case 0xf5:
- // Undefined
- HandleInvalidStatusByte(datum);
- expected_data_bytes = 0;
- status_byte = 0;
- break;
- case 0xf6:
- // Tune Request
- WriteByteEvent(current_frame, datum);
- expected_data_bytes = 0;
- status_byte = 0;
- }
- break;
- }
- continue;
- }
-
- // We're handling a data byte
-
- jack_log("JackPhysicalMidiInput::Process - Buffering data byte.");
-
- if (jack_ringbuffer_write(input_ring, (const char *) &datum,
- datum_size) == datum_size) {
- buffered_bytes++;
- } else {
- unbuffered_bytes++;
- }
- unsigned long total_bytes = buffered_bytes + unbuffered_bytes;
- assert((! expected_data_bytes) ||
- (total_bytes <= expected_data_bytes));
- if (total_bytes == expected_data_bytes) {
- if (! unbuffered_bytes) {
-
- jack_log("JackPhysicalMidiInput::Process - Writing buffered "
- "event.");
-
- WriteBufferedEvent(current_frame);
- } else {
- HandleBufferFailure(unbuffered_bytes, total_bytes);
- Clear();
- }
- if (status_byte >= 0xf0) {
- expected_data_bytes = 0;
- status_byte = 0;
- }
- }
- }
- }
-
- void
- JackPhysicalMidiInput::WriteBufferedEvent(jack_nframes_t frame)
- {
- assert(port_buffer && port_buffer->IsValid());
- size_t space = jack_ringbuffer_read_space(input_ring);
- jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 1);
- if (event) {
- jack_ringbuffer_data_t vector[2];
- jack_ringbuffer_get_read_vector(input_ring, vector);
- event[0] = status_byte;
- size_t data_length_1 = vector[0].len;
- memcpy(event + 1, vector[0].buf, data_length_1);
- size_t data_length_2 = vector[1].len;
- if (data_length_2) {
- memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
- }
- } else {
- HandleWriteFailure(space + 1);
- }
- Clear();
- }
-
- void
- JackPhysicalMidiInput::WriteBufferedSysexEvent(jack_nframes_t frame)
- {
- assert(port_buffer && port_buffer->IsValid());
- size_t space = jack_ringbuffer_read_space(input_ring);
- jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 2);
- if (event) {
- jack_ringbuffer_data_t vector[2];
- jack_ringbuffer_get_read_vector(input_ring, vector);
- event[0] = status_byte;
- size_t data_length_1 = vector[0].len;
- memcpy(event + 1, vector[0].buf, data_length_1);
- size_t data_length_2 = vector[1].len;
- if (data_length_2) {
- memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
- }
- event[data_length_1 + data_length_2 + 1] = 0xf7;
- } else {
- HandleWriteFailure(space + 2);
- }
- Clear();
- }
-
- void
- JackPhysicalMidiInput::WriteByteEvent(jack_nframes_t frame,
- jack_midi_data_t datum)
- {
- assert(port_buffer && port_buffer->IsValid());
- jack_midi_data_t *event = port_buffer->ReserveEvent(frame, 1);
- if (event) {
- event[0] = datum;
- } else {
- HandleWriteFailure(1);
- }
- }
-
- }
|