/[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 665 by schoenebeck, Sun Jun 19 15:11:20 2005 UTC revision 1297 by iliev, Thu Aug 16 15:55:21 2007 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 Christian Schoenebeck                              *   *   Copyright (C) 2005-2007 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    
 #if defined(__APPLE__)  
 # include <stdlib.h>  
 #else  
 # include <malloc.h>  
 #endif  
   
32  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
33    
34      InstrumentResourceManager Engine::instruments;      InstrumentResourceManager Engine::instruments;
# Line 57  namespace LinuxSampler { namespace gig { Line 51  namespace LinuxSampler { namespace gig {
51          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
52              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
53              pEngine = engines[pDevice];              pEngine = engines[pDevice];
54    
55                // Disable the engine while the new engine channel is
56                // added and initialized. The engine will be enabled again
57                // in EngineChannel::Connect.
58                pEngine->DisableAndLock();
59          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
60              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
61              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 103  namespace LinuxSampler { namespace gig { Line 102  namespace LinuxSampler { namespace gig {
102          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
103          pDiskThread        = NULL;          pDiskThread        = NULL;
104          pEventGenerator    = NULL;          pEventGenerator    = NULL;
105          pSysexBuffer       = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
106          pEventQueue        = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
107          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
108          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
109            pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];
110          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
111          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
112            InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);
113            InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);
114    
115          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()) {
116              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
117          }          }
118          pVoicePool->clear();          pVoicePool->clear();
119    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
120          ResetInternal();          ResetInternal();
121          ResetScaleTuning();          ResetScaleTuning();
122      }      }
# Line 126  namespace LinuxSampler { namespace gig { Line 125  namespace LinuxSampler { namespace gig {
125       * Destructor       * Destructor
126       */       */
127      Engine::~Engine() {      Engine::~Engine() {
128            MidiInputPort::RemoveSysexListener(this);
129          if (pDiskThread) {          if (pDiskThread) {
130              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
131              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 139  namespace LinuxSampler { namespace gig { Line 139  namespace LinuxSampler { namespace gig {
139              delete pVoicePool;              delete pVoicePool;
140          }          }
141          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
142          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
143          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
144          EngineFactory::Destroy(this);          if (pGlobalEvents) delete pGlobalEvents;
145            if (InstrumentChangeQueue) delete InstrumentChangeQueue;
146            if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;
147            if (pDimRegionsInUse) delete[] pDimRegionsInUse;
148            Unregister();
149      }      }
150    
151      void Engine::Enable() {      void Engine::Enable() {
# Line 178  namespace LinuxSampler { namespace gig { Line 179  namespace LinuxSampler { namespace gig {
179    
180      /**      /**
181       *  Reset all voices and disk thread and clear input event queue and all       *  Reset all voices and disk thread and clear input event queue and all
182       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
183       */       */
184      void Engine::ResetInternal() {      void Engine::ResetInternal() {
185            ResetInternalMutex.Lock();
186    
187            // make sure that the engine does not get any sysex messages
188            // while it's reseting
189            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
190          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
191          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
192    
# Line 203  namespace LinuxSampler { namespace gig { Line 209  namespace LinuxSampler { namespace gig {
209    
210          // delete all input events          // delete all input events
211          pEventQueue->init();          pEventQueue->init();
212            pSysexBuffer->init();
213            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
214            ResetInternalMutex.Unlock();
215      }      }
216    
217      /**      /**
# Line 232  namespace LinuxSampler { namespace gig { Line 241  namespace LinuxSampler { namespace gig {
241          }          }
242          catch (AudioOutputException e) {          catch (AudioOutputException e) {
243              String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();              String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();
244              throw LinuxSamplerException(msg);              throw Exception(msg);
245          }          }
246    
247          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
# Line 240  namespace LinuxSampler { namespace gig { Line 249  namespace LinuxSampler { namespace gig {
249    
250          // FIXME: audio drivers with varying fragment sizes might be a problem here          // FIXME: audio drivers with varying fragment sizes might be a problem here
251          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
252          if (MaxFadeOutPos < 0)          if (MaxFadeOutPos < 0) {
253              throw LinuxSamplerException("CONFIG_EG_MIN_RELEASE_TIME too big for current audio fragment size / sampling rate!");              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
254                          << "too big for current audio fragment size & sampling rate! "
255                          << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
256                // force volume ramp downs at the beginning of each fragment
257                MaxFadeOutPos = 0;
258                // lower minimum release time
259                const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
260                for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
261                    iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
262                }
263                pVoicePool->clear();
264            }
265    
266          // (re)create disk thread          // (re)create disk thread
267          if (this->pDiskThread) {          if (this->pDiskThread) {
# Line 250  namespace LinuxSampler { namespace gig { Line 270  namespace LinuxSampler { namespace gig {
270              delete this->pDiskThread;              delete this->pDiskThread;
271              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
272          }          }
273          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
274                                               &instruments);
275          if (!pDiskThread) {          if (!pDiskThread) {
276              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
277              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 266  namespace LinuxSampler { namespace gig { Line 287  namespace LinuxSampler { namespace gig {
287          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
288          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
289    
         // (re)allocate synthesis parameter matrix  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
   
         #if defined(__APPLE__)  
         pSynthesisParameters[0] = (float *) malloc(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle());  
         #else  
         pSynthesisParameters[0] = (float *) memalign(16,(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle()));  
         #endif  
         for (int dst = 1; dst < Event::destination_count; dst++)  
             pSynthesisParameters[dst] = pSynthesisParameters[dst - 1] + pAudioOut->MaxSamplesPerCycle();  
   
         // (re)allocate biquad filter parameter sequence  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pMainFilterParameters)  delete[] pMainFilterParameters;  
         pBasicFilterParameters = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()];  
         pMainFilterParameters  = new biquad_param_t[pAudioOut->MaxSamplesPerCycle()];  
   
290          dmsg(1,("Starting disk thread..."));          dmsg(1,("Starting disk thread..."));
291          pDiskThread->StartThread();          pDiskThread->StartThread();
292          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
# Line 316  namespace LinuxSampler { namespace gig { Line 320  namespace LinuxSampler { namespace gig {
320       *                  current audio cycle       *                  current audio cycle
321       */       */
322      void Engine::ImportEvents(uint Samples) {      void Engine::ImportEvents(uint Samples) {
323          RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
324          Event* pEvent;          Event* pEvent;
325          while (true) {          while (true) {
326              // get next event from input event queue              // get next event from input event queue
# Line 339  namespace LinuxSampler { namespace gig { Line 343  namespace LinuxSampler { namespace gig {
343      }      }
344    
345      /**      /**
346       *  Let this engine proceed to render the given amount of sample points. The       * Let this engine proceed to render the given amount of sample points.
347       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
348       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
349       *  converted to the appropriate value range by the audio output class (e.g.       * all voices of each engine channel will be placed into the audio sum
350       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
351         * respective engine channel.
352       *       *
353       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
354       *  @returns       0 on success       *  @returns       0 on success
355       */       */
356      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
357          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));
358    
359          // return if engine disabled          // return if engine disabled
360          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 386  namespace LinuxSampler { namespace gig { Line 391  namespace LinuxSampler { namespace gig {
391          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
392          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
393    
394            // handle instrument change commands
395            instrument_change_command_t command;
396            if (InstrumentChangeQueue->pop(&command) > 0) {
397                EngineChannel* pEngineChannel = command.pEngineChannel;
398                pEngineChannel->pInstrument = command.pInstrument;
399    
400                // iterate through all active voices and mark their
401                // dimension regions as "in use". The instrument resource
402                // manager may delete all of the instrument except the
403                // dimension regions and samples that are in use.
404                int i = 0;
405                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
406                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
407                while (iuiKey != end) { // iterate through all active keys
408                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
409                    ++iuiKey;
410    
411                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
412                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
413                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
414                        if (!itVoice->Orphan) {
415                            itVoice->Orphan = true;
416                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
417                        }
418                    }
419                }
420                pDimRegionsInUse[i] = 0; // end of list
421    
422                // send a reply to the calling thread, which is waiting
423                instrument_change_reply_t reply;
424                InstrumentChangeReplyQueue->push(&reply);
425            }
426    
427          // handle events on all engine channels          // handle events on all engine channels
428          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
429              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
430          }          }
431    
432          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
433          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
434              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
435          }          }
436    
437          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
438          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
439    
440            // handle audio routing for engine channels with FX sends
441            for (int i = 0; i < engineChannels.size(); i++) {
442                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
443                RouteAudio(engineChannels[i], Samples);
444            }
445    
446          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
447          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
448              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
449          }          }
450    
# Line 481  namespace LinuxSampler { namespace gig { Line 522  namespace LinuxSampler { namespace gig {
522       *                         this audio fragment cycle       *                         this audio fragment cycle
523       */       */
524      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
525            #if !CONFIG_PROCESS_MUTED_CHANNELS
526            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
527            #endif
528    
529            uint vc = 0;
530            uint sc = 0;
531          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
532          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
533          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 492  namespace LinuxSampler { namespace gig { Line 539  namespace LinuxSampler { namespace gig {
539              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
540                  // now render current voice                  // now render current voice
541                  itVoice->Render(Samples);                  itVoice->Render(Samples);
542                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
543                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
544                        vc++;
545    
546                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
547                            if ((itVoice->DiskStreamRef).State == Stream::state_active) sc++;
548                        }
549                    }  else { // voice reached end, is now inactive
550                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
551                  }                  }
552              }              }
553          }          }
554            
555            pEngineChannel->SetVoiceCount(vc);
556            pEngineChannel->SetDiskStreamCount(sc);
557      }      }
558    
559      /**      /**
# Line 518  namespace LinuxSampler { namespace gig { Line 574  namespace LinuxSampler { namespace gig {
574          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
575          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
576              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
577                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
578              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
579                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false);                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
580              if (itNewVoice) {              if (itNewVoice) {
581                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
582                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
583                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
584                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
585    
586                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
587                            if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
588                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
589                            }
590                        }
591                    } else { // voice reached end, is now inactive
592                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
593                  }                  }
594              }              }
# Line 537  namespace LinuxSampler { namespace gig { Line 602  namespace LinuxSampler { namespace gig {
602      }      }
603    
604      /**      /**
605         * Will be called in case the respective engine channel sports FX send
606         * channels. In this particular case, engine channel local buffers are
607         * used to render and mix all voices to. This method is responsible for
608         * copying the audio data from those local buffers to the master audio
609         * output channels as well as to the FX send audio output channels with
610         * their respective FX send levels.
611         *
612         * @param pEngineChannel - engine channel from which audio should be
613         *                         routed
614         * @param Samples        - amount of sample points to be routed in
615         *                         this audio fragment cycle
616         */
617        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
618            // route master signal
619            {
620                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
621                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
622                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
623                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
624            }
625            // route FX send signal
626            {
627                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
628                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
629                    // left channel
630                    const int iDstL = pFxSend->DestinationChannel(0);
631                    if (iDstL < 0) {
632                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
633                    } else {
634                        AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
635                        if (!pDstL) {
636                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
637                        } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
638                    }
639                    // right channel
640                    const int iDstR = pFxSend->DestinationChannel(1);
641                    if (iDstR < 0) {
642                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
643                    } else {
644                        AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
645                        if (!pDstR) {
646                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
647                        } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
648                    }
649                }
650            }
651            // reset buffers with silence (zero out) for the next audio cycle
652            pEngineChannel->pChannelLeft->Clear();
653            pEngineChannel->pChannelRight->Clear();
654        }
655    
656        /**
657       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
658       * the list of active keys and clear all event lists on that engine       * the list of active keys and clear all event lists on that engine
659       * channel.       * channel.
# Line 609  namespace LinuxSampler { namespace gig { Line 726  namespace LinuxSampler { namespace gig {
726       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
727       */       */
728      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
729            #if !CONFIG_PROCESS_MUTED_CHANNELS
730            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
731            #endif
732    
733            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
734    
735            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
736            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
737    
738          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
739            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
740    
741            // move note on event to the key's own event list
742            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
743    
744            // if Solo Mode then kill all already active voices
745            if (pEngineChannel->SoloMode) {
746                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
747                if (itYoungestKey) {
748                    const int iYoungestKey = *itYoungestKey;
749                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
750                    if (pOtherKey->Active) {
751                        // get final portamento position of currently active voice
752                        if (pEngineChannel->PortamentoMode) {
753                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
754                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
755                        }
756                        // kill all voices on the (other) key
757                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
758                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
759                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
760                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
761                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
762                        }
763                    }
764                }
765                // set this key as 'currently active solo key'
766                pEngineChannel->SoloKey = key;
767            }
768    
769          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
770          {          {
771              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
772              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
773                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
774                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
775          }          }
776    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
777          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
778          pKey->Velocity   = itNoteOnEvent->Param.Note.Velocity;          pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
779          pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length          pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
780    
781          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
782          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
783              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
784              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
785                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
786                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
787              }              }
788              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
789          }          }
790    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
791          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
792          {          {
793              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
# Line 647  namespace LinuxSampler { namespace gig { Line 796  namespace LinuxSampler { namespace gig {
796                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
797                  // now launch the required amount of voices                  // now launch the required amount of voices
798                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
799                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true);                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
800              }              }
801          }          }
802    
# Line 655  namespace LinuxSampler { namespace gig { Line 804  namespace LinuxSampler { namespace gig {
804          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
805              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
806    
807            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
808          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
809      }      }
810    
# Line 668  namespace LinuxSampler { namespace gig { Line 818  namespace LinuxSampler { namespace gig {
818       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
819       */       */
820      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
821          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
822            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
823            #endif
824    
825            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
826            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
827    
828            const int iKey = itNoteOffEvent->Param.Note.Key;
829            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
830          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
831    
832          // release voices on this key if needed          // move event to the key's own event list
833          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
834              itNoteOffEvent->Type = Event::type_release; // transform event type  
835            bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
836    
837              // move event to the key's own event list          // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
838              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
839                bool bOtherKeysPressed = false;
840                if (iKey == pEngineChannel->SoloKey) {
841                    pEngineChannel->SoloKey = -1;
842                    // if there's still a key pressed down, respawn a voice (group) on the highest key
843                    for (int i = 127; i > 0; i--) {
844                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
845                        if (pOtherKey->KeyPressed) {
846                            bOtherKeysPressed = true;
847                            // make the other key the new 'currently active solo key'
848                            pEngineChannel->SoloKey = i;
849                            // get final portamento position of currently active voice
850                            if (pEngineChannel->PortamentoMode) {
851                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
852                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
853                            }
854                            // create a pseudo note on event
855                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
856                            if (itPseudoNoteOnEvent) {
857                                // copy event
858                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
859                                // transform event to a note on event
860                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
861                                itPseudoNoteOnEvent->Param.Note.Key      = i;
862                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
863                                // allocate and trigger new voice(s) for the other key
864                                {
865                                    // first, get total amount of required voices (dependant on amount of layers)
866                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
867                                    if (pRegion) {
868                                        int voicesRequired = pRegion->Layers;
869                                        // now launch the required amount of voices
870                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
871                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
872                                    }
873                                }
874                                // if neither a voice was spawned or postponed then remove note on event from key again
875                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
876                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
877    
878                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
879                            break; // done
880                        }
881                    }
882                }
883                if (bOtherKeysPressed) {
884                    if (pKey->Active) { // kill all voices on this key
885                        bShouldRelease = false; // no need to release, as we kill it here
886                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
887                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
888                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
889                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
890                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
891                        }
892                    }
893                } else pEngineChannel->PortamentoPos = -1.0f;
894            }
895    
896            // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
897            if (bShouldRelease) {
898                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
899    
900              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
901              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
902                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
903                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
904                  if (pRegion) {                  if (pRegion) {
# Line 691  namespace LinuxSampler { namespace gig { Line 909  namespace LinuxSampler { namespace gig {
909    
910                      // now launch the required amount of voices                      // now launch the required amount of voices
911                      for (int i = 0; i < voicesRequired; i++)                      for (int i = 0; i < voicesRequired; i++)
912                          LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples                          LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
913                  }                  }
914                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
915              }              }
   
             // if neither a voice was spawned or postponed then remove note off event from key again  
             if (!pKey->Active && !pKey->VoiceTheftsQueued)  
                 pKey->pEvents->free(itNoteOffEventOnKeyList);  
