/[svn]/linuxsampler/trunk/src/Sampler.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/Sampler.cpp

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

revision 2499 by persson, Sat Mar 2 07:03:04 2013 UTC revision 2500 by schoenebeck, Fri Jan 10 12:20:05 2014 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 - 2013 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2014 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This library is free software; you can redistribute it and/or modify  *   *   This library 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 44  namespace LinuxSampler { Line 44  namespace LinuxSampler {
44          pSampler           = pS;          pSampler           = pS;
45          pEngineChannel     = NULL;          pEngineChannel     = NULL;
46          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
         pMidiInputDevice   = NULL;  
47          iMidiPort          = 0;          iMidiPort          = 0;
48          midiChannel        = midi_chan_all;          midiChannel        = midi_chan_all;
49          iIndex             = -1;          iIndex             = -1;
# Line 55  namespace LinuxSampler { Line 54  namespace LinuxSampler {
54              Engine* engine = pEngineChannel->GetEngine();              Engine* engine = pEngineChannel->GetEngine();
55              if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);              if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);
56    
             MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : __GetMidiInputDevicePort(GetMidiInputChannel());  
             if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel);  
57              if (pEngineChannel) {              if (pEngineChannel) {
58                    pEngineChannel->DisconnectAllMidiInputPorts();
59                    
60                  if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();                  if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();
61                  EngineChannelFactory::Destroy(pEngineChannel);                  EngineChannelFactory::Destroy(pEngineChannel);
62    
# Line 84  namespace LinuxSampler { Line 83  namespace LinuxSampler {
83          EngineChannel* pNewEngineChannel = EngineChannelFactory::Create(EngineType);          EngineChannel* pNewEngineChannel = EngineChannelFactory::Create(EngineType);
84          if (!pNewEngineChannel) throw Exception("Unknown engine type");          if (!pNewEngineChannel) throw Exception("Unknown engine type");
85    
86          pNewEngineChannel->SetSamplerChannel(this);          // remember current MIDI input connections
87            std::vector<MidiInputPort*> vMidiInputs = GetMidiInputPorts();
         // dereference midi input port.  
         MidiInputPort* pMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort());  
88          midi_chan_t midiChannel = GetMidiInputChannel();          midi_chan_t midiChannel = GetMidiInputChannel();
89          // disconnect old engine channel          
90          if (pEngineChannel) {          try {
91              Engine* engine = pEngineChannel->GetEngine();              pNewEngineChannel->SetSamplerChannel(this);
             if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);  
92    
93              if (pMidiInputPort) pMidiInputPort->Disconnect(pEngineChannel);              // disconnect old engine channel
94              if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();              if (pEngineChannel) {
95              EngineChannelFactory::Destroy(pEngineChannel);                  Engine* engine = pEngineChannel->GetEngine();
96                    if (pAudioOutputDevice) pAudioOutputDevice->Disconnect(engine);
97    
98              // reconnect engine if it still exists                  pEngineChannel->DisconnectAllMidiInputPorts();
99              const std::set<Engine*>& engines = EngineFactory::EngineInstances();                  if (pAudioOutputDevice) pEngineChannel->DisconnectAudioOutputDevice();
100              if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine);                  EngineChannelFactory::Destroy(pEngineChannel);
101          }                  pEngineChannel = NULL;
102    
103          // connect new engine channel                  // reconnect engine if it still exists
104          if (pAudioOutputDevice) {                  const std::set<Engine*>& engines = EngineFactory::EngineInstances();
105              pNewEngineChannel->Connect(pAudioOutputDevice);                  if (engines.find(engine) != engines.end()) pAudioOutputDevice->Connect(engine);
106              pAudioOutputDevice->Connect(pNewEngineChannel->GetEngine());              }
107    
108                // connect new engine channel
109                if (pAudioOutputDevice) {
110                    pNewEngineChannel->Connect(pAudioOutputDevice);
111                    pAudioOutputDevice->Connect(pNewEngineChannel->GetEngine());
112                }
113                pNewEngineChannel->SetMidiChannel(midiChannel);
114                for (int i = 0; i < vMidiInputs.size(); ++i) {
115                    pNewEngineChannel->Connect(vMidiInputs[i]);
116                }
117            } catch (...) {
118                EngineChannelFactory::Destroy(pNewEngineChannel);
119                throw; // re-throw the same exception
120          }          }
         if (pMidiInputPort) pMidiInputPort->Connect(pNewEngineChannel, midiChannel);  
121          pEngineChannel = pNewEngineChannel;          pEngineChannel = pNewEngineChannel;
122    
123          // from now on get MIDI device and port from EngineChannel object          // from now on get MIDI input ports from EngineChannel object
124          this->pMidiInputDevice = NULL;          this->vMidiInputs.clear();
125          this->iMidiPort        = 0;          this->iMidiPort        = 0;
126    
127          pEngineChannel->StatusChanged(true);          pEngineChannel->StatusChanged(true);
# Line 146  namespace LinuxSampler { Line 155  namespace LinuxSampler {
155          }          }
156      }      }
157    
158        void SamplerChannel::Connect(MidiInputPort* pPort) throw (Exception) {
159            if (!pPort) throw Exception("No MIDI input port provided");
160    
161            // prevent attempts to connect non-autonomous MIDI ports
162            // (host plugins like VST, AU, LV2, DSSI)
163            if (!pPort->GetDevice()->isAutonomousDevice())
164                throw Exception("The MIDI input port '" + pPort->GetDevice()->Driver() + "' cannot be managed manually!");
165    
166            std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts();
167    
168            // ignore if port is already connected
169            for (int i = 0; i < vMidiPorts.size(); ++i) {
170                if (vMidiPorts[i] == pPort) return;
171            }
172    
173            // connect this new port
174            if (pEngineChannel) {
175                pEngineChannel->Connect(pPort);
176            } else { // no engine channel yet, remember it for future connection ...
177                const midi_conn_t c = {
178                    pPort->GetDevice()->MidiInputDeviceID(),
179                    pPort->GetPortNumber()
180                };
181                this->vMidiInputs.push_back(c);
182            }
183        }
184    
185        void SamplerChannel::Disconnect(MidiInputPort* pPort) throw (Exception) {
186            if (!pPort) return;
187    
188            // prevent attempts to alter channels with non-autonomous devices
189            // (host plugins like VST, AU, LV2, DSSI)
190            if (!pPort->GetDevice()->isAutonomousDevice())
191                throw Exception("The MIDI input port '" + pPort->GetDevice()->Driver() + "' cannot be managed manually!");
192    
193            // disconnect this port
194            if (pEngineChannel) {
195                pEngineChannel->Disconnect(pPort);
196            } else { // no engine channel yet, forget it regarding future connection ...
197                const midi_conn_t c = {
198                    pPort->GetDevice()->MidiInputDeviceID(),
199                    pPort->GetPortNumber()
200                };
201                for (int i = this->vMidiInputs.size() - 1; i >= 0; --i) {
202                    if (this->vMidiInputs[i] == c)
203                        this->vMidiInputs.erase(this->vMidiInputs.begin() + i);
204                    // no break or return here, for safety reasons
205                    // (just in case there were really duplicates for some reason)
206                }
207            }
208        }
209    
210        void SamplerChannel::DisconnectAllMidiInputPorts() throw (Exception) {
211            std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts();
212            for (int i = 0; i < vMidiPorts.size(); ++i) Disconnect(vMidiPorts[i]);
213        }
214    
215        std::vector<MidiInputPort*> SamplerChannel::GetMidiInputPorts() {
216            std::vector<MidiInputPort*> v;
217            if (pEngineChannel) {
218                MidiInputPort* pPort = pEngineChannel->GetMidiInputPort(0);
219                for (int i = 0; pPort; pPort = pEngineChannel->GetMidiInputPort(++i))
220                    v.push_back(pPort);
221            } else {
222                for (int i = 0; i < this->vMidiInputs.size(); ++i) {
223                    MidiInputPort* pPort = _getPortForID(this->vMidiInputs[i]);
224                    if (pPort) v.push_back(pPort);
225                }
226            }
227            return v;
228        }
229    
230      void SamplerChannel::SetMidiInputDevice(MidiInputDevice* pDevice) throw (Exception) {      void SamplerChannel::SetMidiInputDevice(MidiInputDevice* pDevice) throw (Exception) {
231         SetMidiInput(pDevice, 0, GetMidiInputChannel());         SetMidiInput(pDevice, 0, GetMidiInputChannel());
232      }      }
# Line 155  namespace LinuxSampler { Line 236  namespace LinuxSampler {
236      }      }
237    
238      void SamplerChannel::SetMidiInputChannel(midi_chan_t MidiChannel) {      void SamplerChannel::SetMidiInputChannel(midi_chan_t MidiChannel) {
239         SetMidiInput(GetMidiInputDevice(), GetMidiInputPort(), MidiChannel);          if (!isValidMidiChan(MidiChannel)) throw Exception("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
240            if (pEngineChannel) pEngineChannel->SetMidiChannel(MidiChannel);
241            this->midiChannel = MidiChannel;
242      }      }
243    
244      void SamplerChannel::SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel) throw (Exception) {      void SamplerChannel::SetMidiInput(MidiInputDevice* pDevice, int iMidiPort, midi_chan_t MidiChannel) throw (Exception) {
245          if (!pDevice) throw Exception("No MIDI input device assigned.");          if (!pDevice) throw Exception("No MIDI input device assigned.");
246    
247          // get old and new midi input port          // apply new MIDI channel
248          MidiInputPort* pOldMidiInputPort = __GetMidiInputDevicePort(GetMidiInputPort());          SetMidiInputChannel(MidiChannel);
249          MidiInputPort* pNewMidiInputPort = pDevice->GetPort(iMidiPort);  
250            MidiInputPort* pNewPort = pDevice->GetPort(iMidiPort);
251          // disconnect old device port          if (!pNewPort) throw Exception("There is no MIDI input port with index " + ToString(iMidiPort) + ".");
252          if (pOldMidiInputPort && pEngineChannel) {  
253              MidiInputDevice* pOldDevice = pOldMidiInputPort->GetDevice();          std::vector<MidiInputPort*> vMidiPorts = GetMidiInputPorts();
254              if (pOldMidiInputPort != pNewMidiInputPort &&  
255                  pOldDevice && !pOldDevice->isAutonomousDevice()          // prevent attempts to remove non-autonomous MIDI ports
256              ) throw Exception("The MIDI input port '" + pOldDevice->Driver() + "' cannot be altered on this sampler channel!");          // (host plugins like VST, AU, LV2, DSSI)
257            for (int i = 0; i < vMidiPorts.size(); ++i) {
258              pOldMidiInputPort->Disconnect(pEngineChannel);              if (vMidiPorts[i] == pNewPort) continue;
259          }              if (!vMidiPorts[i]->GetDevice()->isAutonomousDevice())
260                    throw Exception("The MIDI input port '" + vMidiPorts[i]->GetDevice()->Driver() + "' cannot be altered on this sampler channel!");
261          // remember new device, port and channel if not engine channel yet created          }
262          if (!pEngineChannel) {  
263              this->pMidiInputDevice = pDevice;          if (pEngineChannel) {
264              this->iMidiPort        = iMidiPort;              // remove all current connections
265              this->midiChannel      = MidiChannel;              pEngineChannel->DisconnectAllMidiInputPorts();
266          }              // create the new connection (alone)
267                pEngineChannel->Connect(pNewPort);
268          // connect new device port          } else { // if there is no engine channel yet, then store connection for future ...
269          if (pNewMidiInputPort && pEngineChannel) pNewMidiInputPort->Connect(pEngineChannel, MidiChannel);              // delete all previously scheduled connections
270          // Ooops.              this->vMidiInputs.clear();
271          if (pNewMidiInputPort == NULL)              // store the new connection (alone)
272              throw Exception("There is no MIDI input port with index " + ToString(iMidiPort) + ".");              const midi_conn_t c = {
273                    pNewPort->GetDevice()->MidiInputDeviceID(),
274                    pNewPort->GetPortNumber()
275                };
276                this->vMidiInputs.push_back(c);
277                this->iMidiPort = iMidiPort;
278            }
279      }      }
280    
281      EngineChannel* SamplerChannel::GetEngineChannel() {      EngineChannel* SamplerChannel::GetEngineChannel() {
# Line 199  namespace LinuxSampler { Line 288  namespace LinuxSampler {
288      }      }
289    
290      int SamplerChannel::GetMidiInputPort() {      int SamplerChannel::GetMidiInputPort() {
291          MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort() : NULL;          MidiInputPort* pMidiInputPort = (pEngineChannel) ? pEngineChannel->GetMidiInputPort(0) : NULL;
292          if (pMidiInputPort) this->iMidiPort = (int) pMidiInputPort->GetPortNumber();          if (pMidiInputPort) this->iMidiPort = (int) pMidiInputPort->GetPortNumber();
293          return iMidiPort;          return iMidiPort;
294      }      }
# Line 210  namespace LinuxSampler { Line 299  namespace LinuxSampler {
299    
300      MidiInputDevice* SamplerChannel::GetMidiInputDevice() {      MidiInputDevice* SamplerChannel::GetMidiInputDevice() {
301          if (pEngineChannel)          if (pEngineChannel)
302              pMidiInputDevice = (pEngineChannel->GetMidiInputPort()) ? pEngineChannel->GetMidiInputPort()->GetDevice() : NULL;              return (pEngineChannel->GetMidiInputPort(0)) ? pEngineChannel->GetMidiInputPort(0)->GetDevice() : NULL;
303          return pMidiInputDevice;  
304            if (vMidiInputs.empty())
305                return NULL;
306    
307            std::map<uint, MidiInputDevice*> mAllDevices = MidiInputDeviceFactory::Devices();
308            if (!mAllDevices.count(vMidiInputs[0].deviceID))
309                return NULL;
310    
311            return mAllDevices[vMidiInputs[0].deviceID];
312      }      }
313    
314      uint SamplerChannel::Index() {      uint SamplerChannel::Index() {
# Line 255  namespace LinuxSampler { Line 352  namespace LinuxSampler {
352              llEngineChangeListeners.GetListener(i)->EngineChanged(Index());              llEngineChangeListeners.GetListener(i)->EngineChanged(Index());
353          }          }
354      }      }
355        
356        /**
357         * Takes a numeric MIDI device ID, port ID pair as argument and returns
358         * the actual MIDI input port associated with that unique ID pair.
359         */
360        MidiInputPort* SamplerChannel::_getPortForID(const midi_conn_t& c) {
361            std::map<uint, MidiInputDevice*> mAllDevices = MidiInputDeviceFactory::Devices();
362            if (!mAllDevices.count(c.deviceID))
363                return NULL;
364    
365      MidiInputPort* SamplerChannel::__GetMidiInputDevicePort(int iMidiPort) {          return mAllDevices[c.deviceID]->GetPort(c.portNr);
         MidiInputPort* pMidiInputPort = NULL;  
         MidiInputDevice* pMidiInputDevice = GetMidiInputDevice();  
         if (pMidiInputDevice)  
             pMidiInputPort = pMidiInputDevice->GetPort(iMidiPort);  
         return pMidiInputPort;  
366      }      }
367    
368    
   
