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