/[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 973 - (hide annotations) (download)
Fri Dec 15 21:40:27 2006 UTC (17 years, 4 months ago) by schoenebeck
File size: 22531 byte(s)
* revised and extended MIDI instrument mapping feature to allow managing
  arbitrary amount of maps and assigning each sampler channel individually
  to one map (this commit batch includes LSCP spec document update and
  respective implementation on LS side)

1 schoenebeck 221 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 880 * Copyright (C) 2005, 2006 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 947 #include "MidiInstrumentMapper.h"
27 schoenebeck 551 #include "../../Sampler.h"
28 schoenebeck 775 #include "../../engines/EngineFactory.h"
29 schoenebeck 551
30 schoenebeck 221 namespace LinuxSampler {
31    
32     // *************** ParameterName ***************
33     // *
34    
35     MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort) : DeviceRuntimeParameterString("Port " + ToString(pPort->GetPortNumber())) {
36     this->pPort = pPort;
37     }
38    
39     MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort, String val) : DeviceRuntimeParameterString(val) {
40     this->pPort = pPort;
41     }
42    
43     String MidiInputPort::ParameterName::Description() {
44     return "Name for this port";
45     }
46    
47     bool MidiInputPort::ParameterName::Fix() {
48     return false;
49     }
50    
51     std::vector<String> MidiInputPort::ParameterName::PossibilitiesAsString() {
52     return std::vector<String>();
53     }
54    
55 schoenebeck 880 void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
56 schoenebeck 221 return; /* FIXME: Nothing to do here */
57     }
58    
59    
60    
61     // *************** MidiInputPort ***************
62     // *
63    
64     MidiInputPort::~MidiInputPort() {
65     std::map<String,DeviceRuntimeParameter*>::iterator iter = Parameters.begin();
66     while (iter != Parameters.end()) {
67     delete iter->second;
68     iter++;
69     }
70 persson 836 Parameters.clear();
71 schoenebeck 221 }
72    
73 persson 846 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
74     : MidiChannelMapReader(MidiChannelMap),
75     SysexListenersReader(SysexListeners) {
76 schoenebeck 221 this->pDevice = pDevice;
77     this->portNumber = portNumber;
78     Parameters["NAME"] = new ParameterName(this);
79     }
80    
81     MidiInputDevice* MidiInputPort::GetDevice() {
82     return pDevice;
83     }
84    
85     uint MidiInputPort::GetPortNumber() {
86     return portNumber;
87     }
88    
89     std::map<String,DeviceRuntimeParameter*> MidiInputPort::PortParameters() {
90     return Parameters;
91     }
92    
93     void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
94 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
95 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
96 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
97     {
98 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
99     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
100 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
101     }
102     // dispatch event for engines listening to ALL MIDI channels
103     {
104 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
105     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
106 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
107     }
108 persson 846 MidiChannelMapReader.Unlock();
109 schoenebeck 221 }
110    
111 schoenebeck 906 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
112 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
113 schoenebeck 906 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
114     // dispatch event for engines listening to the same MIDI channel
115     {
116     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
117     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
118     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
119     }
120     // dispatch event for engines listening to ALL MIDI channels
121     {
122     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
123     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
124     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
125     }
126     MidiChannelMapReader.Unlock();
127     }
128    
129 schoenebeck 221 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
130 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
131 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
132 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
133     {
134 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
135     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
136 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
137     }
138     // dispatch event for engines listening to ALL MIDI channels
139     {
140 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
141     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
142 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
143     }
144 persson 846 MidiChannelMapReader.Unlock();
145 schoenebeck 221 }
146    
147 schoenebeck 906 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
148 persson 922 if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
149 schoenebeck 906 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
150     // dispatch event for engines listening to the same MIDI channel
151     {
152     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
153     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
154     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
155     }
156     // dispatch event for engines listening to ALL MIDI channels
157     {
158     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
159     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
160     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
161     }
162     MidiChannelMapReader.Unlock();
163     }
164    
165 schoenebeck 221 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
166 persson 922 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
167 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
168 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
169     {
170 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
171     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
172 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
173     }
174     // dispatch event for engines listening to ALL MIDI channels
175     {
176 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
177     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
178 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
179     }
180 persson 846 MidiChannelMapReader.Unlock();
181 schoenebeck 221 }
182    
183 schoenebeck 906 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
184 persson 922 if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
185 schoenebeck 906 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
186     // dispatch event for engines listening to the same MIDI channel
187     {
188     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
189     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
190     for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
191     }
192     // dispatch event for engines listening to ALL MIDI channels
193     {
194     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
195     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
196     for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
197     }
198     MidiChannelMapReader.Unlock();
199     }
200    
201 schoenebeck 221 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
202 persson 922 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
203 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
204 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
205     {
206 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
207     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
208 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
209     }
210     // dispatch event for engines listening to ALL MIDI channels
211     {
212 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
213     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
214 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
215     }
216 persson 846 MidiChannelMapReader.Unlock();
217 schoenebeck 221 }
218    
219 schoenebeck 906 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
220 persson 922 if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
221 schoenebeck 906 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
222     // dispatch event for engines listening to the same MIDI channel
223     {
224     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
225     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
226     for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
227     }
228     // dispatch event for engines listening to ALL MIDI channels
229     {
230     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
231     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
232     for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
233     }
234     MidiChannelMapReader.Unlock();
235     }
236    
237 schoenebeck 244 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
238 persson 846 const std::set<Engine*> allEngines = SysexListenersReader.Lock();
239 schoenebeck 775 // dispatch event to all engine instances
240 persson 846 std::set<Engine*>::iterator engineiter = allEngines.begin();
241     std::set<Engine*>::iterator end = allEngines.end();
242 schoenebeck 775 for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);
243 persson 846 SysexListenersReader.Unlock();
244 schoenebeck 244 }
245    
246 schoenebeck 670 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
247 schoenebeck 947 dmsg(1,("Received MIDI program change (prog=%d,ch=%d)\n",Program,MidiChannel));
248 persson 922 if (Program > 127 || MidiChannel > 16) return;
249 schoenebeck 551 if (!pDevice || !pDevice->pSampler) {
250     std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
251     << "This is a bug, please report it!\n" << std::flush;
252     return;
253     }
254 schoenebeck 973 std::vector<int> maps = MidiInstrumentMapper::Maps();
255     if (maps.empty()) return;
256    
257 schoenebeck 947 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
258     // dispatch event for engines listening to the same MIDI channel
259     {
260     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
261     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
262     for (; engineiter != end; engineiter++) {
263     (*engineiter)->SetMidiProgram(Program);
264 schoenebeck 973 if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
265     // retrieve the MIDI instrument map this engine channel is assigned to
266     int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
267     ? maps[0] /*default*/ : (*engineiter)->GetMidiInstrumentMap();
268     // is there an entry for this MIDI bank&prog pair in that map?
269 schoenebeck 947 midi_prog_index_t midiIndex;
270     midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
271     midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
272     midiIndex.midi_prog = (*engineiter)->GetMidiProgram();
273     optional<MidiInstrumentMapper::entry_t> mapping =
274 schoenebeck 973 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
275 schoenebeck 947 if (mapping) { // if mapping exists ...
276     InstrumentManager::instrument_id_t id;
277     id.FileName = mapping->InstrumentFile;
278     id.Index = mapping->InstrumentIndex;
279     //TODO: we should switch the engine type here
280     InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
281     (*engineiter)->Volume(mapping->Volume);
282     }
283     }
284     }
285     // dispatch event for engines listening to ALL MIDI channels
286     {
287     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
288     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
289     for (; engineiter != end; engineiter++) {
290     (*engineiter)->SetMidiProgram(Program);
291 schoenebeck 973 if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
292     // retrieve the MIDI instrument map this engine channel is assigned to
293     int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
294     ? maps[0] /*default*/ : (*engineiter)->GetMidiInstrumentMap();
295     // is there an entry for this MIDI bank&prog pair in that map?
296 schoenebeck 947 midi_prog_index_t midiIndex;
297     midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
298     midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
299     midiIndex.midi_prog = (*engineiter)->GetMidiProgram();
300     optional<MidiInstrumentMapper::entry_t> mapping =
301 schoenebeck 973 MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
302 schoenebeck 947 if (mapping) { // if mapping exists ...
303     InstrumentManager::instrument_id_t id;
304     id.FileName = mapping->InstrumentFile;
305     id.Index = mapping->InstrumentIndex;
306     //TODO: we should switch the engine type here
307     InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
308     (*engineiter)->Volume(mapping->Volume);
309     }
310     }
311     }
312     MidiChannelMapReader.Unlock();
313     }
314 schoenebeck 551
315 schoenebeck 947 void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
316     if (BankMSB > 127 || MidiChannel > 16) return;
317     if (!pDevice || !pDevice->pSampler) {
318     std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
319     << "This is a bug, please report it!\n" << std::flush;
320     return;
321     }
322     const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
323     // dispatch event for engines listening to the same MIDI channel
324     {
325     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
326     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
327     // according to the MIDI specs, a bank select should not alter the patch
328     for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
329     }
330     // dispatch event for engines listening to ALL MIDI channels
331     {
332     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
333     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
334     // according to the MIDI specs, a bank select should not alter the patch
335     for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
336     }
337     MidiChannelMapReader.Unlock();
338     }
339 schoenebeck 551
340 schoenebeck 947 void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
341     if (BankLSB > 127 || MidiChannel > 16) return;
342     if (!pDevice || !pDevice->pSampler) {
343     std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
344     << "This is a bug, please report it!\n" << std::flush;
345     return;
346 schoenebeck 551 }
347 schoenebeck 947 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
348     // dispatch event for engines listening to the same MIDI channel
349     {
350     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
351     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
352     // according to the MIDI specs, a bank select should not alter the patch
353     for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
354     }
355     // dispatch event for engines listening to ALL MIDI channels
356     {
357     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
358     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
359     // according to the MIDI specs, a bank select should not alter the patch
360     for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
361     }
362     MidiChannelMapReader.Unlock();
363 schoenebeck 551 }
364    
365 schoenebeck 411 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
366 schoenebeck 221 if (MidiChannel < 0 || MidiChannel > 16)
367     throw MidiInputException("MIDI channel index out of bounds");
368 schoenebeck 670
369 persson 840 // first check if desired connection is already established
370 schoenebeck 675 MidiChannelMapMutex.Lock();
371 persson 840 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
372     bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
373 schoenebeck 675 MidiChannelMapMutex.Unlock();
374     if (bAlreadyDone) return;
375    
376     // remove all other connections of that engine channel (if any)
377 schoenebeck 411 Disconnect(pEngineChannel);
378 schoenebeck 670
379 schoenebeck 675 // register engine channel on the desired MIDI channel
380 schoenebeck 551 MidiChannelMapMutex.Lock();
381 persson 840 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
382     MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
383 schoenebeck 551 MidiChannelMapMutex.Unlock();
384 schoenebeck 670
385 schoenebeck 675 // inform engine channel about this connection
386     pEngineChannel->Connect(this, MidiChannel);
387    
388 schoenebeck 670 // mark engine channel as changed
389     pEngineChannel->StatusChanged(true);
390 schoenebeck 221 }
391    
392 schoenebeck 411 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
393 schoenebeck 675 if (!pEngineChannel) return;
394    
395     bool bChannelFound = false;
396    
397     // unregister engine channel from all MIDI channels
398 schoenebeck 551 MidiChannelMapMutex.Lock();
399 schoenebeck 675 try {
400 persson 840 {
401     MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
402     for (int i = 0; i <= 16; i++) {
403     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
404     midiChannelMap[i].erase(pEngineChannel);
405     }
406 schoenebeck 675 }
407 persson 840 // do the same update again, after switching to the other config
408     {
409     MidiChannelMap_t& midiChannelMap = MidiChannelMap.SwitchConfig();
410     for (int i = 0; i <= 16; i++) {
411     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
412     midiChannelMap[i].erase(pEngineChannel);
413     }
414     }
415 schoenebeck 675 }
416 schoenebeck 221 catch(...) { /* NOOP */ }
417 schoenebeck 551 MidiChannelMapMutex.Unlock();
418 schoenebeck 675
419     // inform engine channel about the disconnection (if there is one)
420     if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
421    
422 schoenebeck 670 // mark engine channel as changed
423     pEngineChannel->StatusChanged(true);
424 schoenebeck 221 }
425    
426 persson 846 SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
427    
428     void MidiInputPort::AddSysexListener(Engine* engine) {
429     std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
430     if (p.second) SysexListeners.SwitchConfig().insert(engine);
431     }
432    
433     bool MidiInputPort::RemoveSysexListener(Engine* engine) {
434     int count = SysexListeners.GetConfigForUpdate().erase(engine);
435     if (count) SysexListeners.SwitchConfig().erase(engine);
436     return count;
437     }
438    
439 schoenebeck 221 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC