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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 840 by persson, Sun Feb 26 13:00:08 2006 UTC revision 1924 by persson, Sun Jun 28 16:43:38 2009 UTC
# Line 3  Line 3 
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 - 2009 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  *
# Line 23  Line 23 
23    
24  #include "MidiInputPort.h"  #include "MidiInputPort.h"
25    
26    #include "../../common/global_private.h"
27    #include "MidiInstrumentMapper.h"
28  #include "../../Sampler.h"  #include "../../Sampler.h"
29  #include "../../engines/EngineFactory.h"  #include "../../engines/EngineFactory.h"
30    #include "VirtualMidiDevice.h"
31    
32    #include <algorithm>
33    
34  namespace LinuxSampler {  namespace LinuxSampler {
35    
# Line 51  namespace LinuxSampler { Line 56  namespace LinuxSampler {
56          return std::vector<String>();          return std::vector<String>();
57      }      }
58    
59      void MidiInputPort::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {      void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
60          return; /* FIXME: Nothing to do here */          return; /* FIXME: Nothing to do here */
61      }      }
62    
# Line 69  namespace LinuxSampler { Line 74  namespace LinuxSampler {
74          Parameters.clear();          Parameters.clear();
75      }      }
76    
77      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) {      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
78            : MidiChannelMapReader(MidiChannelMap),
79              SysexListenersReader(SysexListeners),
80              virtualMidiDevicesReader(virtualMidiDevices) {
81          this->pDevice = pDevice;          this->pDevice = pDevice;
82          this->portNumber = portNumber;          this->portNumber = portNumber;
83          Parameters["NAME"] = new ParameterName(this);          Parameters["NAME"] = new ParameterName(this);
         pPreviousProgramChangeEngineChannel = NULL;  
84      }      }
85    
86      MidiInputDevice* MidiInputPort::GetDevice() {      MidiInputDevice* MidiInputPort::GetDevice() {
# Line 89  namespace LinuxSampler { Line 96  namespace LinuxSampler {
96      }      }
97    
98      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
99          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
100            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
101          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
102          {          {
103              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
# Line 102  namespace LinuxSampler { Line 110  namespace LinuxSampler {
110              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
111              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
112          }          }
113          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
114    
115            // dispatch event to all low priority MIDI listeners
116            const std::vector<VirtualMidiDevice*>& listeners =
117                virtualMidiDevicesReader.Lock();
118            for (int i = 0; i < listeners.size(); ++i)
119                listeners[i]->SendNoteOnToDevice(Key, Velocity);
120            virtualMidiDevicesReader.Unlock();
121        }
122    
123        void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
124            if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
125            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
126            // dispatch event for engines listening to the same MIDI channel
127            {
128                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
129                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
130                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
131            }
132            // dispatch event for engines listening to ALL MIDI channels
133            {
134                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
135                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
136                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
137            }
138            MidiChannelMapReader.Unlock();
139    
140            // dispatch event to all low priority MIDI listeners
141            const std::vector<VirtualMidiDevice*>& listeners =
142                virtualMidiDevicesReader.Lock();
143            for (int i = 0; i < listeners.size(); ++i)
144                listeners[i]->SendNoteOnToDevice(Key, Velocity);
145            virtualMidiDevicesReader.Unlock();
146      }      }
147    
148      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
149          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
150            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
151          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
152          {          {
153              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
# Line 119  namespace LinuxSampler { Line 160  namespace LinuxSampler {
160              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
161              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
162          }          }
163          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
164    
165            // dispatch event to all low priority MIDI listeners
166            const std::vector<VirtualMidiDevice*>& listeners =
167                virtualMidiDevicesReader.Lock();
168            for (int i = 0; i < listeners.size(); ++i)
169                listeners[i]->SendNoteOffToDevice(Key, Velocity);
170            virtualMidiDevicesReader.Unlock();
171        }
172    
173        void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
174            if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
175            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
176            // dispatch event for engines listening to the same MIDI channel
177            {
178                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
179                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
180                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
181            }
182            // dispatch event for engines listening to ALL MIDI channels
183            {
184                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
185                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
186                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
187            }
188            MidiChannelMapReader.Unlock();
189    
190            // dispatch event to all low priority MIDI listeners
191            const std::vector<VirtualMidiDevice*>& listeners =
192                virtualMidiDevicesReader.Lock();
193            for (int i = 0; i < listeners.size(); ++i)
194                listeners[i]->SendNoteOffToDevice(Key, Velocity);
195            virtualMidiDevicesReader.Unlock();
196      }      }
197    
198      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
199          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
200            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
201          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
202          {          {
203              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
# Line 136  namespace LinuxSampler { Line 210  namespace LinuxSampler {
210              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
211              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
212          }          }
213          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
214        }
215    
216        void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
217            if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
218            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
219            // dispatch event for engines listening to the same MIDI channel
220            {
221                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
222                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
223                for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
224            }
225            // dispatch event for engines listening to ALL MIDI channels
226            {
227                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
228                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
229                for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
230            }
231            MidiChannelMapReader.Unlock();
232      }      }
233    
234      void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {      void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
235          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
236            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
237          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
238          {          {
239              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
# Line 153  namespace LinuxSampler { Line 246  namespace LinuxSampler {
246              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
247              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
248          }          }
249          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
250        }
251    
252        void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
253            if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
254            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
255            // dispatch event for engines listening to the same MIDI channel
256            {
257                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
258                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
259                for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
260            }
261            // dispatch event for engines listening to ALL MIDI channels
262            {
263                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
264                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
265                for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
266            }
267            MidiChannelMapReader.Unlock();
268      }      }
269    
270      void MidiInputPort::DispatchSysex(void* pData, uint Size) {      void MidiInputPort::DispatchSysex(void* pData, uint Size) {
271            const std::set<Engine*> allEngines = SysexListenersReader.Lock();
272          // dispatch event to all engine instances          // dispatch event to all engine instances
273          std::set<Engine*>::iterator engineiter = EngineFactory::EngineInstances().begin();          std::set<Engine*>::iterator engineiter = allEngines.begin();
274          std::set<Engine*>::iterator end        = EngineFactory::EngineInstances().end();          std::set<Engine*>::iterator end        = allEngines.end();
275          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size, this);
276            SysexListenersReader.Unlock();
277      }      }
278    
279      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
280            if (Program > 127 || MidiChannel > 16) return;
281          if (!pDevice || !pDevice->pSampler) {          if (!pDevice || !pDevice->pSampler) {
282              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
283                        << "This is a bug, please report it!\n" << std::flush;                        << "This is a bug, please report it!\n" << std::flush;
284              return;              return;
285          }          }
286    
287          Sampler*        pSampler        = (Sampler*) pDevice->pSampler;          const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
288          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program);          // dispatch event for engines listening to the same MIDI channel
289          if (!pSamplerChannel) return;          {
290                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
291                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
292                for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
293            }
294            // dispatch event for engines listening to ALL MIDI channels
295            {
296                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
297                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
298                for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
299            }
300            MidiChannelMapReader.Unlock();
301        }
302    
303        void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
304            if (BankMSB > 127 || MidiChannel > 16) return;
305            if (!pDevice || !pDevice->pSampler) {
306                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
307                          << "This is a bug, please report it!\n" << std::flush;
308                return;
309            }
310            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
311            // dispatch event for engines listening to the same MIDI channel
312            {
313                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
314                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
315                // according to the MIDI specs, a bank select should not alter the patch
316                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
317            }
318            // dispatch event for engines listening to ALL MIDI channels
319            {
320                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
321                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
322                // according to the MIDI specs, a bank select should not alter the patch
323                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
324            }
325            MidiChannelMapReader.Unlock();
326        }
327    
328          EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();      void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
329          if (!pEngineChannel) return;          if (BankLSB > 127 || MidiChannel > 16) return;
330            if (!pDevice || !pDevice->pSampler) {
331                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
332                          << "This is a bug, please report it!\n" << std::flush;
333                return;
334            }
335            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
336            // dispatch event for engines listening to the same MIDI channel
337            {
338                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
339                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
340                // according to the MIDI specs, a bank select should not alter the patch
341                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
342            }
343            // dispatch event for engines listening to ALL MIDI channels
344            {
345                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
346                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
347                // according to the MIDI specs, a bank select should not alter the patch
348                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
349            }
350            MidiChannelMapReader.Unlock();
351        }
352    
353          // disconnect from the engine channel which was connected by the last PC event      void MidiInputPort::DispatchRaw(uint8_t* pData) {
354          if (pPreviousProgramChangeEngineChannel)          uint8_t channel = pData[0] & 0x0f;
355              Disconnect(pPreviousProgramChangeEngineChannel);          switch (pData[0] & 0xf0) {
356            case 0x80:
357                DispatchNoteOff(pData[1], pData[2], channel);
358                break;
359            case 0x90:
360                if (pData[2]) {
361                    DispatchNoteOn(pData[1], pData[2], channel);
362                } else {
363                    DispatchNoteOff(pData[1], pData[2], channel);
364                }
365                break;
366            case 0xb0:
367                if (pData[1] == 0) {
368                    DispatchBankSelectMsb(pData[2], channel);
369                } else if (pData[1] == 32) {
370                    DispatchBankSelectLsb(pData[2], channel);
371                }
372                DispatchControlChange(pData[1], pData[2], channel);
373                break;
374            case 0xc0:
375                DispatchProgramChange(pData[1], channel);
376                break;
377            case 0xd0:
378                DispatchControlChange(128, pData[1], channel);
379                break;
380            case 0xe0:
381                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel);
382                break;
383            }
384        }
385    
386          // now connect to the new engine channel and remember it      void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
387          try {          uint8_t channel = pData[0] & 0x0f;
388              Connect(pEngineChannel, (midi_chan_t) MidiChannel);          switch (pData[0] & 0xf0) {
389              pPreviousProgramChangeEngineChannel = pEngineChannel;          case 0x80:
390                DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
391                break;
392            case 0x90:
393                if (pData[2]) {
394                    DispatchNoteOn(pData[1], pData[2], channel, FragmentPos);
395                } else {
396                    DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
397                }
398                break;
399            case 0xb0:
400                if (pData[1] == 0) {
401                    DispatchBankSelectMsb(pData[2], channel);
402                } else if (pData[1] == 32) {
403                    DispatchBankSelectLsb(pData[2], channel);
404                }
405                DispatchControlChange(pData[1], pData[2], channel, FragmentPos);
406                break;
407            case 0xc0:
408                DispatchProgramChange(pData[1], channel);
409                break;
410            case 0xd0:
411                DispatchControlChange(128, pData[1], channel, FragmentPos);
412                break;
413            case 0xe0:
414                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel, FragmentPos);
415                break;
416          }          }
         catch (...) { /* NOOP */ }  