916          }          }
917    
918            // if neither a voice was spawned or postponed on this key then remove note off event from key again
919            if (!pKey->Active && !pKey->VoiceTheftsQueued)
920                pKey->pEvents->free(itNoteOffEventOnKeyList);
921      }      }
922    
923      /**      /**
924       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
925       *  event list.       *  channel's event list. It will actually processed later by the
926         *  respective voice.
927       *       *
928       *  @param pEngineChannel - engine channel on which this event occured on       *  @param pEngineChannel - engine channel on which this event occured on
929       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
930       */       */
931      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
932          pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value          pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
         itPitchbendEvent.moveToEndOf(pEngineChannel->pSynthesisEvents[Event::destination_vco]);  
933      }      }
934    
935      /**      /**
# Line 728  namespace LinuxSampler { namespace gig { Line 946  namespace LinuxSampler { namespace gig {
946       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
947       *                               when there is no free voice       *                               when there is no free voice
948       *                               (optional, default = true)       *                               (optional, default = true)
949         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
950         *                                   key group conflict
951       *  @returns pointer to new voice or NULL if there was no free voice or       *  @returns pointer to new voice or NULL if there was no free voice or
952       *           if the voice wasn't triggered (for example when no region is       *           if the voice wasn't triggered (for example when no region is
953       *           defined for the given key).       *           defined for the given key).
954       */       */
955      Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) {      Pool<Voice>::Iterator Engine::LaunchVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing, bool HandleKeyGroupConflicts) {
956          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
957            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
958            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
959    
960            // if nothing defined for this key
961            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
962    
963            // only mark the first voice of a layered voice (group) to be in a
964            // key group, so the layered voices won't kill each other
965            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
966    
967            // handle key group (a.k.a. exclusive group) conflicts
968            if (HandleKeyGroupConflicts) {
969                if (iKeyGroup) { // if this voice / key belongs to a key group
970                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
971                    if (*ppKeyGroup) { // if there's already an active key in that key group
972                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
973                        // kill all voices on the (other) key
974                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
975                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
976                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
977                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
978                                itVoiceToBeKilled->Kill(itNoteOnEvent);
979                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
980                            }
981                        }
982                    }
983                }
984            }
985    
986            Voice::type_t VoiceType = Voice::type_normal;
987    
988            // get current dimension values to select the right dimension region
989            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
990            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
991            uint DimValues[8] = { 0 };
992            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
993                switch (pRegion->pDimensionDefinitions[i].dimension) {
994                    case ::gig::dimension_samplechannel:
995                        DimValues[i] = 0; //TODO: we currently ignore this dimension
996                        break;
997                    case ::gig::dimension_layer:
998                        DimValues[i] = iLayer;
999                        break;
1000                    case ::gig::dimension_velocity:
1001                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1002                        break;
1003                    case ::gig::dimension_channelaftertouch:
1004                        DimValues[i] = pEngineChannel->ControllerTable[128];
1005                        break;
1006                    case ::gig::dimension_releasetrigger:
1007                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1008                        DimValues[i] = (uint) ReleaseTriggerVoice;
1009                        break;
1010                    case ::gig::dimension_keyboard:
1011                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1012                        break;
1013                    case ::gig::dimension_roundrobin:
1014                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1015                        break;
1016                    case ::gig::dimension_random:
1017                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1018                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1019                        break;
1020                    case ::gig::dimension_modwheel:
1021                        DimValues[i] = pEngineChannel->ControllerTable[1];
1022                        break;
1023                    case ::gig::dimension_breath:
1024                        DimValues[i] = pEngineChannel->ControllerTable[2];
1025                        break;
1026                    case ::gig::dimension_foot:
1027                        DimValues[i] = pEngineChannel->ControllerTable[4];
1028                        break;
1029                    case ::gig::dimension_portamentotime:
1030                        DimValues[i] = pEngineChannel->ControllerTable[5];
1031                        break;
1032                    case ::gig::dimension_effect1:
1033                        DimValues[i] = pEngineChannel->ControllerTable[12];
1034                        break;
1035                    case ::gig::dimension_effect2:
1036                        DimValues[i] = pEngineChannel->ControllerTable[13];
1037                        break;
1038                    case ::gig::dimension_genpurpose1:
1039                        DimValues[i] = pEngineChannel->ControllerTable[16];
1040                        break;
1041                    case ::gig::dimension_genpurpose2:
1042                        DimValues[i] = pEngineChannel->ControllerTable[17];
1043                        break;
1044                    case ::gig::dimension_genpurpose3:
1045                        DimValues[i] = pEngineChannel->ControllerTable[18];
1046                        break;
1047                    case ::gig::dimension_genpurpose4:
1048                        DimValues[i] = pEngineChannel->ControllerTable[19];
1049                        break;
1050                    case ::gig::dimension_sustainpedal:
1051                        DimValues[i] = pEngineChannel->ControllerTable[64];
1052                        break;
1053                    case ::gig::dimension_portamento:
1054                        DimValues[i] = pEngineChannel->ControllerTable[65];
1055                        break;
1056                    case ::gig::dimension_sostenutopedal:
1057                        DimValues[i] = pEngineChannel->ControllerTable[66];
1058                        break;
1059                    case ::gig::dimension_softpedal:
1060                        DimValues[i] = pEngineChannel->ControllerTable[67];
1061                        break;
1062                    case ::gig::dimension_genpurpose5:
1063                        DimValues[i] = pEngineChannel->ControllerTable[80];
1064                        break;
1065                    case ::gig::dimension_genpurpose6:
1066                        DimValues[i] = pEngineChannel->ControllerTable[81];
1067                        break;
1068                    case ::gig::dimension_genpurpose7:
1069                        DimValues[i] = pEngineChannel->ControllerTable[82];
1070                        break;
1071                    case ::gig::dimension_genpurpose8:
1072                        DimValues[i] = pEngineChannel->ControllerTable[83];
1073                        break;
1074                    case ::gig::dimension_effect1depth:
1075                        DimValues[i] = pEngineChannel->ControllerTable[91];
1076                        break;
1077                    case ::gig::dimension_effect2depth:
1078                        DimValues[i] = pEngineChannel->ControllerTable[92];
1079                        break;
1080                    case ::gig::dimension_effect3depth:
1081                        DimValues[i] = pEngineChannel->ControllerTable[93];
1082                        break;
1083                    case ::gig::dimension_effect4depth:
1084                        DimValues[i] = pEngineChannel->ControllerTable[94];
1085                        break;
1086                    case ::gig::dimension_effect5depth:
1087                        DimValues[i] = pEngineChannel->ControllerTable[95];
1088                        break;
1089                    case ::gig::dimension_none:
1090                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1091                        break;
1092                    default:
1093                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1094                }
1095            }
1096    
1097            // return if this is a release triggered voice and there is no
1098            // releasetrigger dimension (could happen if an instrument
1099            // change has occured between note on and off)
1100            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1101    
1102            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1103    
1104            // no need to continue if sample is silent
1105            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1106    
1107          // allocate a new voice for the key          // allocate a new voice for the key
1108          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1109          if (itNewVoice) {          if (itNewVoice) {
1110              // launch the new voice              // launch the new voice
1111              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pEngineChannel->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1112                  dmsg(4,("Voice not triggered\n"));                  dmsg(4,("Voice not triggered\n"));
1113                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1114              }              }
1115              else { // on success              else { // on success
1116                  --VoiceSpawnsLeft;                  --VoiceSpawnsLeft;
                 uint** ppKeyGroup = NULL;  
                 if (itNewVoice->KeyGroup) { // if this voice / key belongs to a key group  
                     ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];  
                     if (*ppKeyGroup) { // if there's already an active key in that key group  
                         midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];  
                         // kill all voices on the (other) key  
                         RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();  
                         RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();  
                         for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {  
                             if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {  
                                 itVoiceToBeKilled->Kill(itNoteOnEvent);  
                                 --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict  
                             }  
                         }  
                     }  
                 }  
