|  | /*
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
 |