/[svn]/linuxsampler/trunk/src/engines/gig/EngineChannel.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/EngineChannel.cpp

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

revision 1298 by iliev, Fri Aug 17 12:55:37 2007 UTC revision 1659 by schoenebeck, Sun Feb 3 00:13:27 2008 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 - 2007 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2008 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 "EngineChannel.h"  #include "EngineChannel.h"
25    
26    #include "../../common/global_private.h"
27    
28  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
29    
30      EngineChannel::EngineChannel() {      EngineChannel::EngineChannel() :
31            InstrumentChangeCommandReader(InstrumentChangeCommand),
32            virtualMidiDevicesReader(virtualMidiDevices)
33        {
34          pMIDIKeyInfo = new midi_key_info_t[128];          pMIDIKeyInfo = new midi_key_info_t[128];
35          pEngine      = NULL;          pEngine      = NULL;
36          pInstrument  = NULL;          pInstrument  = NULL;
# Line 57  namespace LinuxSampler { namespace gig { Line 62  namespace LinuxSampler { namespace gig {
62    
63      EngineChannel::~EngineChannel() {      EngineChannel::~EngineChannel() {
64          DisconnectAudioOutputDevice();          DisconnectAudioOutputDevice();
         if (pInstrument) Engine::instruments.HandBack(pInstrument, this);  
65          if (pEventQueue) delete pEventQueue;          if (pEventQueue) delete pEventQueue;
66          if (pActiveKeys) delete pActiveKeys;          if (pActiveKeys) delete pActiveKeys;
67          if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;          if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
# Line 162  namespace LinuxSampler { namespace gig { Line 166  namespace LinuxSampler { namespace gig {
166       * @see PrepareLoadInstrument()       * @see PrepareLoadInstrument()
167       */       */
168      void EngineChannel::LoadInstrument() {      void EngineChannel::LoadInstrument() {
169          ::gig::Instrument* oldInstrument = pInstrument;          // make sure we don't trigger any new notes with an old
170            // instrument
171          // free old instrument          instrument_change_command_t& cmd = ChangeInstrument(0);
172          if (oldInstrument) {          if (cmd.pInstrument) {
173              if (pEngine) {              // give old instrument back to instrument manager, but
174                  // make sure we don't trigger any new notes with the              // keep the dimension regions and samples that are in use
175                  // old instrument              Engine::instruments.HandBackInstrument(cmd.pInstrument, this, cmd.pDimRegionsInUse);
                 ::gig::DimensionRegion** dimRegionsInUse = pEngine->ChangeInstrument(this, 0);  
   
                 // give old instrument back to instrument manager, but  
                 // keep the dimension regions and samples that are in  
                 // use  
                 Engine::instruments.HandBackInstrument(oldInstrument, this, dimRegionsInUse);  
             } else {  
                 Engine::instruments.HandBack(oldInstrument, this);  
             }  
176          }          }
177            cmd.pDimRegionsInUse->clear();
178    
179          // delete all key groups          // delete all key groups
180          ActiveKeyGroups.clear();          ActiveKeyGroups.clear();
# Line 196  namespace LinuxSampler { namespace gig { Line 192  namespace LinuxSampler { namespace gig {
192          }          }
193          catch (RIFF::Exception e) {          catch (RIFF::Exception e) {
194              InstrumentStat = -2;              InstrumentStat = -2;
195                StatusChanged(true);
196              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;
197              throw Exception(msg);              throw Exception(msg);
198          }          }
199          catch (InstrumentManagerException e) {          catch (InstrumentManagerException e) {
200              InstrumentStat = -3;              InstrumentStat = -3;
201                StatusChanged(true);
202              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();              String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();
203              throw Exception(msg);              throw Exception(msg);
204          }          }
205          catch (...) {          catch (...) {
206              InstrumentStat = -4;              InstrumentStat = -4;
207                StatusChanged(true);
208              throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");              throw Exception("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");
209          }          }
210    
# Line 216  namespace LinuxSampler { namespace gig { Line 215  namespace LinuxSampler { namespace gig {
215          InstrumentIdxName = newInstrument->pInfo->Name;          InstrumentIdxName = newInstrument->pInfo->Name;
216          InstrumentStat = 100;          InstrumentStat = 100;
217    
218          if (pEngine) pEngine->ChangeInstrument(this, newInstrument);          ChangeInstrument(newInstrument);
219          else pInstrument = newInstrument;  
           
220          StatusChanged(true);          StatusChanged(true);
221      }      }
222    
223    
224        /**
225         * Changes the instrument for an engine channel.
226         *
227         * @param pInstrument - new instrument
228         * @returns the resulting instrument change command after the
229         *          command switch, containing the old instrument and
230         *          the dimregions it is using
231         */
232        EngineChannel::instrument_change_command_t& EngineChannel::ChangeInstrument(::gig::Instrument* pInstrument) {
233            instrument_change_command_t& cmd = InstrumentChangeCommand.GetConfigForUpdate();
234            cmd.pInstrument = pInstrument;
235            cmd.bChangeInstrument = true;
236    
237            return InstrumentChangeCommand.SwitchConfig();
238        }
239    
240      /**      /**
241       * Will be called by the InstrumentResourceManager when the instrument       * Will be called by the InstrumentResourceManager when the instrument
242       * we are currently using on this EngineChannel is going to be updated,       * we are currently using on this EngineChannel is going to be updated,
# Line 264  namespace LinuxSampler { namespace gig { Line 279  namespace LinuxSampler { namespace gig {
279          pEngine = Engine::AcquireEngine(this, pAudioOut);          pEngine = Engine::AcquireEngine(this, pAudioOut);
280          ResetInternal();          ResetInternal();
281          pEvents = new RTList<Event>(pEngine->pEventPool);          pEvents = new RTList<Event>(pEngine->pEventPool);
282    
283            // reset the instrument change command struct (need to be done
284            // twice, as it is double buffered)
285            {
286                instrument_change_command_t& cmd = InstrumentChangeCommand.GetConfigForUpdate();
287                cmd.pDimRegionsInUse = new RTList< ::gig::DimensionRegion*>(pEngine->pDimRegionPool[0]);
288                cmd.pInstrument = 0;
289                cmd.bChangeInstrument = false;
290            }
291            {
292                instrument_change_command_t& cmd = InstrumentChangeCommand.SwitchConfig();
293                cmd.pDimRegionsInUse = new RTList< ::gig::DimensionRegion*>(pEngine->pDimRegionPool[1]);
294                cmd.pInstrument = 0;
295                cmd.bChangeInstrument = false;
296            }
297    
298          for (uint i = 0; i < 128; i++) {          for (uint i = 0; i < 128; i++) {
299              pMIDIKeyInfo[i].pActiveVoices = new RTList<Voice>(pEngine->pVoicePool);              pMIDIKeyInfo[i].pActiveVoices = new RTList<Voice>(pEngine->pVoicePool);
300              pMIDIKeyInfo[i].pEvents       = new RTList<Event>(pEngine->pEventPool);              pMIDIKeyInfo[i].pEvents       = new RTList<Event>(pEngine->pEventPool);
# Line 286  namespace LinuxSampler { namespace gig { Line 317  namespace LinuxSampler { namespace gig {
317    
318      void EngineChannel::DisconnectAudioOutputDevice() {      void EngineChannel::DisconnectAudioOutputDevice() {
319          if (pEngine) { // if clause to prevent disconnect loops          if (pEngine) { // if clause to prevent disconnect loops
320    
321                // delete the structures used for instrument change
322                RTList< ::gig::DimensionRegion*>* d = InstrumentChangeCommand.GetConfigForUpdate().pDimRegionsInUse;
323                if (d) delete d;
324                EngineChannel::instrument_change_command_t& cmd = InstrumentChangeCommand.SwitchConfig();
325                d = cmd.pDimRegionsInUse;
326    
327                if (cmd.pInstrument) {
328                    // release the currently loaded instrument
329                    Engine::instruments.HandBackInstrument(cmd.pInstrument, this, d);
330                }
331                if (d) delete d;
332    
333                // release all active dimension regions to resource
334                // manager
335                RTList<uint>::Iterator iuiKey = pActiveKeys->first();
336                RTList<uint>::Iterator end    = pActiveKeys->end();
337                while (iuiKey != end) { // iterate through all active keys
338                    midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];
339                    ++iuiKey;
340    
341                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
342                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
343                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
344                        Engine::instruments.HandBackDimReg(itVoice->pDimRgn);
345                    }
346                }
347    
348              ResetInternal();              ResetInternal();
349              if (pEvents) {              if (pEvents) {
350                  delete pEvents;                  delete pEvents;
# Line 392  namespace LinuxSampler { namespace gig { Line 451  namespace LinuxSampler { namespace gig {
451          fxSends.push_back(pFxSend);          fxSends.push_back(pFxSend);
452          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
453          fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());          fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());
454            
455          return pFxSend;          return pFxSend;
456      }      }
457    
# Line 451  namespace LinuxSampler { namespace gig { Line 510  namespace LinuxSampler { namespace gig {
510              event.pEngineChannel      = this;              event.pEngineChannel      = this;
511              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
512              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
513                // inform instrument editor(s), if any ...
514                pEngine->instruments.TrySendNoteOnToEditors(Key, Velocity, pInstrument);
515          }          }
516      }      }
517    
# Line 477  namespace LinuxSampler { namespace gig { Line 538  namespace LinuxSampler { namespace gig {
538              event.pEngineChannel      = this;              event.pEngineChannel      = this;
539              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
540              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
541                // inform instrument editor(s), if any ...
542                pEngine->instruments.TrySendNoteOnToEditors(Key, Velocity, pInstrument);
543          }          }
544      }      }
545    
# Line 498  namespace LinuxSampler { namespace gig { Line 561  namespace LinuxSampler { namespace gig {
561              event.pEngineChannel      = this;              event.pEngineChannel      = this;
562              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
563              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
564                // inform instrument editor(s), if any ...
565                pEngine->instruments.TrySendNoteOffToEditors(Key, Velocity, pInstrument);
566          }          }
567      }      }
568    
# Line 524  namespace LinuxSampler { namespace gig { Line 589  namespace LinuxSampler { namespace gig {
589              event.pEngineChannel      = this;              event.pEngineChannel      = this;
590              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
591              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
592                // inform instrument editor(s), if any ...
593                pEngine->instruments.TrySendNoteOffToEditors(Key, Velocity, pInstrument);
594          }          }
595      }      }
596    
# Line 663  namespace LinuxSampler { namespace gig { Line 730  namespace LinuxSampler { namespace gig {
730       *                  current audio cycle       *                  current audio cycle
731       */       */
732      void EngineChannel::ImportEvents(uint Samples) {      void EngineChannel::ImportEvents(uint Samples) {
733            // import events from pure software MIDI "devices"
734            // (e.g. virtual keyboard in instrument editor)
735            {
736                const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
737                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
738                VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
739                // as we're going to (carefully) write some status to the
740                // synchronized struct, we cast away the const
741                ArrayList<VirtualMidiDevice*>& devices =
742                    const_cast<ArrayList<VirtualMidiDevice*>&>(virtualMidiDevicesReader.Lock());
743                // iterate through all virtual MIDI devices
744                for (int i = 0; i < devices.size(); i++) {
745                    VirtualMidiDevice* pDev = devices[i];
746                    // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
747                    while (pDev->GetMidiEventFromDevice(devEvent)) {
748                        event.Type =
749                            (devEvent.Type == VirtualMidiDevice::EVENT_TYPE_NOTEON) ?
750                                Event::type_note_on : Event::type_note_off;
751                        event.Param.Note.Key      = devEvent.Key;
752                        event.Param.Note.Velocity = devEvent.Velocity;
753                        event.pEngineChannel      = this;
754                        // copy event to internal event list
755                        if (pEvents->poolIsEmpty()) {
756                            dmsg(1,("Event pool emtpy!\n"));
757                            goto exitVirtualDevicesLoop;
758                        }
759                        *pEvents->allocAppend() = event;
760                    }
761                }
762            }
763            exitVirtualDevicesLoop:
764            virtualMidiDevicesReader.Unlock();
765    
766            // import events from the regular MIDI devices
767          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
768          Event* pEvent;          Event* pEvent;
769          while (true) {          while (true) {
# Line 700  namespace LinuxSampler { namespace gig { Line 801  namespace LinuxSampler { namespace gig {
801                  if (pEngine && pEngine->pAudioOutputDevice) {                  if (pEngine && pEngine->pAudioOutputDevice) {
802                      // fallback to render directly to the AudioOutputDevice's buffer                      // fallback to render directly to the AudioOutputDevice's buffer
803                      pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);                      pChannelRight = pEngine->pAudioOutputDevice->Channel(AudioDeviceChannelRight);
804                  } else pChannelRight = NULL;                  } else pChannelRight = NULL;
805              }              }
806          }          }
807          for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];          for (int i = 0; i < fxSends.size(); i++) delete fxSends[i];
# Line 708  namespace LinuxSampler { namespace gig { Line 809  namespace LinuxSampler { namespace gig {
809          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
810      }      }
811    
812        void EngineChannel::Connect(VirtualMidiDevice* pDevice) {
813            // double buffer ... double work ...
814            {
815                ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
816                devices.add(pDevice);
817            }
818            {
819                ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
820                devices.add(pDevice);
821            }
822        }
823    
824        void EngineChannel::Disconnect(VirtualMidiDevice* pDevice) {
825            // double buffer ... double work ...
826            {
827                ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.GetConfigForUpdate();
828                devices.remove(pDevice);
829            }
830            {
831                ArrayList<VirtualMidiDevice*>& devices = virtualMidiDevices.SwitchConfig();
832                devices.remove(pDevice);
833            }
834        }
835    
836      float EngineChannel::Volume() {      float EngineChannel::Volume() {
837          return GlobalVolume;          return GlobalVolume;
838      }      }

Legend:
Removed from v.1298  
changed lines
  Added in v.1659

  ViewVC Help
Powered by ViewVC