Jack2 1.9.8

JackMidiRawInputWriteQueue.cpp

00001 /*
00002 Copyright (C) 2010 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 <memory>
00022 #include <new>
00023 
00024 #include "JackMidiRawInputWriteQueue.h"
00025 
00026 using Jack::JackMidiRawInputWriteQueue;
00027 
00028 JackMidiRawInputWriteQueue::
00029 JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue,
00030                            size_t max_packet_data, size_t max_packets)
00031 {
00032     packet_queue = new JackMidiAsyncQueue(max_packet_data, max_packets);
00033     std::auto_ptr<JackMidiAsyncQueue> packet_queue_ptr(packet_queue);
00034     input_buffer = new jack_midi_data_t[max_packet_data];
00035     Clear();
00036     expected_bytes = 0;
00037     event_pending = false;
00038     input_buffer_size = max_packet_data;
00039     packet = 0;
00040     status_byte = 0;
00041     this->write_queue = write_queue;
00042     packet_queue_ptr.release();
00043 }
00044 
00045 JackMidiRawInputWriteQueue::~JackMidiRawInputWriteQueue()
00046 {
00047     delete[] input_buffer;
00048     delete packet_queue;
00049 }
00050 
00051 void
00052 JackMidiRawInputWriteQueue::Clear()
00053 {
00054     total_bytes = 0;
00055     unbuffered_bytes = 0;
00056 }
00057 
00058 Jack::JackMidiWriteQueue::EnqueueResult
00059 JackMidiRawInputWriteQueue::EnqueueEvent(jack_nframes_t time, size_t size,
00060                                          jack_midi_data_t *buffer)
00061 {
00062     return packet_queue->EnqueueEvent(time, size, buffer);
00063 }
00064 
00065 size_t
00066 JackMidiRawInputWriteQueue::GetAvailableSpace()
00067 {
00068     return packet_queue->GetAvailableSpace();
00069 }
00070 
00071 void
00072 JackMidiRawInputWriteQueue::HandleBufferFailure(size_t unbuffered_bytes,
00073                                                 size_t total_bytes)
00074 {
00075     jack_error("JackMidiRawInputWriteQueue::HandleBufferFailure - %d MIDI "
00076                "byte(s) of a %d byte message could not be buffered.  The "
00077                "message has been dropped.", unbuffered_bytes, total_bytes);
00078 }
00079 
00080 void
00081 JackMidiRawInputWriteQueue::HandleEventLoss(jack_midi_event_t *event)
00082 {
00083     jack_error("JackMidiRawInputWriteQueue::HandleEventLoss - A %d byte MIDI "
00084                "event scheduled for frame '%d' could not be processed because "
00085                "the write queue cannot accomodate an event of that size.  The "
00086                "event has been discarded.", event->size, event->time);
00087 }
00088 
00089 void
00090 JackMidiRawInputWriteQueue::HandleIncompleteMessage(size_t total_bytes)
00091 {
00092     jack_error("JackMidiRawInputWriteQueue::HandleIncompleteMessage - "
00093                "Discarding %d MIDI byte(s) of an incomplete message.  The "
00094                "MIDI cable may have been unplugged.", total_bytes);
00095 }
00096 
00097 void
00098 JackMidiRawInputWriteQueue::HandleInvalidStatusByte(jack_midi_data_t byte)
00099 {
00100     jack_error("JackMidiRawInputWriteQueue::HandleInvalidStatusByte - "
00101                "Dropping invalid MIDI status byte '%x'.", (unsigned int) byte);
00102 }
00103 
00104 void
00105 JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd(size_t total_bytes)
00106 {
00107     jack_error("JackMidiRawInputWriteQueue::HandleUnexpectedSysexEnd - "
00108                "Received a sysex end byte without first receiving a sysex "
00109                "start byte.  Discarding %d MIDI byte(s).  The cable may have "
00110                "been unplugged.", total_bytes);
00111 }
00112 
00113 bool
00114 JackMidiRawInputWriteQueue::PrepareBufferedEvent(jack_nframes_t time)
00115 {
00116     bool result = ! unbuffered_bytes;
00117     if (! result) {
00118         HandleBufferFailure(unbuffered_bytes, total_bytes);
00119     } else {
00120         PrepareEvent(time, total_bytes, input_buffer);
00121     }
00122     Clear();
00123     if (status_byte >= 0xf0) {
00124         expected_bytes = 0;
00125         status_byte = 0;
00126     }
00127     return result;
00128 }
00129 
00130 bool
00131 JackMidiRawInputWriteQueue::PrepareByteEvent(jack_nframes_t time,
00132                                              jack_midi_data_t byte)
00133 {
00134     event_byte = byte;
00135     PrepareEvent(time, 1, &event_byte);
00136     return true;
00137 }
00138 
00139 void
00140 JackMidiRawInputWriteQueue::PrepareEvent(jack_nframes_t time, size_t size,
00141                                          jack_midi_data_t *buffer)
00142 {
00143     event.buffer = buffer;
00144     event.size = size;
00145     event.time = time;
00146     event_pending = true;
00147 }
00148 
00149 jack_nframes_t
00150 JackMidiRawInputWriteQueue::Process(jack_nframes_t boundary_frame)
00151 {
00152     if (event_pending) {
00153         if (! WriteEvent(boundary_frame)) {
00154             return event.time;
00155         }
00156     }
00157     if (! packet) {
00158         packet = packet_queue->DequeueEvent();
00159     }
00160     for (; packet; packet = packet_queue->DequeueEvent()) {
00161         for (; packet->size; (packet->buffer)++, (packet->size)--) {
00162             if (ProcessByte(packet->time, *(packet->buffer))) {
00163                 if (! WriteEvent(boundary_frame)) {
00164                     (packet->buffer)++;
00165                     (packet->size)--;
00166                     return event.time;
00167                 }
00168             }
00169         }
00170     }
00171     return 0;
00172 }
00173 
00174 bool
00175 JackMidiRawInputWriteQueue::ProcessByte(jack_nframes_t time,
00176                                         jack_midi_data_t byte)
00177 {
00178     if (byte >= 0xf8) {
00179         // Realtime
00180         if (byte == 0xfd) {
00181             HandleInvalidStatusByte(byte);
00182             return false;
00183         }
00184         return PrepareByteEvent(time, byte);
00185     }
00186     if (byte == 0xf7) {
00187         // Sysex end
00188         if (status_byte == 0xf0) {
00189             RecordByte(byte);
00190             return PrepareBufferedEvent(time);
00191         }
00192         HandleUnexpectedSysexEnd(total_bytes);
00193         Clear();
00194         expected_bytes = 0;
00195         status_byte = 0;
00196         return false;
00197     }
00198     if (byte >= 0x80) {
00199         // Non-realtime status byte
00200         if (total_bytes) {
00201             HandleIncompleteMessage(total_bytes);
00202             Clear();
00203         }
00204         status_byte = byte;
00205         switch (byte & 0xf0) {
00206         case 0x80:
00207         case 0x90:
00208         case 0xa0:
00209         case 0xb0:
00210         case 0xe0:
00211             // Note On, Note Off, Aftertouch, Control Change, Pitch Wheel
00212             expected_bytes = 3;
00213             break;
00214         case 0xc0:
00215         case 0xd0:
00216             // Program Change, Channel Pressure
00217             expected_bytes = 2;
00218             break;
00219         case 0xf0:
00220             switch (byte) {
00221             case 0xf0:
00222                 // Sysex
00223                 expected_bytes = 0;
00224                 break;
00225             case 0xf1:
00226             case 0xf3:
00227                 // MTC Quarter Frame, Song Select
00228                 expected_bytes = 2;
00229                 break;
00230             case 0xf2:
00231                 // Song Position
00232                 expected_bytes = 3;
00233                 break;
00234             case 0xf4:
00235             case 0xf5:
00236                 // Undefined
00237                 HandleInvalidStatusByte(byte);
00238                 expected_bytes = 0;
00239                 status_byte = 0;
00240                 return false;
00241             case 0xf6:
00242                 // Tune Request
00243                 bool result = PrepareByteEvent(time, byte);
00244                 if (result) {
00245                     expected_bytes = 0;
00246                     status_byte = 0;
00247                 }
00248                 return result;
00249             }
00250         }
00251         RecordByte(byte);
00252         return false;
00253     }
00254     // Data byte
00255     if (! status_byte) {
00256         // Data bytes without a status will be discarded.
00257         total_bytes++;
00258         unbuffered_bytes++;
00259         return false;
00260     }
00261     if (! total_bytes) {
00262         // Apply running status.
00263         RecordByte(status_byte);
00264     }
00265     RecordByte(byte);
00266     return (total_bytes == expected_bytes) ? PrepareBufferedEvent(time) :
00267         false;
00268 }
00269 
00270 void
00271 JackMidiRawInputWriteQueue::RecordByte(jack_midi_data_t byte)
00272 {
00273     if (total_bytes < input_buffer_size) {
00274         input_buffer[total_bytes] = byte;
00275     } else {
00276         unbuffered_bytes++;
00277     }
00278     total_bytes++;
00279 }
00280 
00281 bool
00282 JackMidiRawInputWriteQueue::WriteEvent(jack_nframes_t boundary_frame)
00283 {
00284     if ((! boundary_frame) || (event.time < boundary_frame)) {
00285         switch (write_queue->EnqueueEvent(&event)) {
00286         case BUFFER_TOO_SMALL:
00287             HandleEventLoss(&event);
00288             // Fallthrough on purpose
00289         case OK:
00290             event_pending = false;
00291             return true;
00292         default:
00293             // This is here to stop compilers from warning us about not
00294             // handling enumeration values.
00295             ;
00296         }
00297     }
00298     return false;
00299 }