Jack2 1.9.6

JackPhysicalMidiInput.cpp

00001 /*
00002 Copyright (C) 2009 Devin Anderson
00003 
00004 This program is free software; you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as published by
00006 the Free Software Foundation; either version 2.1 of the License, or
00007 (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018 */
00019 
00020 #include <cassert>
00021 #include <cstring>
00022 #include <new>
00023 
00024 #include "JackError.h"
00025 #include "JackPhysicalMidiInput.h"
00026 
00027 namespace Jack {
00028 
00029 JackPhysicalMidiInput::JackPhysicalMidiInput(size_t buffer_size)
00030 {
00031     size_t datum_size = sizeof(jack_midi_data_t);
00032     assert(buffer_size > 0);
00033     input_ring = jack_ringbuffer_create((buffer_size + 1) * datum_size);
00034     if (! input_ring) {
00035         throw std::bad_alloc();
00036     }
00037     jack_ringbuffer_mlock(input_ring);
00038     Clear();
00039     expected_data_bytes = 0;
00040     status_byte = 0;
00041 }
00042 
00043 JackPhysicalMidiInput::~JackPhysicalMidiInput()
00044 {
00045     jack_ringbuffer_free(input_ring);
00046 }
00047 
00048 void
00049 JackPhysicalMidiInput::Clear()
00050 {
00051     jack_ringbuffer_reset(input_ring);
00052     buffered_bytes = 0;
00053     unbuffered_bytes = 0;
00054 }
00055 
00056 void
00057 JackPhysicalMidiInput::HandleBufferFailure(size_t unbuffered_bytes,
00058                                            size_t total_bytes)
00059 {
00060     jack_error("%d MIDI byte(s) of a %d byte message could not be buffered - "
00061                "message dropped", unbuffered_bytes, total_bytes);
00062 }
00063 
00064 void
00065 JackPhysicalMidiInput::HandleIncompleteMessage(size_t bytes)
00066 {
00067     jack_error("Discarding %d MIDI byte(s) - incomplete message (cable "
00068                "unplugged?)", bytes);
00069 }
00070 
00071 void
00072 JackPhysicalMidiInput::HandleInvalidStatusByte(jack_midi_data_t status)
00073 {
00074     jack_error("Dropping invalid MIDI status byte '%x'",
00075                (unsigned int) status);
00076 }
00077 
00078 void
00079 JackPhysicalMidiInput::HandleUnexpectedSysexEnd(size_t bytes)
00080 {
00081     jack_error("Discarding %d MIDI byte(s) - received sysex end without sysex "
00082                "start (cable unplugged?)", bytes);
00083 }
00084 
00085 void
00086 JackPhysicalMidiInput::HandleWriteFailure(size_t bytes)
00087 {
00088     jack_error("Failed to write a %d byte MIDI message to the port buffer",
00089                bytes);
00090 }
00091 
00092 void
00093 JackPhysicalMidiInput::Process(jack_nframes_t frames)
00094 {
00095     assert(port_buffer);
00096     port_buffer->Reset(frames);
00097     jack_nframes_t current_frame = 0;
00098     size_t datum_size = sizeof(jack_midi_data_t);
00099     for (;;) {
00100         jack_midi_data_t datum;
00101         current_frame = Receive(&datum, current_frame, frames);
00102         if (current_frame >= frames) {
00103             break;
00104         }
00105 
00106         jack_log("JackPhysicalMidiInput::Process (%d) - Received '%x' byte",
00107                  current_frame, (unsigned int) datum);
00108 
00109         if (datum >= 0xf8) {
00110             // Realtime
00111             if (datum == 0xfd) {
00112                 HandleInvalidStatusByte(datum);
00113             } else {
00114 
00115                 jack_log("JackPhysicalMidiInput::Process - Writing realtime "
00116                          "event.");
00117 
00118                 WriteByteEvent(current_frame, datum);
00119             }
00120             continue;
00121         }
00122         if (datum == 0xf7) {
00123             // Sysex end
00124             if (status_byte != 0xf0) {
00125                 HandleUnexpectedSysexEnd(buffered_bytes + unbuffered_bytes);
00126                 Clear();
00127                 expected_data_bytes = 0;
00128                 status_byte = 0;
00129             } else {
00130 
00131                 jack_log("JackPhysicalMidiInput::Process - Writing sysex "
00132                          "event.");
00133 
00134                 WriteBufferedSysexEvent(current_frame);
00135             }
00136             continue;
00137         }
00138         if (datum >= 0x80) {
00139 
00140             // We're handling a non-realtime status byte
00141 
00142             jack_log("JackPhysicalMidiInput::Process - Handling non-realtime "
00143                      "status byte.");
00144 
00145             if (buffered_bytes || unbuffered_bytes) {
00146                 HandleIncompleteMessage(buffered_bytes + unbuffered_bytes + 1);
00147                 Clear();
00148             }
00149             status_byte = datum;
00150             switch (datum & 0xf0) {
00151             case 0x80:
00152             case 0x90:
00153             case 0xa0:
00154             case 0xb0:
00155             case 0xe0:
00156                 // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
00157                 expected_data_bytes = 2;
00158                 break;
00159             case 0xc0:
00160             case 0xd0:
00161                 // Program Change, Channel Pressure
00162                 expected_data_bytes = 1;
00163                 break;
00164             case 0xf0:
00165                 switch (datum) {
00166                 case 0xf0:
00167                     // Sysex message
00168                     expected_data_bytes = 0;
00169                     break;
00170                 case 0xf1:
00171                 case 0xf3:
00172                     // MTC Quarter frame, Song Select
00173                     expected_data_bytes = 1;
00174                     break;
00175                 case 0xf2:
00176                     // Song Position
00177                     expected_data_bytes = 2;
00178                     break;
00179                 case 0xf4:
00180                 case 0xf5:
00181                     // Undefined
00182                     HandleInvalidStatusByte(datum);
00183                     expected_data_bytes = 0;
00184                     status_byte = 0;
00185                     break;
00186                 case 0xf6:
00187                     // Tune Request
00188                     WriteByteEvent(current_frame, datum);
00189                     expected_data_bytes = 0;
00190                     status_byte = 0;
00191                 }
00192                 break;
00193             }
00194             continue;
00195         }
00196 
00197         // We're handling a data byte
00198 
00199         jack_log("JackPhysicalMidiInput::Process - Buffering data byte.");
00200 
00201         if (jack_ringbuffer_write(input_ring, (const char *) &datum,
00202                                   datum_size) == datum_size) {
00203             buffered_bytes++;
00204         } else {
00205             unbuffered_bytes++;
00206         }
00207         unsigned long total_bytes = buffered_bytes + unbuffered_bytes;
00208         assert((! expected_data_bytes) ||
00209                (total_bytes <= expected_data_bytes));
00210         if (total_bytes == expected_data_bytes) {
00211             if (! unbuffered_bytes) {
00212 
00213                 jack_log("JackPhysicalMidiInput::Process - Writing buffered "
00214                          "event.");
00215 
00216                 WriteBufferedEvent(current_frame);
00217             } else {
00218                 HandleBufferFailure(unbuffered_bytes, total_bytes);
00219                 Clear();
00220             }
00221             if (status_byte >= 0xf0) {
00222                 expected_data_bytes = 0;
00223                 status_byte = 0;
00224             }
00225         }
00226     }
00227 }
00228 
00229 void
00230 JackPhysicalMidiInput::WriteBufferedEvent(jack_nframes_t frame)
00231 {
00232     assert(port_buffer && port_buffer->IsValid());
00233     size_t space = jack_ringbuffer_read_space(input_ring);
00234     jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 1);
00235     if (event) {
00236         jack_ringbuffer_data_t vector[2];
00237         jack_ringbuffer_get_read_vector(input_ring, vector);
00238         event[0] = status_byte;
00239         size_t data_length_1 = vector[0].len;
00240         memcpy(event + 1, vector[0].buf, data_length_1);
00241         size_t data_length_2 = vector[1].len;
00242         if (data_length_2) {
00243             memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
00244         }
00245     } else {
00246         HandleWriteFailure(space + 1);
00247     }
00248     Clear();
00249 }
00250 
00251 void
00252 JackPhysicalMidiInput::WriteBufferedSysexEvent(jack_nframes_t frame)
00253 {
00254     assert(port_buffer && port_buffer->IsValid());
00255     size_t space = jack_ringbuffer_read_space(input_ring);
00256     jack_midi_data_t *event = port_buffer->ReserveEvent(frame, space + 2);
00257     if (event) {
00258         jack_ringbuffer_data_t vector[2];
00259         jack_ringbuffer_get_read_vector(input_ring, vector);
00260         event[0] = status_byte;
00261         size_t data_length_1 = vector[0].len;
00262         memcpy(event + 1, vector[0].buf, data_length_1);
00263         size_t data_length_2 = vector[1].len;
00264         if (data_length_2) {
00265             memcpy(event + data_length_1 + 1, vector[1].buf, data_length_2);
00266         }
00267         event[data_length_1 + data_length_2 + 1] = 0xf7;
00268     } else {
00269         HandleWriteFailure(space + 2);
00270     }
00271     Clear();
00272 }
00273 
00274 void
00275 JackPhysicalMidiInput::WriteByteEvent(jack_nframes_t frame,
00276                                       jack_midi_data_t datum)
00277 {
00278     assert(port_buffer && port_buffer->IsValid());
00279     jack_midi_data_t *event = port_buffer->ReserveEvent(frame, 1);
00280     if (event) {
00281         event[0] = datum;
00282     } else {
00283         HandleWriteFailure(1);
00284     }
00285 }
00286 
00287 }