Jack2 1.9.8
|
00001 /* 00002 Copyright (C) 2011 Devin Anderson 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 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 General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #include <cassert> 00021 #include <memory> 00022 00023 #include "JackCoreMidiInputPort.h" 00024 #include "JackMidiUtil.h" 00025 00026 using Jack::JackCoreMidiInputPort; 00027 00028 JackCoreMidiInputPort::JackCoreMidiInputPort(double time_ratio, 00029 size_t max_bytes, 00030 size_t max_messages): 00031 JackCoreMidiPort(time_ratio) 00032 { 00033 thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages); 00034 std::auto_ptr<JackMidiAsyncQueue> thread_queue_ptr(thread_queue); 00035 write_queue = new JackMidiBufferWriteQueue(); 00036 std::auto_ptr<JackMidiBufferWriteQueue> write_queue_ptr(write_queue); 00037 sysex_buffer = new jack_midi_data_t[max_bytes]; 00038 write_queue_ptr.release(); 00039 thread_queue_ptr.release(); 00040 jack_event = 0; 00041 } 00042 00043 JackCoreMidiInputPort::~JackCoreMidiInputPort() 00044 { 00045 delete thread_queue; 00046 delete write_queue; 00047 delete[] sysex_buffer; 00048 } 00049 00050 jack_nframes_t 00051 JackCoreMidiInputPort::GetFramesFromTimeStamp(MIDITimeStamp timestamp) 00052 { 00053 return GetFramesFromTime((jack_time_t) (timestamp * time_ratio)); 00054 } 00055 00056 void 00057 JackCoreMidiInputPort::Initialize(const char *alias_name, 00058 const char *client_name, 00059 const char *driver_name, int index, 00060 MIDIEndpointRef endpoint) 00061 { 00062 JackCoreMidiPort::Initialize(alias_name, client_name, driver_name, index, endpoint, false); 00063 } 00064 00065 void 00066 JackCoreMidiInputPort::ProcessCoreMidi(const MIDIPacketList *packet_list) 00067 { 00068 set_threaded_log_function(); 00069 00070 unsigned int packet_count = packet_list->numPackets; 00071 assert(packet_count); 00072 MIDIPacket *packet = (MIDIPacket *) packet_list->packet; 00073 for (unsigned int i = 0; i < packet_count; i++) { 00074 jack_midi_data_t *data = packet->data; 00075 size_t size = packet->length; 00076 assert(size); 00077 jack_midi_event_t event; 00078 00079 // XX: There might be dragons in my spaghetti. This code is begging 00080 // for a rewrite. 00081 00082 if (sysex_bytes_sent) { 00083 if (data[0] & 0x80) { 00084 jack_error("JackCoreMidiInputPort::ProcessCoreMidi - System " 00085 "exclusive message aborted."); 00086 sysex_bytes_sent = 0; 00087 goto parse_event; 00088 } 00089 buffer_sysex_bytes: 00090 if ((sysex_bytes_sent + size) <= sizeof(sysex_buffer)) { 00091 memcpy(sysex_buffer + sysex_bytes_sent, packet, 00092 size * sizeof(jack_midi_data_t)); 00093 } 00094 sysex_bytes_sent += size; 00095 if (data[size - 1] == 0xf7) { 00096 if (sysex_bytes_sent > sizeof(sysex_buffer)) { 00097 jack_error("JackCoreMidiInputPort::ProcessCoreMidi - " 00098 "Could not buffer a %d-byte system exclusive " 00099 "message. Discarding message.", 00100 sysex_bytes_sent); 00101 sysex_bytes_sent = 0; 00102 goto get_next_packet; 00103 } 00104 event.buffer = sysex_buffer; 00105 event.size = sysex_bytes_sent; 00106 sysex_bytes_sent = 0; 00107 goto send_event; 00108 } 00109 goto get_next_packet; 00110 } 00111 00112 parse_event: 00113 if (data[0] == 0xf0) { 00114 if (data[size - 1] != 0xf7) { 00115 goto buffer_sysex_bytes; 00116 } 00117 } 00118 event.buffer = data; 00119 event.size = size; 00120 00121 send_event: 00122 event.time = GetFramesFromTimeStamp(packet->timeStamp); 00123 switch (thread_queue->EnqueueEvent(&event)) { 00124 case JackMidiWriteQueue::BUFFER_FULL: 00125 jack_error("JackCoreMidiInputPort::ProcessCoreMidi - The thread " 00126 "queue buffer is full. Dropping event."); 00127 break; 00128 case JackMidiWriteQueue::BUFFER_TOO_SMALL: 00129 jack_error("JackCoreMidiInputPort::ProcessCoreMidi - The thread " 00130 "queue couldn't enqueue a %d-byte packet. Dropping " 00131 "event.", event.size); 00132 break; 00133 default: 00134 ; 00135 } 00136 00137 get_next_packet: 00138 packet = MIDIPacketNext(packet); 00139 assert(packet); 00140 } 00141 } 00142 00143 void 00144 JackCoreMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer, 00145 jack_nframes_t frames) 00146 { 00147 write_queue->ResetMidiBuffer(port_buffer, frames); 00148 if (! jack_event) { 00149 jack_event = thread_queue->DequeueEvent(); 00150 } 00151 00152 for (; jack_event; jack_event = thread_queue->DequeueEvent()) { 00153 // Add 'frames' to MIDI events to align with audio. 00154 switch (write_queue->EnqueueEvent(jack_event, frames)) { 00155 case JackMidiWriteQueue::BUFFER_TOO_SMALL: 00156 jack_error("JackCoreMidiInputPort::ProcessJack - The write queue " 00157 "couldn't enqueue a %d-byte event. Dropping event.", 00158 jack_event->size); 00159 // Fallthrough on purpose 00160 case JackMidiWriteQueue::OK: 00161 continue; 00162 default: 00163 ; 00164 } 00165 break; 00166 } 00167 } 00168 00169 bool 00170 JackCoreMidiInputPort::Start() 00171 { 00172 // Hack: Get rid of any messages that might have come in before starting 00173 // the engine. 00174 while (thread_queue->DequeueEvent()); 00175 sysex_bytes_sent = 0; 00176 return true; 00177 } 00178 00179 bool 00180 JackCoreMidiInputPort::Stop() 00181 { 00182 return true; 00183 }