1 /*
2 Copyright (C) 2010 Devin Anderson
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #ifndef __JackMidiRawOutputWriteQueue__
21 #define __JackMidiRawOutputWriteQueue__
22 
23 #include "JackMidiAsyncQueue.h"
24 #include "JackMidiSendQueue.h"
25 
26 namespace Jack {
27 
28     /**
29      * This queue enqueues valid MIDI events and modifies them for raw output
30      * to a write queue.  It has a couple of advantages over straight MIDI
31      * event copying:
32      *
33      * -Running status: Status bytes can be omitted when the status byte of the
34      * current MIDI message is the same as the status byte of the last sent
35      * MIDI message.
36      *
37      * -Realtime messages: Realtime messages are given priority over
38      * non-realtime messages.  Realtime bytes are interspersed with
39      * non-realtime bytes so that realtime messages can be sent as close as
40      * possible to the time they're scheduled for sending.
41      *
42      * Use this queue if the MIDI API you're interfacing with allows you to
43      * send raw MIDI bytes.
44      */
45 
46     class SERVER_EXPORT JackMidiRawOutputWriteQueue:
47         public JackMidiWriteQueue {
48 
49     private:
50 
51         jack_midi_event_t *non_rt_event;
52         jack_nframes_t non_rt_event_time;
53         JackMidiAsyncQueue *non_rt_queue;
54         jack_midi_event_t *rt_event;
55         jack_nframes_t rt_event_time;
56         JackMidiAsyncQueue *rt_queue;
57         jack_midi_data_t running_status;
58         JackMidiSendQueue *send_queue;
59 
60         void
61         DequeueNonRealtimeEvent();
62 
63         void
64         DequeueRealtimeEvent();
65 
66         bool
67         SendByte(jack_nframes_t time, jack_midi_data_t byte);
68 
69         bool
70         SendNonRTBytes(jack_nframes_t boundary_frame);
71 
72     protected:
73 
74         /**
75          * Override this method to specify what happens when the write queue
76          * says that a 1-byte event is too large for its buffer.  Basically,
77          * this should never happen.
78          */
79 
80         virtual void
81         HandleWriteQueueBug(jack_nframes_t time, jack_midi_data_t byte);
82 
83     public:
84 
85         using JackMidiWriteQueue::EnqueueEvent;
86 
87         /**
88          * Called to create a new raw write queue.  The `send_queue` argument
89          * is the queue to write raw bytes to.  The optional `max_rt_messages`
90          * argument specifies the number of messages that can be enqueued in
91          * the internal realtime queue.  The optional `max_non_rt_messages`
92          * argument specifies the number of messages that can be enqueued in
93          * the internal non-realtime queue.  The optional `non_rt_size`
94          * argument specifies the total number of MIDI bytes that can be put in
95          * the non-realtime queue.
96          */
97 
98         JackMidiRawOutputWriteQueue(JackMidiSendQueue *send_queue,
99                                     size_t non_rt_size=4096,
100                                     size_t max_non_rt_messages=1024,
101                                     size_t max_rt_messages=128);
102 
103         ~JackMidiRawOutputWriteQueue();
104 
105         EnqueueResult
106         EnqueueEvent(jack_nframes_t time, size_t size,
107                      jack_midi_data_t *buffer);
108 
109         /**
110          * The `Process()` method should be called each time the
111          * `EnqueueEvent()` method returns 'OK'.  The `Process()` method will
112          * return the next frame at which an event should be sent.  The return
113          * value from `Process()` depends upon the result of writing bytes to
114          * the write queue:
115          *
116          * -If the return value is '0', then all events that have been enqueued
117          * in this queue have been sent successfully to the write queue.  Don't
118          * call `Process()` again until another event has been enqueued.
119          *
120          * -If the return value is an earlier frame or the current frame, it
121          * means that the write queue returned 'BUFFER_FULL', 'ERROR', or
122          * 'EVENT_EARLY' when this queue attempted to send the next byte, and
123          * that the byte should have already been sent, or is scheduled to be
124          * sent *now*.  `Process()` should be called again when the write queue
125          * can enqueue events again successfully.  How to determine when this
126          * will happen is left up to the caller.
127          *
128          * -If the return value is in the future, then `Process()` should be
129          * called again at that time, or after another event is enqueued.
130          */
131 
132         jack_nframes_t
133         Process(jack_nframes_t boundary_frame=0);
134 
135     };
136 
137 }
138 
139 #endif
140