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