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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2427 - (hide annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years ago) by persson
File size: 28819 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

1 schoenebeck 221 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 2426 * Copyright (C) 2005 - 2013 Christian Schoenebeck *
7 schoenebeck 221 * *
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 schoenebeck 1424 #include "../../common/global_private.h"
27 schoenebeck 947 #include "MidiInstrumentMapper.h"
28 schoenebeck 551 #include "../../Sampler.h"
29 schoenebeck 775 #include "../../engines/EngineFactory.h"
30 schoenebeck 1695 #include "VirtualMidiDevice.h"
31 schoenebeck 551
32 schoenebeck 1695 #include <algorithm>
33    
34 schoenebeck 221 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 schoenebeck 880 void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
60 schoenebeck 221 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 persson 836 Parameters.clear();
75 schoenebeck 221 }
76    
77 persson 846 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
78     : MidiChannelMapReader(MidiChannelMap),
79 schoenebeck 1695 SysexListenersReader(SysexListeners),
80 schoenebeck 2380 virtualMidiDevicesReader(virtualMidiDevices),
81     noteOnVelocityFilterReader(noteOnVelocityFilter)
82     {
83 schoenebeck 221 this->pDevice = pDevice;
84     this->portNumber = portNumber;
85 schoenebeck 2426 runningStatusBuf[0] = 0;
86 schoenebeck 221 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 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
103 schoenebeck 2380
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 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
110 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
111     {
112 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
113     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
114 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
115 schoenebeck 274 }
116     // dispatch event for engines listening to ALL MIDI channels
117     {
118 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
119     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
120 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
121 schoenebeck 274 }
122 persson 846 MidiChannelMapReader.Unlock();
123 schoenebeck 1695
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 schoenebeck 221 }
131    
132 schoenebeck 906 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
133 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
134 schoenebeck 2380
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 schoenebeck 906 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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
146 schoenebeck 906 }
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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
152 schoenebeck 906 }
153     MidiChannelMapReader.Unlock();
154 schoenebeck 1695
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 schoenebeck 906 }
162    
163 schoenebeck 221 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
164 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
165 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
166 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
167     {
168 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
169     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
170 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
171 schoenebeck 274 }
172     // dispatch event for engines listening to ALL MIDI channels
173     {
174 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
175     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
176 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
177 schoenebeck 274 }
178 persson 846 MidiChannelMapReader.Unlock();
179 schoenebeck 1695
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 schoenebeck 221 }
187    
188 schoenebeck 906 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
189 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
190 schoenebeck 906 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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
196 schoenebeck 906 }
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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
202 schoenebeck 906 }
203     MidiChannelMapReader.Unlock();
204 schoenebeck 1695
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 schoenebeck 906 }
212    
213 schoenebeck 221 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
214 persson 922 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
215 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
216 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
217     {
218 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
219     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
220 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
221 schoenebeck 274 }
222     // dispatch event for engines listening to ALL MIDI channels
223     {
224 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
225     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
226 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
227 schoenebeck 274 }
228 persson 846 MidiChannelMapReader.Unlock();
229 schoenebeck 221 }
230    
231 schoenebeck 906 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
232 persson 922 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
233 schoenebeck 906 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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
239 schoenebeck 906 }
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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
245 schoenebeck 906 }
246     MidiChannelMapReader.Unlock();
247     }
248    
249 schoenebeck 221 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
250 persson 922 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
251 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
252 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
253     {
254 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
255     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
256 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
257 schoenebeck 274 }
258     // dispatch event for engines listening to ALL MIDI channels
259     {
260 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
261     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
262 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
263 schoenebeck 274 }
264 persson 846 MidiChannelMapReader.Unlock();
265 schoenebeck 2025
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 schoenebeck 221 }
273    
274 schoenebeck 906 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
275 persson 922 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
276 schoenebeck 906 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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
282 schoenebeck 906 }
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 persson 2317 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
288 schoenebeck 906 }
289     MidiChannelMapReader.Unlock();
290 schoenebeck 2025
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 schoenebeck 906 }
298    
299 schoenebeck 244 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
300 persson 846 const std::set<Engine*> allEngines = SysexListenersReader.Lock();
301 schoenebeck 775 // dispatch event to all engine instances
302 persson 846 std::set<Engine*>::iterator engineiter = allEngines.begin();
303     std::set<Engine*>::iterator end = allEngines.end();
304 schoenebeck 1751 for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size, this);
305 persson 846 SysexListenersReader.Unlock();
306 schoenebeck 244 }
307    
308 schoenebeck 670 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
309 persson 922 if (Program > 127 || MidiChannel > 16) return;
310 schoenebeck 551 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 schoenebeck 973
316 schoenebeck 947 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 persson 1924 for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
322 schoenebeck 947 }
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 persson 1924 for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
328 schoenebeck 947 }
329     MidiChannelMapReader.Unlock();
330     }
331 schoenebeck 551
332 schoenebeck 947 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 schoenebeck 551
357 schoenebeck 947 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 schoenebeck 551 }
364 schoenebeck 947 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 schoenebeck 551 }
381 schoenebeck 2426
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 schoenebeck 551
418 persson 1887 void MidiInputPort::DispatchRaw(uint8_t* pData) {
419 schoenebeck 2426 pData = handleRunningStatus(pData);
420    
421 persson 1887 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 persson 1765 void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
454 schoenebeck 2426 pData = handleRunningStatus(pData);
455    
456 persson 1765 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 persson 1887 DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel, FragmentPos);
484 persson 1765 break;
485     }
486     }
487 schoenebeck 2380
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 persson 2427 LockGuard lock(noteOnVelocityFilterMutex);
500 schoenebeck 2380 // 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     }
512 persson 1765
513 schoenebeck 411 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
514 schoenebeck 221 if (MidiChannel < 0 || MidiChannel > 16)
515     throw MidiInputException("MIDI channel index out of bounds");
516 schoenebeck 670
517 persson 840 // first check if desired connection is already established
518 persson 2427 {
519     LockGuard lock(MidiChannelMapMutex);
520     MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
521     if (midiChannelMap[MidiChannel].count(pEngineChannel)) return;
522     }
523 schoenebeck 675
524     // remove all other connections of that engine channel (if any)
525 schoenebeck 411 Disconnect(pEngineChannel);
526 schoenebeck 670
527 schoenebeck 675 // register engine channel on the desired MIDI channel
528 persson 2427 {
529     LockGuard lock(MidiChannelMapMutex);
530     MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
531     MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
532     }
533 schoenebeck 670
534 schoenebeck 675 // inform engine channel about this connection
535     pEngineChannel->Connect(this, MidiChannel);
536    
537 schoenebeck 670 // mark engine channel as changed
538     pEngineChannel->StatusChanged(true);
539 schoenebeck 221 }
540    
541 schoenebeck 411 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
542 schoenebeck 675 if (!pEngineChannel) return;
543    
544     bool bChannelFound = false;
545    
546     // unregister engine channel from all MIDI channels
547     try {
548 persson 2427 LockGuard lock(MidiChannelMapMutex);
549 persson 840 {
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 schoenebeck 675 }
556 persson 840 // 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 schoenebeck 675 }
565 schoenebeck 221 catch(...) { /* NOOP */ }
566 schoenebeck 675
567     // inform engine channel about the disconnection (if there is one)
568     if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
569    
570 schoenebeck 670 // mark engine channel as changed
571     pEngineChannel->StatusChanged(true);
572 schoenebeck 221 }
573    
574 persson 846 SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
575    
576     void MidiInputPort::AddSysexListener(Engine* engine) {
577     std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
578     if (p.second) SysexListeners.SwitchConfig().insert(engine);
579     }
580    
581     bool MidiInputPort::RemoveSysexListener(Engine* engine) {
582     int count = SysexListeners.GetConfigForUpdate().erase(engine);
583     if (count) SysexListeners.SwitchConfig().erase(engine);
584     return count;
585     }
586    
587 schoenebeck 1695 void MidiInputPort::Connect(VirtualMidiDevice* pDevice) {
588 persson 2427 LockGuard lock(virtualMidiDevicesMutex);
589 schoenebeck 1695 // double buffer ... double work ...
590     {
591     std::vector<VirtualMidiDevice*>& devices =
592     virtualMidiDevices.GetConfigForUpdate();
593     devices.push_back(pDevice);
594     }
595     {
596     std::vector<VirtualMidiDevice*>& devices =
597     virtualMidiDevices.SwitchConfig();
598     devices.push_back(pDevice);
599     }
600     }
601    
602     void MidiInputPort::Disconnect(VirtualMidiDevice* pDevice) {
603 persson 2427 LockGuard lock(virtualMidiDevicesMutex);
604 schoenebeck 1695 // double buffer ... double work ...
605     {
606     std::vector<VirtualMidiDevice*>& devices =
607     virtualMidiDevices.GetConfigForUpdate();
608     devices.erase(std::find(devices.begin(), devices.end(), pDevice));
609     }
610     {
611     std::vector<VirtualMidiDevice*>& devices =
612     virtualMidiDevices.SwitchConfig();
613     devices.erase(std::find(devices.begin(), devices.end(), pDevice));
614     }
615     }
616    
617 schoenebeck 221 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC