/* Copyright (C) 2010 Devin Anderson This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __JackMidiRawOutputWriteQueue__ #define __JackMidiRawOutputWriteQueue__ #include "JackMidiAsyncQueue.h" #include "JackMidiSendQueue.h" namespace Jack { /** * This queue enqueues valid MIDI events and modifies them for raw output * to a write queue. It has a couple of advantages over straight MIDI * event copying: * * -Running status: Status bytes can be omitted when the status byte of the * current MIDI message is the same as the status byte of the last sent * MIDI message. * * -Realtime messages: Realtime messages are given priority over * non-realtime messages. Realtime bytes are interspersed with * non-realtime bytes so that realtime messages can be sent as close as * possible to the time they're scheduled for sending. * * Use this queue if the MIDI API you're interfacing with allows you to * send raw MIDI bytes. */ class SERVER_EXPORT JackMidiRawOutputWriteQueue: public JackMidiWriteQueue { private: jack_midi_event_t *non_rt_event; jack_nframes_t non_rt_event_time; JackMidiAsyncQueue *non_rt_queue; jack_midi_event_t *rt_event; jack_nframes_t rt_event_time; JackMidiAsyncQueue *rt_queue; jack_midi_data_t running_status; JackMidiSendQueue *send_queue; void DequeueNonRealtimeEvent(); void DequeueRealtimeEvent(); bool SendByte(jack_nframes_t time, jack_midi_data_t byte); bool SendNonRTBytes(jack_nframes_t boundary_frame); protected: /** * Override this method to specify what happens when the write queue * says that a 1-byte event is too large for its buffer. Basically, * this should never happen. */ virtual void HandleWriteQueueBug(jack_nframes_t time, jack_midi_data_t byte); public: using JackMidiWriteQueue::EnqueueEvent; /** * Called to create a new raw write queue. The `send_queue` argument * is the queue to write raw bytes to. The optional `max_rt_messages` * argument specifies the number of messages that can be enqueued in * the internal realtime queue. The optional `max_non_rt_messages` * argument specifies the number of messages that can be enqueued in * the internal non-realtime queue. The optional `non_rt_size` * argument specifies the total number of MIDI bytes that can be put in * the non-realtime queue. */ JackMidiRawOutputWriteQueue(JackMidiSendQueue *send_queue, size_t non_rt_size=4096, size_t max_non_rt_messages=1024, size_t max_rt_messages=128); ~JackMidiRawOutputWriteQueue(); EnqueueResult EnqueueEvent(jack_nframes_t time, size_t size, jack_midi_data_t *buffer); /** * The `Process()` method should be called each time the * `EnqueueEvent()` method returns 'OK'. The `Process()` method will * return the next frame at which an event should be sent. The return * value from `Process()` depends upon the result of writing bytes to * the write queue: * * -If the return value is '0', then all events that have been enqueued * in this queue have been sent successfully to the write queue. Don't * call `Process()` again until another event has been enqueued. * * -If the return value is an earlier frame or the current frame, it * means that the write queue returned 'BUFFER_FULL', 'ERROR', or * 'EVENT_EARLY' when this queue attempted to send the next byte, and * that the byte should have already been sent, or is scheduled to be * sent *now*. `Process()` should be called again when the write queue * can enqueue events again successfully. How to determine when this * will happen is left up to the caller. * * -If the return value is in the future, then `Process()` should be * called again at that time, or after another event is enqueued. */ jack_nframes_t Process(jack_nframes_t boundary_frame=0); }; } #endif