417      }      }
418    
419      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
# Line 250  namespace LinuxSampler { Line 477  namespace LinuxSampler {
477          pEngineChannel->StatusChanged(true);          pEngineChannel->StatusChanged(true);
478      }      }
479    
480        SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
481    
482        void MidiInputPort::AddSysexListener(Engine* engine) {
483            std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
484            if (p.second) SysexListeners.SwitchConfig().insert(engine);
485        }
486    
487        bool MidiInputPort::RemoveSysexListener(Engine* engine) {
488            int count = SysexListeners.GetConfigForUpdate().erase(engine);
489            if (count) SysexListeners.SwitchConfig().erase(engine);
490            return count;
491        }
492    
493        void MidiInputPort::Connect(VirtualMidiDevice* pDevice) {
494            virtualMidiDevicesMutex.Lock();
495            // double buffer ... double work ...
496            {
497                std::vector<VirtualMidiDevice*>& devices =
498                    virtualMidiDevices.GetConfigForUpdate();
499                devices.push_back(pDevice);
500            }
501            {
502                std::vector<VirtualMidiDevice*>& devices =
503                    virtualMidiDevices.SwitchConfig();
504                devices.push_back(pDevice);
505            }
506            virtualMidiDevicesMutex.Unlock();
507        }
508    
509        void MidiInputPort::Disconnect(VirtualMidiDevice* pDevice) {
510            virtualMidiDevicesMutex.Lock();
511            // double buffer ... double work ...
512            {
513                std::vector<VirtualMidiDevice*>& devices =
514                    virtualMidiDevices.GetConfigForUpdate();
515                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
516            }
517            {
518                std::vector<VirtualMidiDevice*>& devices =
519                    virtualMidiDevices.SwitchConfig();
520                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
521            }
522            virtualMidiDevicesMutex.Unlock();
523        }
524    
525  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.840  
changed lines
  Added in v.1924

  ViewVC Help
Powered by ViewVC