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

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

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

revision 1321 by schoenebeck, Tue Sep 4 01:12:49 2007 UTC revision 1646 by persson, Sun Jan 20 15:04:51 2008 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
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 29  Line 29 
29    
30  #include "Engine.h"  #include "Engine.h"
31    
32    #include "../../common/global_private.h"
33    
34  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
35    
36      InstrumentResourceManager Engine::instruments;      InstrumentResourceManager Engine::instruments;
# Line 72  namespace LinuxSampler { namespace gig { Line 74  namespace LinuxSampler { namespace gig {
74    
75      /**      /**
76       * Once an engine channel is disconnected from an audio output device,       * Once an engine channel is disconnected from an audio output device,
77       * it wil immediately call this method to unregister itself from the       * it will immediately call this method to unregister itself from the
78       * engine instance and if that engine instance is not used by any other       * engine instance and if that engine instance is not used by any other
79       * engine channel anymore, then that engine instance will be destroyed.       * engine channel anymore, then that engine instance will be destroyed.
80       *       *
# Line 106  namespace LinuxSampler { namespace gig { Line 108  namespace LinuxSampler { namespace gig {
108          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
111          pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];          pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
112            pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
         InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);  
         InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);  
115    
116          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
117              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
# Line 143  namespace LinuxSampler { namespace gig { Line 144  namespace LinuxSampler { namespace gig {
144          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
145          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
146          if (pGlobalEvents) delete pGlobalEvents;          if (pGlobalEvents) delete pGlobalEvents;
147          if (InstrumentChangeQueue) delete InstrumentChangeQueue;          if (pDimRegionPool[0]) delete pDimRegionPool[0];
148          if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;          if (pDimRegionPool[1]) delete pDimRegionPool[1];
         if (pDimRegionsInUse) delete[] pDimRegionsInUse;  
149          ResetSuspendedRegions();          ResetSuspendedRegions();
150          Unregister();          Unregister();
151      }      }
# Line 189  namespace LinuxSampler { namespace gig { Line 189  namespace LinuxSampler { namespace gig {
189       * engine afterwards by calling @c ResumeAll() later on!       * engine afterwards by calling @c ResumeAll() later on!
190       */       */
191      void Engine::SuspendAll() {      void Engine::SuspendAll() {
192          dmsg(1,("gig::Engine: Suspending all ...\n"));          dmsg(2,("gig::Engine: Suspending all ...\n"));
193          // stop the engine, so we can safely modify the engine's          // stop the engine, so we can safely modify the engine's
194          // data structures from this foreign thread          // data structures from this foreign thread
195          DisableAndLock();          DisableAndLock();
# Line 223  namespace LinuxSampler { namespace gig { Line 223  namespace LinuxSampler { namespace gig {
223              if (!iPendingStreamDeletions) break;              if (!iPendingStreamDeletions) break;
224              usleep(10000); // sleep for 10ms              usleep(10000); // sleep for 10ms
225          }          }
226          dmsg(1,("gig::Engine: Everything suspended.\n"));          dmsg(2,("gig::Engine: Everything suspended.\n"));
227      }      }
228    
229      /**      /**
# Line 245  namespace LinuxSampler { namespace gig { Line 245  namespace LinuxSampler { namespace gig {
245       * @param pRegion - region the engine shall stop using       * @param pRegion - region the engine shall stop using
246       */       */
247      void Engine::Suspend(::gig::Region* pRegion) {      void Engine::Suspend(::gig::Region* pRegion) {
248          dmsg(1,("gig::Engine: Suspending Region %x ...\n",pRegion));          dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
249          SuspendedRegionsMutex.Lock();          SuspendedRegionsMutex.Lock();
250          SuspensionChangeOngoing.Set(true);          SuspensionChangeOngoing.Set(true);
251          pPendingRegionSuspension = pRegion;          pPendingRegionSuspension = pRegion;
252          SuspensionChangeOngoing.WaitAndUnlockIf(true);          SuspensionChangeOngoing.WaitAndUnlockIf(true);
253          SuspendedRegionsMutex.Unlock();          SuspendedRegionsMutex.Unlock();
254          dmsg(1,("gig::Engine: Region %x suspended.",pRegion));          dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
255      }      }
256    
257      /**      /**
# Line 261  namespace LinuxSampler { namespace gig { Line 261  namespace LinuxSampler { namespace gig {
261       * @param pRegion - region the engine shall be allowed to use again       * @param pRegion - region the engine shall be allowed to use again
262       */       */
263      void Engine::Resume(::gig::Region* pRegion) {      void Engine::Resume(::gig::Region* pRegion) {
264          dmsg(1,("gig::Engine: Resuming Region %x ...\n",pRegion));          dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
265          SuspendedRegionsMutex.Lock();          SuspendedRegionsMutex.Lock();
266          SuspensionChangeOngoing.Set(true);          SuspensionChangeOngoing.Set(true);
267          pPendingRegionResumption = pRegion;          pPendingRegionResumption = pRegion;
268          SuspensionChangeOngoing.WaitAndUnlockIf(true);          SuspensionChangeOngoing.WaitAndUnlockIf(true);
269          SuspendedRegionsMutex.Unlock();          SuspendedRegionsMutex.Unlock();
270          dmsg(1,("gig::Engine: Region %x resumed.\n",pRegion));          dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
271      }      }
272    
273      /**      /**
# Line 458  namespace LinuxSampler { namespace gig { Line 458  namespace LinuxSampler { namespace gig {
458              // free request slot for next caller (and to make sure that              // free request slot for next caller (and to make sure that
459              // we're not going to process the same request in the next cycle)              // we're not going to process the same request in the next cycle)
460              pPendingRegionSuspension = NULL;              pPendingRegionSuspension = NULL;
461              // if no disk stream deletions are pending, awaker other side, as              // if no disk stream deletions are pending, awaken other side, as
462              // we're done in this case              // we're done in this case
463              if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);              if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
464          }          }
# Line 569  namespace LinuxSampler { namespace gig { Line 569  namespace LinuxSampler { namespace gig {
569       *  @returns       0 on success       *  @returns       0 on success
570       */       */
571      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
572          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
573    
574          // return if engine disabled          // return if engine disabled
575          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 611  namespace LinuxSampler { namespace gig { Line 611  namespace LinuxSampler { namespace gig {
611          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
612    
613          // handle instrument change commands          // handle instrument change commands
614          instrument_change_command_t command;          bool instrumentChanged = false;
615          if (InstrumentChangeQueue->pop(&command) > 0) {          for (int i = 0; i < engineChannels.size(); i++) {
616              EngineChannel* pEngineChannel = command.pEngineChannel;              EngineChannel* pEngineChannel = engineChannels[i];
             pEngineChannel->pInstrument = command.pInstrument;  
   
             //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions  
             ResetSuspendedRegions();  
617    
618              // iterate through all active voices and mark their              // as we're going to (carefully) write some status to the
619              // dimension regions as "in use". The instrument resource              // synchronized struct, we cast away the const
620              // manager may delete all of the instrument except the              EngineChannel::instrument_change_command_t& cmd =
621              // dimension regions and samples that are in use.                  const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
622              int i = 0;  
623              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();              pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
624              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();              pEngineChannel->pDimRegionsInUse->clear();
625              while (iuiKey != end) { // iterate through all active keys  
626                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];              if (cmd.bChangeInstrument) {
627                  ++iuiKey;                  // change instrument
628                    dmsg(5,("Engine: instrument change command received\n"));
629                    cmd.bChangeInstrument = false;
630                    pEngineChannel->pInstrument = cmd.pInstrument;
631                    instrumentChanged = true;
632    
633                    // Iterate through all active voices and mark them as
634                    // "orphans", which means that the dimension regions
635                    // and samples they use should be released to the
636                    // instrument resource manager when the voices die.
637                    int i = 0;
638                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
639                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
640                    while (iuiKey != end) { // iterate through all active keys
641                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
642                        ++iuiKey;
643    
644                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
645                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
646                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
                     if (!itVoice->Orphan) {  
647                          itVoice->Orphan = true;                          itVoice->Orphan = true;
                         pDimRegionsInUse[i++] = itVoice->pDimRgn;  
648                      }                      }
649                  }                  }
650              }              }
651              pDimRegionsInUse[i] = 0; // end of list          }
652            if (instrumentChanged) {
653              // send a reply to the calling thread, which is waiting              //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
654              instrument_change_reply_t reply;              ResetSuspendedRegions();
             InstrumentChangeReplyQueue->push(&reply);  
655          }          }
656    
657          // handle events on all engine channels          // handle events on all engine channels
# Line 686  namespace LinuxSampler { namespace gig { Line 694  namespace LinuxSampler { namespace gig {
694          // been deleted by the disk thread          // been deleted by the disk thread
695          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
696    
697            for (int i = 0; i < engineChannels.size(); i++) {
698                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
699            }
700          FrameTime += Samples;          FrameTime += Samples;
701    
702          return 0;          return 0;
# Line 767  namespace LinuxSampler { namespace gig { Line 778  namespace LinuxSampler { namespace gig {
778                  // now render current voice                  // now render current voice
779                  itVoice->Render(Samples);                  itVoice->Render(Samples);
780                  if (itVoice->IsActive()) { // still active                  if (itVoice->IsActive()) { // still active
781                        if (!itVoice->Orphan) {
782                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
783                        }
784                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
785                      voiceCount++;                      voiceCount++;
786    
# Line 778  namespace LinuxSampler { namespace gig { Line 792  namespace LinuxSampler { namespace gig {
792                  }                  }
793              }              }
794          }          }
795            
796          pEngineChannel->SetVoiceCount(voiceCount);          pEngineChannel->SetVoiceCount(voiceCount);
797          pEngineChannel->SetDiskStreamCount(streamCount);          pEngineChannel->SetDiskStreamCount(streamCount);
798      }      }
# Line 807  namespace LinuxSampler { namespace gig { Line 821  namespace LinuxSampler { namespace gig {
821              if (itNewVoice) {              if (itNewVoice) {
822                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
823                  if (itNewVoice->IsActive()) { // still active                  if (itNewVoice->IsActive()) { // still active
824                        *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
825                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
826                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
827    
# Line 1686  namespace LinuxSampler { namespace gig { Line 1701  namespace LinuxSampler { namespace gig {
1701                  break;                  break;
1702              }              }
1703              case 65: { // portamento on / off              case 65: { // portamento on / off
1704                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1705                  pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64;                  if (bPortamento != pEngineChannel->PortamentoMode)
1706                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1707                    pEngineChannel->PortamentoMode = bPortamento;
1708                  break;                  break;
1709              }              }
1710              case 66: { // sostenuto              case 66: { // sostenuto
# Line 1757  namespace LinuxSampler { namespace gig { Line 1774  namespace LinuxSampler { namespace gig {
1774                  break;                  break;
1775              }              }
1776              case 126: { // mono mode on              case 126: { // mono mode on
1777                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  if (!pEngineChannel->SoloMode)
1778                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1779                  pEngineChannel->SoloMode = true;                  pEngineChannel->SoloMode = true;
1780                  break;                  break;
1781              }              }
1782              case 127: { // poly mode on              case 127: { // poly mode on
1783                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  if (pEngineChannel->SoloMode)
1784                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1785                  pEngineChannel->SoloMode = false;                  pEngineChannel->SoloMode = false;
1786                  break;                  break;
1787              }              }
# Line 1967  namespace LinuxSampler { namespace gig { Line 1986  namespace LinuxSampler { namespace gig {
1986      }      }
1987    
1988      String Engine::Description() {      String Engine::Description() {
1989          return "Gigasampler Engine";          return "Gigasampler Format Engine";
1990      }      }
1991    
1992      String Engine::Version() {      String Engine::Version() {
1993          String s = "$Revision: 1.80 $";          String s = "$Revision: 1.87 $";
1994          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
1995      }      }
1996    
# Line 1980  namespace LinuxSampler { namespace gig { Line 1999  namespace LinuxSampler { namespace gig {
1999      }      }
2000    
2001      // static constant initializers      // static constant initializers
2002      const float* Engine::VolumeCurve(InitVolumeCurve());      const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2003      const float* Engine::PanCurve(InitPanCurve());      const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2004      const float* Engine::CrossfadeCurve(InitCrossfadeCurve());      const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2005    
2006      float* Engine::InitVolumeCurve() {      float* Engine::InitVolumeCurve() {
2007          // line-segment approximation          // line-segment approximation
# Line 2021  namespace LinuxSampler { namespace gig { Line 2040  namespace LinuxSampler { namespace gig {
2040          return y;          return y;
2041      }      }
2042    
     /**  
      * Changes the instrument for an engine channel.  
      *  
      * @param pEngineChannel - engine channel on which the instrument  
      *                         should be changed  
      * @param pInstrument - new instrument  
      * @returns a list of dimension regions from the old instrument  
      *          that are still in use  
      */  
     ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {  
         instrument_change_command_t command;  
         command.pEngineChannel = pEngineChannel;  
         command.pInstrument = pInstrument;  
         InstrumentChangeQueue->push(&command);  
   
         // wait for the audio thread to confirm that the instrument  
         // change has been done  
         instrument_change_reply_t reply;  
         while (InstrumentChangeReplyQueue->pop(&reply) == 0) {  
             usleep(10000);  
         }  
         return pDimRegionsInUse;  
     }  
   
2043  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.1321  
changed lines
  Added in v.1646

  ViewVC Help
Powered by ViewVC