369      // ******************************************************************      // ******************************************************************
370      // * Sampler      // * Sampler
371    
# Line 622  namespace LinuxSampler { Line 722  namespace LinuxSampler {
722          if (pDevice) {          if (pDevice) {
723              // check if there are still sampler engines connected to this device              // check if there are still sampler engines connected to this device
724              for (SamplerChannelMap::iterator iterChan = mSamplerChannels.begin();              for (SamplerChannelMap::iterator iterChan = mSamplerChannels.begin();
725                   iterChan != mSamplerChannels.end(); iterChan++                   iterChan != mSamplerChannels.end(); ++iterChan)
726              ) if (iterChan->second->GetMidiInputDevice() == pDevice) throw Exception("Sampler channel " + ToString(iterChan->first) + " is still connected to the midi input device.");              {
727                    std::vector<MidiInputPort*> vPorts = iterChan->second->GetMidiInputPorts();
728                    for (int k = 0; k < vPorts.size(); ++k)
729                        if (vPorts[k]->GetDevice() == pDevice)
730                            throw Exception("Sampler channel " + ToString(iterChan->first) + " is still connected to the midi input device.");
731                }
732    
733              fireMidiDeviceToBeDestroyed(pDevice);              fireMidiDeviceToBeDestroyed(pDevice);
734              MidiInputDeviceFactory::Destroy(pDevice);              MidiInputDeviceFactory::Destroy(pDevice);

Legend:
Removed from v.2499  
changed lines
  Added in v.2500

  ViewVC Help
Powered by ViewVC