Jack2
1.9.8
|
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 }