/[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 1001 by schoenebeck, Wed Dec 27 16:17:08 2006 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, 2006 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 159  namespace LinuxSampler { namespace gig { Line 163  namespace LinuxSampler { namespace gig {
163       * This method will then actually start to load the instrument and block       * This method will then actually start to load the instrument and block
164       * the calling thread until loading was completed.       * the calling thread until loading was completed.
165       *       *
      * @returns detailed description of the method call result  
166       * @see PrepareLoadInstrument()       * @see PrepareLoadInstrument()
167       */       */
168      void EngineChannel::LoadInstrument() {      void EngineChannel::LoadInstrument() {
169            // make sure we don't trigger any new notes with an old
170          if (pEngine) pEngine->DisableAndLock();          // instrument
171            instrument_change_command_t& cmd = ChangeInstrument(0);
172          ResetInternal();          if (cmd.pInstrument) {
173                // give old instrument back to instrument manager, but
174          // free old instrument              // keep the dimension regions and samples that are in use
175          if (pInstrument) {              Engine::instruments.HandBackInstrument(cmd.pInstrument, this, cmd.pDimRegionsInUse);
             // give old instrument back to instrument manager  
             Engine::instruments.HandBack(pInstrument, this);  
176          }          }
177            cmd.pDimRegionsInUse->clear();
178    
179          // delete all key groups          // delete all key groups
180          ActiveKeyGroups.clear();          ActiveKeyGroups.clear();
181    
182          // request gig instrument from instrument manager          // request gig instrument from instrument manager
183            ::gig::Instrument* newInstrument;
184          try {          try {
185              InstrumentManager::instrument_id_t instrid;              InstrumentManager::instrument_id_t instrid;
186              instrid.FileName  = InstrumentFile;              instrid.FileName  = InstrumentFile;
187              instrid.Index     = InstrumentIdx;              instrid.Index     = InstrumentIdx;
188              pInstrument = Engine::instruments.Borrow(instrid, this);              newInstrument = Engine::instruments.Borrow(instrid, this);
189              if (!pInstrument) {              if (!newInstrument) {
190                  InstrumentStat = -1;                  throw InstrumentManagerException("resource was not created");
                 dmsg(1,("no instrument loaded!!!\n"));  
                 exit(EXIT_FAILURE);  
191              }              }
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 (InstrumentResourceManagerException 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    
211          // rebuild ActiveKeyGroups map with key groups of current instrument          // rebuild ActiveKeyGroups map with key groups of current instrument
212          for (::gig::Region* pRegion = pInstrument->GetFirstRegion(); pRegion; pRegion = pInstrument->GetNextRegion())          for (::gig::Region* pRegion = newInstrument->GetFirstRegion(); pRegion; pRegion = newInstrument->GetNextRegion())
213              if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;              if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;
214    
215          InstrumentIdxName = pInstrument->pInfo->Name;          InstrumentIdxName = newInstrument->pInfo->Name;
216          InstrumentStat = 100;          InstrumentStat = 100;
217    
218          // inform audio driver for the need of two channels          ChangeInstrument(newInstrument);
         try {  
             if (pEngine && pEngine->pAudioOutputDevice)  
                 pEngine->pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo  
         }  
         catch (AudioOutputException e) {  
             String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();  
             throw Exception(msg);  
         }  
219    
220          if (pEngine) pEngine->Enable();          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      /**      /**
# Line 266  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 282  namespace LinuxSampler { namespace gig { Line 311  namespace LinuxSampler { namespace gig {
311              pChannelLeft  = new AudioChannel(0, pAudioOut->MaxSamplesPerCycle());              pChannelLeft  = new AudioChannel(0, pAudioOut->MaxSamplesPerCycle());
312              pChannelRight = new AudioChannel(1, pAudioOut->MaxSamplesPerCycle());              pChannelRight = new AudioChannel(1, pAudioOut->MaxSamplesPerCycle());
313          }          }
314            if (pEngine->EngineDisabled.GetUnsafe()) pEngine->Enable();
315          MidiInputPort::AddSysexListener(pEngine);          MidiInputPort::AddSysexListener(pEngine);
316      }      }
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 338  namespace LinuxSampler { namespace gig { Line 396  namespace LinuxSampler { namespace gig {
396              default:              default:
397                  throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));                  throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));
398          }          }
399    
400            bStatusChanged = true;
401      }      }
402    
403      int EngineChannel::OutputChannel(uint EngineAudioChannel) {      int EngineChannel::OutputChannel(uint EngineAudioChannel) {
# Line 390  namespace LinuxSampler { namespace gig { Line 450  namespace LinuxSampler { namespace gig {
450          }          }
451          fxSends.push_back(pFxSend);          fxSends.push_back(pFxSend);
452          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
453            fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());
454    
455          return pFxSend;          return pFxSend;
456      }      }
457    
# Line 427  namespace LinuxSampler { namespace gig { Line 489  namespace LinuxSampler { namespace gig {
489              }              }
490          }          }
491          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
492            fireFxSendCountChanged(iSamplerChannelIndex, GetFxSendCount());
493      }      }
494    
495      /**      /**
# Line 447  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 473  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 494  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 520  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 629  namespace LinuxSampler { namespace gig { Line 700  namespace LinuxSampler { namespace gig {
700          Pitch          = 0;          Pitch          = 0;
701          SustainPedal   = false;          SustainPedal   = false;
702          SostenutoPedal = false;          SostenutoPedal = false;
703          GlobalVolume   = CONFIG_GLOBAL_ATTENUATION;          GlobalVolume   = 1.0f;
704          MidiVolume     = 1.0;          MidiVolume     = 1.0;
705          GlobalPanLeft  = 1.0f;          GlobalPanLeft  = 1.0f;
706          GlobalPanRight = 1.0f;          GlobalPanRight = 1.0f;
707            GlobalTranspose = 0;
708          // set all MIDI controller values to zero          // set all MIDI controller values to zero
709          memset(ControllerTable, 0x00, 129);          memset(ControllerTable, 0x00, 129);
710            // reset all FX Send levels
711            for (
712                std::vector<FxSend*>::iterator iter = fxSends.begin();
713                iter != fxSends.end(); iter++
714            ) {
715                (*iter)->Reset();
716            }
717      }      }
718    
719      /**      /**
# Line 651  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 688  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 696  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.1001  
changed lines
  Added in v.1659

  ViewVC Help
Powered by ViewVC