1 /*
2     Copyright (C) 2008 - 2016 Christian Schoenebeck
3  */
4 
5 #ifndef LS_VIRTUALMIDIDEVICE_H
6 #define LS_VIRTUALMIDIDEVICE_H
7 
8 #include "../../common/global.h"
9 
10 namespace LinuxSampler {
11 
12 /**
13  * Light-weight MIDI interface (for MIDI in & out) intended to be used by
14  * pure software MIDI "devices", that is e.g. a graphical virtual MIDI
15  * keyboard in an instrument editor or in a sampler frontend. This class
16  * should not be used for regular MIDI input device drivers for the sampler.
17  * This primitive interface by design doesn't care about jitter, fast event
18  * delivery or masses and masses of events in a short time!
19  */
20 class VirtualMidiDevice {
21 public:
22     enum event_type_t {
23         EVENT_TYPE_NOTEON  = 1,
24         EVENT_TYPE_NOTEOFF = 2,
25         EVENT_TYPE_CC      = 3,
26         EVENT_TYPE_PITCHBEND,
27         EVENT_TYPE_PROGRAM,
28         EVENT_TYPE_CHPRESSURE,
29     };
30 
31     struct event_t {
32         event_type_t Type;
33         uint8_t      Arg1; ///< Depends on @c Type (e.g. key number for note on/off events).
34         uint8_t      Arg2; ///< Depends on @c Type (e.g. velocity for note on/off events).
35     };
36 
37     /////////////////////////////////////////////////////////////////
38     // Device methods
39     //     (called by the VirtualMidiDevice implementation)
40 
41     /**
42      * Sends a MIDI @e note @e on event to the sampler.
43      *
44      * @returns true on success, false if internal FIFO full
45      *          (or provided values invalid)
46      */
47     bool SendNoteOnToSampler(uint8_t Key, uint8_t Velocity);
48 
49     /**
50      * Sends a MIDI @e note @e off event to the sampler.
51      *
52      * @returns true on success, false if internal FIFO full
53      *          (or provided values invalid)
54      */
55     bool SendNoteOffToSampler(uint8_t Key, uint8_t Velocity);
56 
57     /**
58      * Sends a MIDI @e Control @e Change event to the sampler.
59      *
60      * @returns true on success, false if internal FIFO full
61      *          (or provided values invalid)
62      */
63     bool SendCCToSampler(uint8_t Controller, uint8_t Value);
64 
65     /**
66      * Sends a MIDI @e Channel @e Pressure (aftertouch) event to the sampler.
67      *
68      * @returns true on success, false if internal FIFO full
69      *          (or provided value invalid)
70      */
71     bool SendChannelPressureToSampler(uint8_t Pressure);
72 
73     /**
74      * Sends a MIDI @e Pitch @e Bend event to the sampler.
75      *
76      * @param Pitch - MIDI pitch value (-8192 ... +8191)
77      *
78      * @returns true on success, false if internal FIFO full
79      *          (or provided pitch value out of valid range)
80      */
81     bool SendPitchBendToSampler(int Pitch);
82 
83     /**
84      * Sends a MIDI @e Program @e Change event to the sampler.
85      *
86      * If you want to change the sound bank, call SendCCToSampler() (with
87      * controller = 0 for bank select MSB and/or controller = 32 for bank select
88      * LSB) before calling this method.
89      *
90      * @param Program - MIDI program number
91      *
92      * @returns true on success, false if internal FIFO full
93      *          (or provided value invalid)
94      */
95     bool SendProgramChangeToSampler(uint8_t Program);
96 
97     /**
98      * Can be called by the virtual MIDI device to check whether a new note
99      * on or note off MIDI event arrived to the sampler during the last
100      * call to this method. So this is a asynchronously, "polling" based
101      * communication mechanism, which works in conjunction with the
102      * NoteIsActive() method call.
103      */
104     bool NotesChanged();
105 
106     /**
107      * Can be called by the virtual MIDI device to check whether a new note
108      * on or note off MIDI event arrived to the sampler for @a Key during
109      * the last call to this method. So this is a asynchronously,
110      * "polling" based communication mechanism, which works in
111      * conjunction with the NoteIsActive() method call.
112      */
113     bool NoteChanged(uint8_t Key);
114 
115     /**
116      * Can be called by the virtual MIDI device to check which key / note
117      * is currently active by the sampler, e.g. to highlight the
118      * respective keys on a graphical virtual keyboard.
119      *
120      * @see NotesChanged(), NoteChanged()
121      */
122     bool NoteIsActive(uint8_t Key);
123 
124     /**
125      * Returns the velocity of the @e last note on event. No FIFO is used!
126      */
127     uint8_t NoteOnVelocity(uint8_t Key);
128 
129     /**
130      * Returns the velocity of the @e last note off event. No FIFO is used!
131      */
132     uint8_t NoteOffVelocity(uint8_t Key);
133 
134     /**
135      * Can be called by the virtual MIDI device to check whether a Control
136      * Change MIDI event arrived to the sampler during the last
137      * call to this method. So this is a asynchronously, "polling" based
138      * communication mechanism, which works in conjunction with the
139      * ControllerValue() method call.
140      */
141     bool ControllersChanged();
142 
143     /**
144      * Can be called by the virtual MIDI device to check whether a Control
145      * Change MIDI event arrived to the sampler for @a Controller during
146      * the last call to this method. So this is a asynchronously,
147      * "polling" based communication mechanism, which works in
148      * conjunction with the ControllerValue() method call.
149      */
150     bool ControllerChanged(uint8_t Controller);
151 
152     /**
153      * Returns the value of the @e last Control Change event. No FIFO is used!
154      */
155     uint8_t ControllerValue(uint8_t Controller);
156 
157     /////////////////////////////////////////////////////////////////
158     // Sampler methods
159     //     (usually only called by the Sampler)
160 
161     /**
162      * Informs the virtual MIDI device that a @e note @e on event occured
163      * (e.g. caused by a MIDI keyboard connected to the sampler).
164      * Communication acts asynchronously, that is this method call doesn't
165      * lock in any way and returns immediately. It is thus realtime safe.
166      *
167      * @e Note: this method is usually only called by the sampler.
168      *
169      * @see ActiveNotesChanged(), NoteIsActive()
170      */
171     void SendNoteOnToDevice(uint8_t Key, uint8_t Velocity);
172 
173     /**
174      * Informs the virtual MIDI device that a @e note @e off event occured
175      * (e.g. caused by a MIDI keyboard connected to the sampler).
176      * Communication acts asynchronously, that is this method call doesn't
177      * lock in any way and returns immediately. It is thus realtime safe.
178      *
179      * @e Note: this method is usually only called by the sampler.
180      *
181      * @see ActiveNotesChanged(), NoteIsActive()
182      */
183     void SendNoteOffToDevice(uint8_t Key, uint8_t Velocity);
184 
185     /**
186      * Informs the virtual MIDI device that a @e Control @e Change event
187      * occured (e.g. caused by a MIDI keyboard connected to the sampler).
188      * Communication acts asynchronously, that is this method call doesn't
189      * lock in any way and returns immediately. It is thus realtime safe.
190      *
191      * @e Note: this method is usually only called by the sampler.
192      *
193      * @see ControllersChanged(), ControllerValue()
194      */
195     void SendCCToDevice(uint8_t Controller, uint8_t Value);
196 
197     /**
198      * Gets the next pending MIDI event from the virtual MIDI device by
199      * using a lockfree FIFO.
200      *
201      * @e Note: this method is usually only called by the sampler.
202      *
203      * @param Event - destination for writing the next event to
204      * @returns true on success, false if no event pending
205      */
206     bool GetMidiEventFromDevice(event_t& Event);
207 
208     /////////////////////////////////////////////////////////////////
209     // General Purpose Methods
210 
211     /**
212      * Adjusts the internal event buffer to cover at least the given
213      * amount of MIDI events. This might be useful, since the internal
214      * event buffer is by default quite small (i.e. just 12 events).
215      *
216      * This method is not thread safe! Any operations upon this device
217      * have to be stopped before calling this method!
218      */
219     void SetMaxEvents(int n);
220 
221     /**
222      * Constructor
223      */
224     VirtualMidiDevice();
225 
226     /**
227      * Destructor
228      */
229     virtual ~VirtualMidiDevice();
230 
231 private:
232     struct private_data_t;
233     private_data_t* const p;
234 };
235 
236 } // namespace LinuxSampler
237 
238 #endif // LS_VIRTUALMIDIDEVICE_H
239