3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005 Christian Schoenebeck * |
* Copyright (C) 2005 - 2012 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
26 |
|
|
27 |
#include "../../common/global.h" |
#include "../../common/global.h" |
28 |
#include "../../common/Mutex.h" |
#include "../../common/Mutex.h" |
29 |
#include "../../common/LinuxSamplerException.h" |
#include "../../common/Exception.h" |
30 |
#include "../DeviceParameter.h" |
#include "../DeviceParameter.h" |
31 |
#include "midi.h" |
#include "midi.h" |
32 |
#include "MidiInputDevice.h" |
#include "MidiInputDevice.h" |
33 |
#include "../../engines/common/EngineChannel.h" |
#include "../../engines/EngineChannel.h" |
34 |
#include "../../common/SynchronizedConfig.h" |
#include "../../common/SynchronizedConfig.h" |
35 |
|
|
36 |
namespace LinuxSampler { |
namespace LinuxSampler { |
38 |
// just symbol prototyping |
// just symbol prototyping |
39 |
class MidiInputDevice; |
class MidiInputDevice; |
40 |
class EngineChannel; |
class EngineChannel; |
41 |
|
class VirtualMidiDevice; |
42 |
|
|
43 |
class MidiInputPort { |
class MidiInputPort { |
44 |
public: |
public: |
57 |
virtual String Description(); |
virtual String Description(); |
58 |
virtual bool Fix(); |
virtual bool Fix(); |
59 |
virtual std::vector<String> PossibilitiesAsString(); |
virtual std::vector<String> PossibilitiesAsString(); |
60 |
virtual void OnSetValue(String s) throw (LinuxSamplerException); |
virtual void OnSetValue(String s) throw (Exception); |
61 |
protected: |
protected: |
62 |
MidiInputPort* pPort; |
MidiInputPort* pPort; |
63 |
}; |
}; |
69 |
// (usually not to be overriden by descendant) |
// (usually not to be overriden by descendant) |
70 |
|
|
71 |
/** |
/** |
72 |
* Connect given sampler engine with this MIDI input device. |
* Connect given sampler engine channel with this MIDI input |
73 |
* The engine can either be connected to one specific MIDI |
* device. The engine channel can either be connected to one |
74 |
* channel or all MIDI channels. If an engine gets connected |
* specific MIDI channel or all MIDI channels. If an engine |
75 |
* twice to this MIDI input device, then the engine's old |
* channel gets connected twice to this MIDI input device, then |
76 |
* connection will be detached (no matter on which MIDI channel). |
* the engine's old connection will be detached (no matter on |
77 |
|
* which MIDI channel). |
78 |
* |
* |
79 |
* @param pEngine - sampler engine |
* @param pEngineChannel - sampler engine |
80 |
* @param MidiChannel - MIDI channel to connect to |
* @param MidiChannel - MIDI channel to connect to |
81 |
* @throws MidiInputException if MidiChannel argument invalid |
* @throws MidiInputException if MidiChannel argument invalid |
82 |
*/ |
*/ |
83 |
void Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel); |
void Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel); |
84 |
|
|
85 |
/** |
/** |
86 |
* Disconnect given sampler engine from this MIDI input device. |
* Disconnect given sampler engine channel from this MIDI input |
87 |
* If the given engine was not connected with this device, |
* device. If the given engine channel was not connected with |
88 |
* nothing happens. |
* this device, nothing happens. |
89 |
* |
* |
90 |
* @param pEngine - sampler engine |
* @param pEngineChannel - sampler engine |
91 |
*/ |
*/ |
92 |
void Disconnect(EngineChannel* pEngineChannel); |
void Disconnect(EngineChannel* pEngineChannel); |
93 |
|
|
121 |
*/ |
*/ |
122 |
static bool RemoveSysexListener(Engine* engine); |
static bool RemoveSysexListener(Engine* engine); |
123 |
|
|
124 |
|
/** |
125 |
|
* Connects the given virtual MIDI device to this MIDI input |
126 |
|
* device. This can be used to listen to MIDI data arriving on |
127 |
|
* the MIDI input device's MIDI ports, e.g. to show an MIDI |
128 |
|
* activity indicator somewhere. |
129 |
|
*/ |
130 |
|
void Connect(VirtualMidiDevice* pDevice); |
131 |
|
|
132 |
|
/** |
133 |
|
* Disconnect the previously connected virtual MIDI device. |
134 |
|
*/ |
135 |
|
void Disconnect(VirtualMidiDevice* pDevice); |
136 |
|
|
137 |
|
/** |
138 |
|
* Registers the given @a filter to be applied against all note on |
139 |
|
* events, adjusting their MIDI velocity data. The vector supplied |
140 |
|
* here must exactly be either of size 128 or 0. In case the given |
141 |
|
* vector is of size 128, it will be used as lookup table by this |
142 |
|
* MIDI inpurt port to remap any incoming MIDI note on velocity |
143 |
|
* data to the respective value in that vector, or exactly: |
144 |
|
* @code |
145 |
|
* velocity = filter[velocity]; |
146 |
|
* @endcode |
147 |
|
* Accordingly the values in the vector have to be in the range |
148 |
|
* 0..127, however note that a value 0 should actually never be |
149 |
|
* used, since by MIDI specification, a note on with velocity 0 is |
150 |
|
* interpreted as note off event instead! |
151 |
|
* |
152 |
|
* If a vector of size 0 is supplied, this note on velocity filter |
153 |
|
* mechanism will be disabled. |
154 |
|
* |
155 |
|
* @param filter - lookup table in the format described above |
156 |
|
* @throws MidiInputException - if filter is in invalid format |
157 |
|
*/ |
158 |
|
void SetNoteOnVelocityFilter(const std::vector<uint8_t>& filter); |
159 |
|
|
160 |
|
|
161 |
///////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////// |
162 |
// dispatch methods |
// dispatch methods |
168 |
* event to be forwarded to all connected engines on the |
* event to be forwarded to all connected engines on the |
169 |
* corresponding MIDI channel. |
* corresponding MIDI channel. |
170 |
* |
* |
171 |
|
* This method is meant for realtime rendering, this way an event |
172 |
|
* is immediately created with the current system time as time |
173 |
|
* stamp. |
174 |
|
* |
175 |
* @param Key - MIDI key number of the triggered key |
* @param Key - MIDI key number of the triggered key |
176 |
* @param Velocity - MIDI velocity of the triggered key |
* @param Velocity - MIDI velocity of the triggered key |
177 |
* @param MidiChannel - MIDI channel on which event occured on |
* @param MidiChannel - MIDI channel on which event occured on |
181 |
|
|
182 |
/** |
/** |
183 |
* Should be called by the implementing MIDI input device |
* Should be called by the implementing MIDI input device |
184 |
|
* whenever a note on event arrived, this will cause the note on |
185 |
|
* event to be forwarded to all connected engines on the |
186 |
|
* corresponding MIDI channel. |
187 |
|
* |
188 |
|
* This method is meant for offline rendering and / or in case the |
189 |
|
* exact fragment position of the event is already known. |
190 |
|
* |
191 |
|
* @param Key - MIDI key number of the triggered key |
192 |
|
* @param Velocity - MIDI velocity of the triggered key |
193 |
|
* @param MidiChannel - MIDI channel on which event occured on |
194 |
|
* (low level indexing, means 0..15) |
195 |
|
* @param FragmentPos - event's sample point position in the |
196 |
|
* current audio fragment |
197 |
|
*/ |
198 |
|
void DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos); |
199 |
|
|
200 |
|
/** |
201 |
|
* Should be called by the implementing MIDI input device |
202 |
* whenever a note off event arrived, this will cause the note |
* whenever a note off event arrived, this will cause the note |
203 |
* off event to be forwarded to all connected engines on the |
* off event to be forwarded to all connected engines on the |
204 |
* corresponding MIDI channel. |
* corresponding MIDI channel. |
205 |
* |
* |
206 |
|
* This method is meant for realtime rendering, this way an event |
207 |
|
* is immediately created with the current system time as time |
208 |
|
* stamp. |
209 |
|
* |
210 |
* @param Key - MIDI key number of the released key |
* @param Key - MIDI key number of the released key |
211 |
* @param Velocity - MIDI velocity of the released key |
* @param Velocity - MIDI velocity of the released key |
212 |
* @param MidiChannel - MIDI channel on which event occured on |
* @param MidiChannel - MIDI channel on which event occured on |
216 |
|
|
217 |
/** |
/** |
218 |
* Should be called by the implementing MIDI input device |
* Should be called by the implementing MIDI input device |
219 |
|
* whenever a note off event arrived, this will cause the note |
220 |
|
* off event to be forwarded to all connected engines on the |
221 |
|
* corresponding MIDI channel. |
222 |
|
* |
223 |
|
* This method is meant for offline rendering and / or in case the |
224 |
|
* exact fragment position of the event is already known. |
225 |
|
* |
226 |
|
* @param Key - MIDI key number of the released key |
227 |
|
* @param Velocity - MIDI velocity of the released key |
228 |
|
* @param MidiChannel - MIDI channel on which event occured on |
229 |
|
* (low level indexing, means 0..15) |
230 |
|
* @param FragmentPos - event's sample point position in the |
231 |
|
* current audio fragment |
232 |
|
*/ |
233 |
|
void DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos); |
234 |
|
|
235 |
|
/** |
236 |
|
* Should be called by the implementing MIDI input device |
237 |
* whenever a pitchbend event arrived, this will cause the |
* whenever a pitchbend event arrived, this will cause the |
238 |
* pitchbend event to be forwarded to all connected engines. |
* pitchbend event to be forwarded to all connected engines. |
239 |
* |
* |
240 |
|
* This method is meant for realtime rendering, this way an event |
241 |
|
* is immediately created with the current system time as time |
242 |
|
* stamp. |
243 |
|
* |
244 |
* @param Pitch - MIDI pitch value |
* @param Pitch - MIDI pitch value |
245 |
* @param MidiChannel - MIDI channel on which event occured on |
* @param MidiChannel - MIDI channel on which event occured on |
246 |
* (low level indexing, means 0..15) |
* (low level indexing, means 0..15) |
249 |
|
|
250 |
/** |
/** |
251 |
* Should be called by the implementing MIDI input device |
* Should be called by the implementing MIDI input device |
252 |
|
* whenever a pitchbend event arrived, this will cause the |
253 |
|
* pitchbend event to be forwarded to all connected engines. |
254 |
|
* |
255 |
|
* This method is meant for offline rendering and / or in case the |
256 |
|
* exact fragment position of the event is already known. |
257 |
|
* |
258 |
|
* @param Pitch - MIDI pitch value |
259 |
|
* @param MidiChannel - MIDI channel on which event occured on |
260 |
|
* (low level indexing, means 0..15) |
261 |
|
* @param FragmentPos - event's sample point position in the |
262 |
|
* current audio fragment |
263 |
|
*/ |
264 |
|
void DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos); |
265 |
|
|
266 |
|
/** |
267 |
|
* Should be called by the implementing MIDI input device |
268 |
* whenever a control change event arrived, this will cause the |
* whenever a control change event arrived, this will cause the |
269 |
* control change event to be forwarded to all engines on the |
* control change event to be forwarded to all engines on the |
270 |
* corresponding MIDI channel. |
* corresponding MIDI channel. |
271 |
* |
* |
272 |
|
* This method is meant for realtime rendering, this way an event |
273 |
|
* is immediately created with the current system time as time |
274 |
|
* stamp. |
275 |
|
* |
276 |
* @param Controller - MIDI controller number |
* @param Controller - MIDI controller number |
277 |
* @param Value - MIDI control change value |
* @param Value - MIDI control change value |
278 |
* @param MidiChannel - MIDI channel on which event occured on |
* @param MidiChannel - MIDI channel on which event occured on |
282 |
|
|
283 |
/** |
/** |
284 |
* Should be called by the implementing MIDI input device |
* Should be called by the implementing MIDI input device |
285 |
* whenever a program change event arrived, this will cause the |
* whenever a control change event arrived, this will cause the |
286 |
* appropriate sampler channel to be connected with this MIDI |
* control change event to be forwarded to all engines on the |
287 |
* device. |
* corresponding MIDI channel. |
288 |
* |
* |
289 |
* For example consider a program change event on MIDI channel |
* This method is meant for offline rendering and / or in case the |
290 |
* 3 for program number 18. This would cause this MIDI input |
* exact fragment position of the event is already known. |
291 |
* device to be connected to sampler channel 18 and would cause |
* |
292 |
* sampler channel 18 to listen to MIDI channel 3. |
* @param Controller - MIDI controller number |
293 |
* |
* @param Value - MIDI control change value |
294 |
* This is the current, general implementation of program |
* @param MidiChannel - MIDI channel on which event occured on |
295 |
* change events. It might change in future, e.g to allow |
* (low level indexing, means 0..15) |
296 |
* sampler engines to allow by themselfes how to act on a |
* @param FragmentPos - event's sample point position in the |
297 |
* program change event. |
* current audio fragment |
298 |
* |
*/ |
299 |
* @param Program - sampler channel to connect to this MIDI |
void DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos); |
300 |
* input device |
|
301 |
* @param MidiChannel - MIDI channel on which sampler channel |
/** |
302 |
* \a Program should listen to |
* Should be called by the implementing MIDI input device |
303 |
|
* whenever a program change event arrived. In case the |
304 |
|
* respective sampler channel(s) are enabled for MIDI |
305 |
|
* instrument mapping, the respective sampler engine and |
306 |
|
* instrument will be loaded on the connected sampler |
307 |
|
* channel(s) as defined by the respective entry in the |
308 |
|
* MIDI instrument map. |
309 |
|
* |
310 |
|
* @e Note: the MIDI instrument map is empty by default on |
311 |
|
* sampler startup. It has to be explicitly filled with |
312 |
|
* entries and the sampler channel(s) have to be enabled for |
313 |
|
* a certain MIDI instrument table, otherwise program change |
314 |
|
* messages are ignored! |
315 |
|
* |
316 |
|
* @param Program - MIDI program change number |
317 |
|
* @param MidiChannel - MIDI channel on which this program |
318 |
|
* change occured |
319 |
|
* @see MidiInstrumentMapper |
320 |
*/ |
*/ |
321 |
void DispatchProgramChange(uint8_t Program, uint MidiChannel); |
void DispatchProgramChange(uint8_t Program, uint MidiChannel); |
322 |
|
|
323 |
|
void DispatchBankSelectMsb(uint8_t BankMsb, uint MidiChannel); |
324 |
|
|
325 |
|
void DispatchBankSelectLsb(uint8_t BankLsb, uint MidiChannel); |
326 |
|
|
327 |
/** |
/** |
328 |
* Should be called by the implementing MIDI input device |
* Should be called by the implementing MIDI input device |
329 |
* whenever a system exclusive message arrived, this will cause |
* whenever a system exclusive message arrived, this will cause |
334 |
*/ |
*/ |
335 |
void DispatchSysex(void* pData, uint Size); |
void DispatchSysex(void* pData, uint Size); |
336 |
|
|
337 |
|
/** |
338 |
|
* Helper function for MIDI input devices that have the |
339 |
|
* MIDI data as raw bytes. |
340 |
|
* |
341 |
|
* @param pData - pointer to the raw MIDI data |
342 |
|
*/ |
343 |
|
void DispatchRaw(uint8_t* pData); |
344 |
|
|
345 |
|
/** |
346 |
|
* Helper function for MIDI input devices that have the |
347 |
|
* MIDI data as raw bytes. |
348 |
|
* |
349 |
|
* @param pData - pointer to the raw MIDI data |
350 |
|
* @param FragmentPos - event's sample point position in the |
351 |
|
* current audio fragment |
352 |
|
*/ |
353 |
|
void DispatchRaw(uint8_t* pData, int32_t FragmentPos); |
354 |
|
|
355 |
protected: |
protected: |
356 |
MidiInputDevice* pDevice; |
MidiInputDevice* pDevice; |
357 |
int portNumber; |
int portNumber; |
361 |
SynchronizedConfig<MidiChannelMap_t>::Reader MidiChannelMapReader; ///< MIDI thread access to MidiChannelMap |
SynchronizedConfig<MidiChannelMap_t>::Reader MidiChannelMapReader; ///< MIDI thread access to MidiChannelMap |
362 |
Mutex MidiChannelMapMutex; ///< Used to protect the MidiChannelMap from being used at the same time by different threads. |
Mutex MidiChannelMapMutex; ///< Used to protect the MidiChannelMap from being used at the same time by different threads. |
363 |
SynchronizedConfig<std::set<Engine*> >::Reader SysexListenersReader; ///< MIDI thread access to SysexListeners |
SynchronizedConfig<std::set<Engine*> >::Reader SysexListenersReader; ///< MIDI thread access to SysexListeners |
364 |
|
SynchronizedConfig<std::vector<VirtualMidiDevice*> > virtualMidiDevices; |
365 |
|
SynchronizedConfig<std::vector<VirtualMidiDevice*> >::Reader virtualMidiDevicesReader; |
366 |
|
Mutex virtualMidiDevicesMutex; |
367 |
|
SynchronizedConfig<std::vector<uint8_t> > noteOnVelocityFilter; |
368 |
|
SynchronizedConfig<std::vector<uint8_t> >::Reader noteOnVelocityFilterReader; |
369 |
|
Mutex noteOnVelocityFilterMutex; |
370 |
|
|
371 |
/** |
/** |
372 |
* Constructor |
* Constructor |
381 |
friend class MidiInputDevice; |
friend class MidiInputDevice; |
382 |
|
|
383 |
private: |
private: |
|
EngineChannel* pPreviousProgramChangeEngineChannel; ///< Points to the engine channel which was connected by the previous DispatchProgramChange() call. |
|
384 |
static SynchronizedConfig<std::set<Engine*> > SysexListeners; ///< All engines that are listening to sysex messages. |
static SynchronizedConfig<std::set<Engine*> > SysexListeners; ///< All engines that are listening to sysex messages. |
385 |
}; |
}; |
386 |
|
|