summaryrefslogtreecommitdiff
path: root/common/JackMidiRawInputWriteQueue.h
blob: 32573d0f9c52301e2dd678566b8242be906bd446 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
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 __JackMidiRawInputWriteQueue__
#define __JackMidiRawInputWriteQueue__

#include "JackMidiAsyncQueue.h"
#include "JackMidiWriteQueue.h"

namespace Jack {

    /**
     * This queue enqueues raw, unparsed MIDI packets, and outputs complete
     * MIDI messages to a write queue.
     *
     * Use this queue if the MIDI API you're interfacing with gives you raw
     * MIDI bytes that must be parsed.
     */

    class SERVER_EXPORT JackMidiRawInputWriteQueue: public JackMidiWriteQueue {

    private:

        jack_midi_event_t event;
        jack_midi_data_t event_byte;
        bool event_pending;
        size_t expected_bytes;
        jack_midi_data_t *input_buffer;
        size_t input_buffer_size;
        jack_midi_event_t *packet;
        JackMidiAsyncQueue *packet_queue;
        jack_midi_data_t status_byte;
        size_t total_bytes;
        size_t unbuffered_bytes;
        JackMidiWriteQueue *write_queue;

        void
        Clear();

        bool
        PrepareBufferedEvent(jack_nframes_t time);

        bool
        PrepareByteEvent(jack_nframes_t time, jack_midi_data_t byte);

        void
        PrepareEvent(jack_nframes_t time, size_t size,
                     jack_midi_data_t *buffer);

        bool
        ProcessByte(jack_nframes_t time, jack_midi_data_t byte);

        void
        RecordByte(jack_midi_data_t byte);

        bool
        WriteEvent(jack_nframes_t boundary_frame);

    protected:

        /**
         * Override this method to specify what happens when there isn't enough
         * room in the ringbuffer to contain a parsed event.  The default
         * method outputs an error message.
         */

        virtual void
        HandleBufferFailure(size_t unbuffered_bytes, size_t total_bytes);

        /**
         * Override this method to specify what happens when a parsed event
         * can't be written to the write queue because the event's size exceeds
         * the total possible space in the write queue.  The default method
         * outputs an error message.
         */

        virtual void
        HandleEventLoss(jack_midi_event_t *event);

        /**
         * Override this method to specify what happens when an incomplete MIDI
         * message is parsed.  The default method outputs an error message.
         */

        virtual void
        HandleIncompleteMessage(size_t total_bytes);

        /**
         * Override this method to specify what happens when an invalid MIDI
         * status byte is parsed.  The default method outputs an error message.
         */

        virtual void
        HandleInvalidStatusByte(jack_midi_data_t byte);

        /**
         * Override this method to specify what happens when a sysex end byte
         * is parsed without first parsing a sysex begin byte.  The default
         * method outputs an error message.
         */

        virtual void
        HandleUnexpectedSysexEnd(size_t total_bytes);

    public:

        using JackMidiWriteQueue::EnqueueEvent;

        /**
         * Called to create a new raw input write queue.  The `write_queue`
         * argument is the queue to write parsed messages to.  The optional
         * `max_packets` argument specifies the number of packets that can be
         * enqueued in the internal queue.  The optional `max_packet_data`
         * argument specifies the total number of MIDI bytes that can be put in
         * the internal queue, AND the maximum size for an event that can be
         * written to the write queue.
         */

        JackMidiRawInputWriteQueue(JackMidiWriteQueue *write_queue,
                                   size_t max_packet_data=4096,
                                   size_t max_packets=1024);

        ~JackMidiRawInputWriteQueue();

        EnqueueResult
        EnqueueEvent(jack_nframes_t time, size_t size,
                     jack_midi_data_t *buffer);

        /**
         * Returns the maximum size event that can be enqueued right *now*.
         */

        size_t
        GetAvailableSpace();

        /**
         * 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 *complete* events have been
         * sent successfully to the write queue.  Don't call `Process()` again
         * until another event has been enqueued.
         *
         * -If the return value is a non-zero value, then it specifies the
         * frame that a pending event is scheduled to sent at.  If the frame is
         * in the future, then `Process()` should be called again at that time;
         * otherwise, `Process()` should be called as soon as the write queue
         * will accept events again.
         */

        jack_nframes_t
        Process(jack_nframes_t boundary_frame=0);

    };

}

#endif