/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2426 - (show annotations) (download)
Fri Mar 1 23:00:17 2013 UTC (7 years, 7 months ago) by schoenebeck
File size: 28981 byte(s)
* MIDI drivers: Implemented missing handling of MIDI "running status".
* MME driver: pass time stamps to the sampler.

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2013 Christian Schoenebeck *
7 * *
8 * 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 *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include "MidiInputPort.h"
25
26 #include "../../common/global_private.h"
27 #include "MidiInstrumentMapper.h"
28 #include "../../Sampler.h"
29 #include "../../engines/EngineFactory.h"
30 #include "VirtualMidiDevice.h"
31
32 #include <algorithm>
33
34 namespace LinuxSampler {
35
36 // *************** ParameterName ***************
37 // *
38
39 MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort) : DeviceRuntimeParameterString("Port " + ToString(pPort->GetPortNumber())) {
40 this->pPort = pPort;
41 }
42
43 MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort, String val) : DeviceRuntimeParameterString(val) {
44 this->pPort = pPort;
45 }
46
47 String MidiInputPort::ParameterName::Description() {
48 return "Name for this port";
49 }
50
51 bool MidiInputPort::ParameterName::Fix() {
52 return false;
53 }
54
55 std::vector<String> MidiInputPort::ParameterName::PossibilitiesAsString() {
56 return std::vector<String>();
57 }
58
59 void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
60 return; /* FIXME: Nothing to do here */
61 }
62
63
64
65 // *************** MidiInputPort ***************
66 // *
67
68 MidiInputPort::~MidiInputPort() {
69 std::map<String,DeviceRuntimeParameter*>::iterator iter = Parameters.begin();
70 while (iter != Parameters.end()) {
71 delete iter->second;
72 iter++;
73 }
74 Parameters.clear();
75 }
76
77 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
78 : MidiChannelMapReader(MidiChannelMap),
79 SysexListenersReader(SysexListeners),
80 virtualMidiDevicesReader(virtualMidiDevices),
81 noteOnVelocityFilterReader(noteOnVelocityFilter)
82 {
83 this->pDevice = pDevice;
84 this->portNumber = portNumber;
85 runningStatusBuf[0] = 0;
86 Parameters["NAME"] = new ParameterName(this);
87 }
88
89 MidiInputDevice* MidiInputPort::GetDevice() {
90 return pDevice;
91 }
92
93 uint MidiInputPort::GetPortNumber() {
94 return portNumber;
95 }
96
97 std::map<String,DeviceRuntimeParameter*> MidiInputPort::PortParameters() {
98 return Parameters;
99 }
100
101 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
102 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
103
104 // apply velocity filter (if any)
105 const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock();
106 if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity];
107 noteOnVelocityFilterReader.Unlock();
108
109 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
110 // dispatch event for engines listening to the same MIDI channel
111 {
112 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
113 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
114 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
115 }
116 // dispatch event for engines listening to ALL MIDI channels
117 {
118 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
119 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
120 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
121 }
122 MidiChannelMapReader.Unlock();
123
124 // dispatch event to all low priority MIDI listeners
125 const std::vector<VirtualMidiDevice*>& listeners =
126 virtualMidiDevicesReader.Lock();
127 for (int i = 0; i < listeners.size(); ++i)
128 listeners[i]->SendNoteOnToDevice(Key, Velocity);
129 virtualMidiDevicesReader.Unlock();
130 }
131
132 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
133 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
134
135 // apply velocity filter (if any)
136 const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock();
137 if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity];
138 noteOnVelocityFilterReader.Unlock();
139
140 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
141 // dispatch event for engines listening to the same MIDI channel
142 {
143 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
144 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
145 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
146 }
147 // dispatch event for engines listening to ALL MIDI channels
148 {
149 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
150 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
151 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
152 }
153 MidiChannelMapReader.Unlock();
154
155 // dispatch event to all low priority MIDI listeners
156 const std::vector<VirtualMidiDevice*>& listeners =
157 virtualMidiDevicesReader.Lock();
158 for (int i = 0; i < listeners.size(); ++i)
159 listeners[i]->SendNoteOnToDevice(Key, Velocity);
160 virtualMidiDevicesReader.Unlock();
161 }
162
163 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
164 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
165 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
166 // dispatch event for engines listening to the same MIDI channel
167 {
168 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
169 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
170 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
171 }
172 // dispatch event for engines listening to ALL MIDI channels
173 {
174 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
175 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
176 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
177 }
178 MidiChannelMapReader.Unlock();
179
180 // dispatch event to all low priority MIDI listeners
181 const std::vector<VirtualMidiDevice*>& listeners =
182 virtualMidiDevicesReader.Lock();
183 for (int i = 0; i < listeners.size(); ++i)
184 listeners[i]->SendNoteOffToDevice(Key, Velocity);
185 virtualMidiDevicesReader.Unlock();
186 }
187
188 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
189 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
190 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
191 // dispatch event for engines listening to the same MIDI channel
192 {
193 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
194 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
195 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
196 }
197 // dispatch event for engines listening to ALL MIDI channels
198 {
199 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
200 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
201 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
202 }
203 MidiChannelMapReader.Unlock();
204
205 // dispatch event to all low priority MIDI listeners
206 const std::vector<VirtualMidiDevice*>& listeners =
207 virtualMidiDevicesReader.Lock();
208 for (int i = 0; i < listeners.size(); ++i)
209 listeners[i]->SendNoteOffToDevice(Key, Velocity);
210 virtualMidiDevicesReader.Unlock();
211 }
212
213 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
214 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
215 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
216 // dispatch event for engines listening to the same MIDI channel
217 {
218 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
219 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
220 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
221 }
222 // dispatch event for engines listening to ALL MIDI channels
223 {
224 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
225 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
226 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
227 }
228 MidiChannelMapReader.Unlock();
229 }
230
231 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
232 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
233 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
234 // dispatch event for engines listening to the same MIDI channel
235 {
236 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
237 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
238 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
239 }
240 // dispatch event for engines listening to ALL MIDI channels
241 {
242 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
243 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
244 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
245 }
246 MidiChannelMapReader.Unlock();
247 }
248
249 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
250 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
251 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
252 // dispatch event for engines listening to the same MIDI channel
253 {
254 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
255 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
256 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
257 }
258 // dispatch event for engines listening to ALL MIDI channels
259 {
260 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
261 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
262 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
263 }
264 MidiChannelMapReader.Unlock();
265
266 // dispatch event to all low priority MIDI listeners
267 const std::vector<VirtualMidiDevice*>& listeners =
268 virtualMidiDevicesReader.Lock();
269 for (int i = 0; i < listeners.size(); ++i)
270 listeners[i]->SendCCToDevice(Controller, Value);
271 virtualMidiDevicesReader.Unlock();
272 }
273
274 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
275 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
276 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
277 // dispatch event for engines listening to the same MIDI channel
278 {
279 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
280 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
281 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
282 }
283 // dispatch event for engines listening to ALL MIDI channels
284 {
285 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
286 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
287 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
288 }
289 MidiChannelMapReader.Unlock();
290
291 // dispatch event to all low priority MIDI listeners
292 const std::vector<VirtualMidiDevice*>& listeners =
293 virtualMidiDevicesReader.Lock();
294 for (int i = 0; i < listeners.size(); ++i)
295 listeners[i]->SendCCToDevice(Controller, Value);
296 virtualMidiDevicesReader.Unlock();
297 }
298
299 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
300 const std::set<Engine*> allEngines = SysexListenersReader.Lock();
301 // dispatch event to all engine instances
302 std::set<Engine*>::iterator engineiter = allEngines.begin();
303 std::set<Engine*>::iterator end = allEngines.end();
304 for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size, this);
305 SysexListenersReader.Unlock();
306 }
307
308 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
309 if (Program > 127 || MidiChannel > 16) return;
310 if (!pDevice || !pDevice->pSampler) {
311 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
312 << "This is a bug, please report it!\n" << std::flush;
313 return;
314 }
315
316 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
317 // dispatch event for engines listening to the same MIDI channel
318 {
319 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
320 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
321 for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
322 }
323 // dispatch event for engines listening to ALL MIDI channels
324 {
325 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
326 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
327 for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
328 }
329 MidiChannelMapReader.Unlock();
330 }
331
332 void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
333 if (BankMSB > 127 || MidiChannel > 16) return;
334 if (!pDevice || !pDevice->pSampler) {
335 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
336 << "This is a bug, please report it!\n" << std::flush;
337 return;
338 }
339 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
340 // dispatch event for engines listening to the same MIDI channel
341 {
342 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
343 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
344 // according to the MIDI specs, a bank select should not alter the patch
345 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
346 }
347 // dispatch event for engines listening to ALL MIDI channels
348 {
349 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
350 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
351 // according to the MIDI specs, a bank select should not alter the patch
352 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
353 }
354 MidiChannelMapReader.Unlock();
355 }
356
357 void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
358 if (BankLSB > 127 || MidiChannel > 16) return;
359 if (!pDevice || !pDevice->pSampler) {
360 std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
361 << "This is a bug, please report it!\n" << std::flush;
362 return;
363 }
364 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
365 // dispatch event for engines listening to the same MIDI channel
366 {
367 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
368 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
369 // according to the MIDI specs, a bank select should not alter the patch
370 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
371 }
372 // dispatch event for engines listening to ALL MIDI channels
373 {
374 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
375 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
376 // according to the MIDI specs, a bank select should not alter the patch
377 for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
378 }
379 MidiChannelMapReader.Unlock();
380 }
381
382 /**
383 * Handles the so called MIDI "running status" mode, which allows devices
384 * to reduce bandwidth (data reduction).
385 *
386 * If the passed in MIDI data is regular MIDI data, this method will simply
387 * return the original data pointer and just stores the status byte for
388 * potential "running status" event eventually coming next.
389 *
390 * If the passed in MIDI data however seems to be in "running status" mode,
391 * this method will return another buffer, which allows the MIDI parser
392 * to handle the MIDI data as usually with "normal" MIDI data.
393 */
394 uint8_t* MidiInputPort::handleRunningStatus(uint8_t* pData) {
395 if ((pData[0] & 0x80) || !runningStatusBuf[0]) {
396 // store status byte for eventual "running status" in next event
397 if (pData[0] & 0x80) {
398 if (pData[0] < 0xf0) {
399 // "running status" is only allowed for channel messages
400 runningStatusBuf[0] = pData[0];
401 } else if (pData[0] < 0xf8) {
402 // "system common" messages (0xf0..0xf7) shall reset any running
403 // status, however "realtime" messages (0xf8..0xff) shall be
404 // ignored here
405 runningStatusBuf[0] = 0;
406 }
407 }
408 // it's either a regular status byte, or some invalid "running status"
409 return pData;
410 } else { // "running status" mode ...
411 const uint8_t type = runningStatusBuf[0] & 0xf0;
412 const int size = (type == 0xc0 || type == 0xd0) ? 1 : 2; // only program change & channel pressure have 1 data bytes
413 memcpy(&runningStatusBuf[1], pData, size);
414 return runningStatusBuf;
415 }
416 }
417
418 void MidiInputPort::DispatchRaw(uint8_t* pData) {
419 pData = handleRunningStatus(pData);
420
421 uint8_t channel = pData[0] & 0x0f;
422 switch (pData[0] & 0xf0) {
423 case 0x80:
424 DispatchNoteOff(pData[1], pData[2], channel);
425 break;
426 case 0x90:
427 if (pData[2]) {
428 DispatchNoteOn(pData[1], pData[2], channel);
429 } else {
430 DispatchNoteOff(pData[1], pData[2], channel);
431 }
432 break;
433 case 0xb0:
434 if (pData[1] == 0) {
435 DispatchBankSelectMsb(pData[2], channel);
436 } else if (pData[1] == 32) {
437 DispatchBankSelectLsb(pData[2], channel);
438 }
439 DispatchControlChange(pData[1], pData[2], channel);
440 break;
441 case 0xc0:
442 DispatchProgramChange(pData[1], channel);
443 break;
444 case 0xd0:
445 DispatchControlChange(128, pData[1], channel);
446 break;
447 case 0xe0:
448 DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel);
449 break;
450 }
451 }
452
453 void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
454 pData = handleRunningStatus(pData);
455
456 uint8_t channel = pData[0] & 0x0f;
457 switch (pData[0] & 0xf0) {
458 case 0x80:
459 DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
460 break;
461 case 0x90:
462 if (pData[2]) {
463 DispatchNoteOn(pData[1], pData[2], channel, FragmentPos);
464 } else {
465 DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
466 }
467 break;
468 case 0xb0:
469 if (pData[1] == 0) {
470 DispatchBankSelectMsb(pData[2], channel);
471 } else if (pData[1] == 32) {
472 DispatchBankSelectLsb(pData[2], channel);
473 }
474 DispatchControlChange(pData[1], pData[2], channel, FragmentPos);
475 break;
476 case 0xc0:
477 DispatchProgramChange(pData[1], channel);
478 break;
479 case 0xd0:
480 DispatchControlChange(128, pData[1], channel, FragmentPos);
481 break;
482 case 0xe0:
483 DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel, FragmentPos);
484 break;
485 }
486 }
487
488 void MidiInputPort::SetNoteOnVelocityFilter(const std::vector<uint8_t>& filter) {
489 if (filter.size() != 128 && filter.size() != 0)
490 throw MidiInputException("Note on velocity filter must be either of size 128 or 0");
491
492 // check the value range of the filter
493 if (!filter.empty())
494 for (int i = 0; i < 128; i++)
495 if (filter[i] > 127)
496 throw MidiInputException("Invalid note on velocity filter, values must be in range 0 .. 127");
497
498 // apply new filter ...
499 noteOnVelocityFilterMutex.Lock();
500 // double buffer ... double work ...
501 {
502 std::vector<uint8_t>& config =
503 noteOnVelocityFilter.GetConfigForUpdate();
504 config = filter;
505 }
506 {
507 std::vector<uint8_t>& config =
508 noteOnVelocityFilter.SwitchConfig();
509 config = filter;
510 }
511 noteOnVelocityFilterMutex.Unlock();
512 }
513
514 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
515 if (MidiChannel < 0 || MidiChannel > 16)
516 throw MidiInputException("MIDI channel index out of bounds");
517
518 // first check if desired connection is already established
519 MidiChannelMapMutex.Lock();
520 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
521 bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
522 MidiChannelMapMutex.Unlock();
523 if (bAlreadyDone) return;
524
525 // remove all other connections of that engine channel (if any)
526 Disconnect(pEngineChannel);
527
528 // register engine channel on the desired MIDI channel
529 MidiChannelMapMutex.Lock();
530 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
531 MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
532 MidiChannelMapMutex.Unlock();
533
534 // inform engine channel about this connection
535 pEngineChannel->Connect(this, MidiChannel);
536
537 // mark engine channel as changed
538 pEngineChannel->StatusChanged(true);
539 }
540
541 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
542 if (!pEngineChannel) return;
543
544 bool bChannelFound = false;
545
546 // unregister engine channel from all MIDI channels
547 MidiChannelMapMutex.Lock();
548 try {
549 {
550 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
551 for (int i = 0; i <= 16; i++) {
552 bChannelFound |= midiChannelMap[i].count(pEngineChannel);
553 midiChannelMap[i].erase(pEngineChannel);
554 }
555 }
556 // do the same update again, after switching to the other config
557 {
558 MidiChannelMap_t& midiChannelMap = MidiChannelMap.SwitchConfig();
559 for (int i = 0; i <= 16; i++) {
560 bChannelFound |= midiChannelMap[i].count(pEngineChannel);
561 midiChannelMap[i].erase(pEngineChannel);
562 }
563 }
564 }
565 catch(...) { /* NOOP */ }
566 MidiChannelMapMutex.Unlock();
567
568 // inform engine channel about the disconnection (if there is one)
569 if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
570
571 // mark engine channel as changed
572 pEngineChannel->StatusChanged(true);
573 }
574
575 SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
576
577 void MidiInputPort::AddSysexListener(Engine* engine) {
578 std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
579 if (p.second) SysexListeners.SwitchConfig().insert(engine);
580 }
581
582 bool MidiInputPort::RemoveSysexListener(Engine* engine) {
583 int count = SysexListeners.GetConfigForUpdate().erase(engine);
584 if (count) SysexListeners.SwitchConfig().erase(engine);
585 return count;
586 }
587
588 void MidiInputPort::Connect(VirtualMidiDevice* pDevice) {
589 virtualMidiDevicesMutex.Lock();
590 // double buffer ... double work ...
591 {
592 std::vector<VirtualMidiDevice*>& devices =
593 virtualMidiDevices.GetConfigForUpdate();
594 devices.push_back(pDevice);
595 }
596 {
597 std::vector<VirtualMidiDevice*>& devices =
598 virtualMidiDevices.SwitchConfig();
599 devices.push_back(pDevice);
600 }
601 virtualMidiDevicesMutex.Unlock();
602 }
603
604 void MidiInputPort::Disconnect(VirtualMidiDevice* pDevice) {
605 virtualMidiDevicesMutex.Lock();
606 // double buffer ... double work ...
607 {
608 std::vector<VirtualMidiDevice*>& devices =
609 virtualMidiDevices.GetConfigForUpdate();
610 devices.erase(std::find(devices.begin(), devices.end(), pDevice));
611 }
612 {
613 std::vector<VirtualMidiDevice*>& devices =
614 virtualMidiDevices.SwitchConfig();
615 devices.erase(std::find(devices.begin(), devices.end(), pDevice));
616 }
617 virtualMidiDevicesMutex.Unlock();
618 }
619
620 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC