Jack2 1.9.8

JackCoreMidiInputPort.cpp

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 }