Jack2  1.9.10
JackALSARawMidiInputPort.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 "JackALSARawMidiInputPort.h"
00024 #include "JackMidiUtil.h"
00025 #include "JackError.h"
00026 
00027 using Jack::JackALSARawMidiInputPort;
00028 
00029 JackALSARawMidiInputPort::JackALSARawMidiInputPort(snd_rawmidi_info_t *info,
00030                                                    size_t index,
00031                                                    size_t max_bytes,
00032                                                    size_t max_messages):
00033     JackALSARawMidiPort(info, index, POLLIN)
00034 {
00035     alsa_event = 0;
00036     jack_event = 0;
00037     receive_queue = new JackALSARawMidiReceiveQueue(rawmidi, max_bytes);
00038     std::auto_ptr<JackALSARawMidiReceiveQueue> receive_ptr(receive_queue);
00039     thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
00040     std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
00041     write_queue = new JackMidiBufferWriteQueue();
00042     std::auto_ptr<JackMidiBufferWriteQueue> write_ptr(write_queue);
00043     raw_queue = new JackMidiRawInputWriteQueue(thread_queue, max_bytes,
00044                                                max_messages);
00045     write_ptr.release();
00046     thread_ptr.release();
00047     receive_ptr.release();
00048 }
00049 
00050 JackALSARawMidiInputPort::~JackALSARawMidiInputPort()
00051 {
00052     delete raw_queue;
00053     delete receive_queue;
00054     delete thread_queue;
00055     delete write_queue;
00056 }
00057 
00058 bool
00059 JackALSARawMidiInputPort::ProcessJack(JackMidiBuffer *port_buffer,
00060                                       jack_nframes_t frames)
00061 {
00062     write_queue->ResetMidiBuffer(port_buffer, frames);
00063     bool dequeued = false;
00064     if (! jack_event) {
00065         goto dequeue_event;
00066     }
00067     for (;;) {
00068         switch (write_queue->EnqueueEvent(jack_event, frames)) {
00069         case JackMidiWriteQueue::BUFFER_TOO_SMALL:
00070             jack_error("JackALSARawMidiInputPort::ProcessJack - The write "
00071                        "queue couldn't enqueue a %d-byte event.  Dropping "
00072                        "event.", jack_event->size);
00073             // Fallthrough on purpose.
00074         case JackMidiWriteQueue::OK:
00075             break;
00076         default:
00077             goto trigger_queue_event;
00078         }
00079     dequeue_event:
00080         jack_event = thread_queue->DequeueEvent();
00081         if (! jack_event) {
00082             break;
00083         }
00084         dequeued = true;
00085     }
00086  trigger_queue_event:
00087     return dequeued ? TriggerQueueEvent() : true;
00088 }
00089 
00090 bool
00091 JackALSARawMidiInputPort::ProcessPollEvents(jack_nframes_t current_frame)
00092 {
00093     if (GetQueuePollEvent() == -1) {
00094         return false;
00095     }
00096     int io_event = GetIOPollEvent();
00097     switch (io_event) {
00098     case -1:
00099         return false;
00100     case 1:
00101         alsa_event = receive_queue->DequeueEvent();
00102     }
00103     if (alsa_event) {
00104         size_t size = alsa_event->size;
00105         size_t space = raw_queue->GetAvailableSpace();
00106         bool enough_room = space >= size;
00107         if (enough_room) {
00108             assert(raw_queue->EnqueueEvent(current_frame, size,
00109                                            alsa_event->buffer) ==
00110                    JackMidiWriteQueue::OK);
00111             alsa_event = 0;
00112         } else if (space) {
00113             assert(raw_queue->EnqueueEvent(current_frame, space,
00114                                            alsa_event->buffer) ==
00115                    JackMidiWriteQueue::OK);
00116             alsa_event->buffer += space;
00117             alsa_event->size -= space;
00118         }
00119         SetIOEventsEnabled(enough_room);
00120     }
00121     raw_queue->Process();
00122     return true;
00123 }