1117                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1118                      pKey->Active = true;                      pKey->Active = true;
1119                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1120                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1121                  }                  }
1122                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1123                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1124                      *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group                      *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
1125                  }                  }
1126                  if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)                  if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
# Line 974  namespace LinuxSampler { namespace gig { Line 1328  namespace LinuxSampler { namespace gig {
1328    
1329              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1330    
1331                // if the sample and dimension region belong to an
1332                // instrument that is unloaded, tell the disk thread to
1333                // release them
1334                if (itVoice->Orphan) {
1335                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1336                }
1337    
1338              // free the voice object              // free the voice object
1339              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1340    
# Line 1018  namespace LinuxSampler { namespace gig { Line 1379  namespace LinuxSampler { namespace gig {
1379          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1380          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1381    
1382          // move event from the unsorted event list to the control change event list          // handle hard coded MIDI controllers
1383          Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pCCEvents);          switch (itControlChangeEvent->Param.CC.Controller) {
1384                case 5: { // portamento time
1385          switch (itControlChangeEventOnCCList->Param.CC.Controller) {                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1386                    break;
1387                }
1388                case 6: { // data entry (currently only used for RPN controllers)
1389                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1390                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1391                        // limit to +- two octaves for now
1392                        transpose = RTMath::Min(transpose,  24);
1393                        transpose = RTMath::Max(transpose, -24);
1394                        pEngineChannel->GlobalTranspose = transpose;
1395                        // workaround, so we won't have hanging notes
1396                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1397                    }
1398                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1399                    pEngineChannel->ResetMidiRpnController();
1400                    break;
1401                }
1402              case 7: { // volume              case 7: { // volume
1403                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1404                  pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1405                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1406                  break;                  break;
1407              }              }
1408              case 10: { // panpot              case 10: { // panpot
1409                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1410                  const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1411                  pEngineChannel->GlobalPanLeft  = 1.0f - float(RTMath::Max(pan, 0)) /  63.0f;                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
                 pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f;  
1412                  break;                  break;
1413              }              }
1414              case 64: { // sustain              case 64: { // sustain
1415                  if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1416                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1417                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1418    
1419                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1420                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1421                        #endif
1422    
1423                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1424                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1425                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
# Line 1047  namespace LinuxSampler { namespace gig { Line 1427  namespace LinuxSampler { namespace gig {
1427                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed) {
1428                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1429                              if (itNewEvent) {                              if (itNewEvent) {
1430                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1431                                  itNewEvent->Type = Event::type_cancel_release; // transform event type                                  itNewEvent->Type = Event::type_cancel_release; // transform event type
1432                              }                              }
1433                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
1434                          }                          }
1435                      }                      }
1436                  }                  }
1437                  if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1438                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1439                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1440    
1441                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1442                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1443                        #endif
1444    
1445                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1446                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1447                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1448                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1449                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1450                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1451                                if (itNewEvent) {
1452                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1453                                    itNewEvent->Type = Event::type_release; // transform event type
1454                                }
1455                                else dmsg(1,("Event pool emtpy!\n"));
1456                            }
1457                        }
1458                    }
1459                    break;
1460                }
1461                case 65: { // portamento on / off
1462                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1463                    pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64;
1464                    break;
1465                }
1466                case 66: { // sostenuto
1467                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1468                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1469                        pEngineChannel->SostenutoPedal = true;
1470    
1471                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1472                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1473                        #endif
1474    
1475                        SostenutoKeyCount = 0;
1476                        // Remeber the pressed keys
1477                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1478                        for (; iuiKey; ++iuiKey) {
1479                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1480                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1481                        }
1482                    }
1483                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1484                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1485                        pEngineChannel->SostenutoPedal = false;
1486    
1487                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1488                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1489                        #endif
1490    
1491                        // release voices if the damper pedal is up and their respective key is not pressed
1492                        for (int i = 0; i < SostenutoKeyCount; i++) {
1493                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1494                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1495                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1496                              if (itNewEvent) {                              if (itNewEvent) {
1497                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1498                                  itNewEvent->Type = Event::type_release; // transform event type                                  itNewEvent->Type = Event::type_release; // transform event type
1499                              }                              }
1500                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
# Line 1074  namespace LinuxSampler { namespace gig { Line 1503  namespace LinuxSampler { namespace gig {
1503                  }                  }
1504                  break;                  break;
1505              }              }
1506                case 100: { // RPN controller LSB
1507                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1508                    break;
1509                }
1510                case 101: { // RPN controller MSB
1511                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1512                    break;
1513                }
1514    
1515    
1516              // Channel Mode Messages              // Channel Mode Messages
1517    
1518              case 120: { // all sound off              case 120: { // all sound off
1519                  KillAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1520                  break;                  break;
1521              }              }
1522              case 121: { // reset all controllers              case 121: { // reset all controllers
# Line 1087  namespace LinuxSampler { namespace gig { Line 1524  namespace LinuxSampler { namespace gig {
1524                  break;                  break;
1525              }              }
1526              case 123: { // all notes off              case 123: { // all notes off
1527                  ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  #if CONFIG_PROCESS_ALL_NOTES_OFF
1528                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1529                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1530                  break;                  break;
1531              }              }
1532                case 126: { // mono mode on
1533                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1534                    pEngineChannel->SoloMode = true;
1535                    break;
1536                }
1537                case 127: { // poly mode on
1538                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1539                    pEngineChannel->SoloMode = false;
1540                    break;
1541                }
1542            }
1543    
1544            // handle FX send controllers
1545            if (!pEngineChannel->fxSends.empty()) {
1546                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1547                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1548                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1549                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1550                        pFxSend->SetInfoChanged(true);
1551                }
1552          }          }
1553      }      }
1554    
# Line 1099  namespace LinuxSampler { namespace gig { Line 1558  namespace LinuxSampler { namespace gig {
1558       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1559       */       */
1560      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1561          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1562    
1563          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1564          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1118  namespace LinuxSampler { namespace gig { Line 1577  namespace LinuxSampler { namespace gig {
1577    
1578                  // command address                  // command address
1579                  uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)                  uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
1580                  const RingBuffer<uint8_t>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later                  const RingBuffer<uint8_t,false>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
1581                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1582                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1583                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
# Line 1165  namespace LinuxSampler { namespace gig { Line 1624  namespace LinuxSampler { namespace gig {
1624       *                     question       *                     question
1625       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1626       */       */
1627      uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t>::NonVolatileReader AddrReader, uint DataSize) {      uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t,false>::NonVolatileReader AddrReader, uint DataSize) {
1628          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1629          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1630          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1631          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1231  namespace LinuxSampler { namespace gig { Line 1690  namespace LinuxSampler { namespace gig {
1690      }      }
1691    
1692      /**      /**
1693       * Initialize the parameter sequence for the modulation destination given by       * Determines whether the specified voice should be released.
1694       * by 'dst' with the constant value given by val.       *
1695       */       * @param pEngineChannel - The engine channel on which the voice should be checked
1696      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {       * @param Key - The key number
1697          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();       * @returns true if the specified should be released, false otherwise.
1698          float* m = &pSynthesisParameters[dst][0];       */
1699          for (int i = 0; i < maxsamples; i += 4) {      bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
1700             m[i]   = val;          if (pEngineChannel->SustainPedal) return false;
1701             m[i+1] = val;  
1702             m[i+2] = val;          if (pEngineChannel->SostenutoPedal) {
1703             m[i+3] = val;              for (int i = 0; i < SostenutoKeyCount; i++)
1704                    if (Key == SostenutoKeys[i]) return false;
1705          }          }
1706    
1707            return true;
1708      }      }
1709    
1710      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
# Line 1282  namespace LinuxSampler { namespace gig { Line 1744  namespace LinuxSampler { namespace gig {
1744      }      }
1745    
1746      String Engine::Version() {      String Engine::Version() {
1747          String s = "$Revision: 1.45 $";          String s = "$Revision: 1.78 $";
1748          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
1749      }      }
1750    
1751        InstrumentManager* Engine::GetInstrumentManager() {
1752            return &instruments;
1753        }
1754    
1755        // static constant initializers
1756        const float* Engine::VolumeCurve(InitVolumeCurve());
1757        const float* Engine::PanCurve(InitPanCurve());
1758        const float* Engine::CrossfadeCurve(InitCrossfadeCurve());
1759    
1760        float* Engine::InitVolumeCurve() {
1761            // line-segment approximation
1762            const float segments[] = {
1763                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
1764                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
1765            };
1766            return InitCurve(segments);
1767        }
1768    
1769        float* Engine::InitPanCurve() {
1770            // line-segment approximation
1771            const float segments[] = {
1772                0, 0, 1, 0,
1773                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
1774                127, 1.41, 128, 1.41
1775            };
1776            return InitCurve(segments, 129);
1777        }
1778    
1779        float* Engine::InitCrossfadeCurve() {
1780            // line-segment approximation
1781            const float segments[] = {
1782                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
1783            };
1784            return InitCurve(segments);
1785        }
1786    
1787        float* Engine::InitCurve(const float* segments, int size) {
1788            float* y = new float[size];
1789            for (int x = 0 ; x < size ; x++) {
1790                if (x > segments[2]) segments += 2;
1791                y[x] = segments[1] + (x - segments[0]) *
1792                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
1793            }
1794            return y;
1795        }
1796    
1797        /**
1798         * Changes the instrument for an engine channel.
1799         *
1800         * @param pEngineChannel - engine channel on which the instrument
1801         *                         should be changed
1802         * @param pInstrument - new instrument
1803         * @returns a list of dimension regions from the old instrument
1804         *          that are still in use
1805         */
1806        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
1807            instrument_change_command_t command;
1808            command.pEngineChannel = pEngineChannel;
1809            command.pInstrument = pInstrument;
1810            InstrumentChangeQueue->push(&command);
1811    
1812            // wait for the audio thread to confirm that the instrument
1813            // change has been done
1814            instrument_change_reply_t reply;
1815            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
1816                usleep(10000);
1817            }
1818            return pDimRegionsInUse;
1819        }
1820    
1821  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.665  
changed lines
  Added in v.1297

  ViewVC Help
Powered by ViewVC