Jack2  1.9.10
JackALSARawMidiOutputPort.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 "JackALSARawMidiOutputPort.h"
00024 #include "JackError.h"
00025 
00026 using Jack::JackALSARawMidiOutputPort;
00027 
00028 JackALSARawMidiOutputPort::JackALSARawMidiOutputPort(snd_rawmidi_info_t *info,
00029                                                      size_t index,
00030                                                      size_t max_bytes_per_poll,
00031                                                      size_t max_bytes,
00032                                                      size_t max_messages):
00033     JackALSARawMidiPort(info, index, POLLOUT)
00034 {
00035     alsa_event = 0;
00036     read_queue = new JackMidiBufferReadQueue();
00037     std::auto_ptr<JackMidiBufferReadQueue> read_ptr(read_queue);
00038     send_queue = new JackALSARawMidiSendQueue(rawmidi, max_bytes_per_poll);
00039     std::auto_ptr<JackALSARawMidiSendQueue> send_ptr(send_queue);
00040     thread_queue = new JackMidiAsyncQueue(max_bytes, max_messages);
00041     std::auto_ptr<JackMidiAsyncQueue> thread_ptr(thread_queue);
00042     raw_queue = new JackMidiRawOutputWriteQueue(send_queue, max_bytes,
00043                                                 max_messages, max_messages);
00044     thread_ptr.release();
00045     send_ptr.release();
00046     read_ptr.release();
00047 }
00048 
00049 JackALSARawMidiOutputPort::~JackALSARawMidiOutputPort()
00050 {
00051     delete raw_queue;
00052     delete read_queue;
00053     delete send_queue;
00054     delete thread_queue;
00055 }
00056 
00057 bool
00058 JackALSARawMidiOutputPort::ProcessJack(JackMidiBuffer *port_buffer,
00059                                        jack_nframes_t frames)
00060 {
00061     read_queue->ResetMidiBuffer(port_buffer);
00062     bool enqueued = false;
00063     for (jack_midi_event_t *event = read_queue->DequeueEvent(); event;
00064          event = read_queue->DequeueEvent()) {
00065         switch (thread_queue->EnqueueEvent(event, frames)) {
00066         case JackMidiWriteQueue::BUFFER_FULL:
00067             jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
00068                        "queue doesn't have enough room to enqueue a %d-byte "
00069                        "event.  Dropping event.", event->size);
00070             continue;
00071         case JackMidiWriteQueue::BUFFER_TOO_SMALL:
00072             jack_error("JackALSARawMidiOutputPort::ProcessJack - The thread "
00073                        "queue is too small to enqueue a %d-byte event.  "
00074                        "Dropping event.", event->size);
00075             continue;
00076         default:
00077             enqueued = true;
00078         }
00079     }
00080     return enqueued ? TriggerQueueEvent() : true;
00081 }
00082 
00083 bool
00084 JackALSARawMidiOutputPort::ProcessPollEvents(bool handle_output, bool timeout,
00085                                              jack_nframes_t *frame)
00086 {
00087     int io_event;
00088     int queue_event;
00089     send_queue->ResetPollByteCount();
00090     if (! handle_output) {
00091         assert(timeout);
00092         goto process_raw_queue;
00093     }
00094     io_event = GetIOPollEvent();
00095     if (io_event == -1) {
00096         return false;
00097     }
00098     queue_event = GetQueuePollEvent();
00099     if (queue_event == -1) {
00100         return false;
00101     }
00102     if (io_event || timeout) {
00103     process_raw_queue:
00104         // We call the 'Process' event early because there are events waiting
00105         // to be processed that either need to be sent now, or before now.
00106         raw_queue->Process();
00107     } else if (! queue_event) {
00108         return true;
00109     }
00110     if (! alsa_event) {
00111         alsa_event = thread_queue->DequeueEvent();
00112     }
00113     for (; alsa_event; alsa_event = thread_queue->DequeueEvent()) {
00114         switch (raw_queue->EnqueueEvent(alsa_event)) {
00115         case JackMidiWriteQueue::BUFFER_TOO_SMALL:
00116             jack_error("JackALSARawMidiOutputPort::ProcessQueues - The raw "
00117                        "output queue couldn't enqueue a %d-byte event.  "
00118                        "Dropping event.", alsa_event->size);
00119             // Fallthrough on purpose.
00120         case JackMidiWriteQueue::OK:
00121             continue;
00122         default:
00123             ;
00124         }
00125 
00126         // Try to free up some space by processing events early.
00127         *frame = raw_queue->Process();
00128 
00129         switch (raw_queue->EnqueueEvent(alsa_event)) {
00130         case JackMidiWriteQueue::BUFFER_FULL:
00131             goto set_io_events;
00132         case JackMidiWriteQueue::BUFFER_TOO_SMALL:
00133             // This shouldn't happen.
00134             assert(false);
00135         default:
00136             ;
00137         }
00138     }
00139     *frame = raw_queue->Process();
00140  set_io_events:
00141     bool blocked = send_queue->IsBlocked();
00142     SetIOEventsEnabled(blocked);
00143     if (blocked) {
00144         *frame = 0;
00145     }
00146     return true;
00147 }