/[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 659 by schoenebeck, Thu Jun 16 21:35:30 2005 UTC revision 1722 by schoenebeck, Thu Apr 10 17:41:32 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 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  #if defined(__APPLE__)  #include "../../common/global_private.h"
 # include <stdlib.h>  
 #else  
 # include <malloc.h>  
 #endif  
33    
34  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
35    
# Line 57  namespace LinuxSampler { namespace gig { Line 53  namespace LinuxSampler { namespace gig {
53          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
54              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
55              pEngine = engines[pDevice];              pEngine = engines[pDevice];
56    
57                // Disable the engine while the new engine channel is
58                // added and initialized. The engine will be enabled again
59                // in EngineChannel::Connect.
60                pEngine->DisableAndLock();
61          } 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
62              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
63              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 73  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 99  namespace LinuxSampler { namespace gig { Line 100  namespace LinuxSampler { namespace gig {
100      /**      /**
101       * Constructor       * Constructor
102       */       */
103      Engine::Engine() {      Engine::Engine() : SuspendedRegions(128) {
104          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
105          pDiskThread        = NULL;          pDiskThread        = NULL;
106          pEventGenerator    = NULL;          pEventGenerator    = NULL;
107          pSysexBuffer       = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
108          pEventQueue        = new RingBuffer<Event>(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            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);
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);
118          }          }
119          pVoicePool->clear();          pVoicePool->clear();
120    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
121          ResetInternal();          ResetInternal();
122          ResetScaleTuning();          ResetScaleTuning();
123            ResetSuspendedRegions();
124      }      }
125    
126      /**      /**
127       * Destructor       * Destructor
128       */       */
129      Engine::~Engine() {      Engine::~Engine() {
130            MidiInputPort::RemoveSysexListener(this);
131          if (pDiskThread) {          if (pDiskThread) {
132              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
133              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 139  namespace LinuxSampler { namespace gig { Line 141  namespace LinuxSampler { namespace gig {
141              delete pVoicePool;              delete pVoicePool;
142          }          }
143          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
144          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
145          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
146          EngineFactory::Destroy(this);          if (pGlobalEvents) delete pGlobalEvents;
147            if (pDimRegionPool[0]) delete pDimRegionPool[0];
148            if (pDimRegionPool[1]) delete pDimRegionPool[1];
149            ResetSuspendedRegions();
150            Unregister();
151      }      }
152    
153      void Engine::Enable() {      void Engine::Enable() {
# Line 153  namespace LinuxSampler { namespace gig { Line 156  namespace LinuxSampler { namespace gig {
156          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
157      }      }
158    
159        /**
160         * Temporarily stop the engine to not do anything. The engine will just be
161         * frozen during that time, that means after enabling it again it will
162         * continue where it was, with all its voices and playback state it had at
163         * the point of disabling. Notice that the engine's (audio) thread will
164         * continue to run, it just remains in an inactive loop during that time.
165         *
166         * If you need to be sure that all voices and disk streams are killed as
167         * well, use @c SuspendAll() instead.
168         *
169         * @see Enable(), SuspendAll()
170         */
171      void Engine::Disable() {      void Engine::Disable() {
172          dmsg(3,("gig::Engine: disabling\n"));          dmsg(3,("gig::Engine: disabling\n"));
173          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
# Line 166  namespace LinuxSampler { namespace gig { Line 181  namespace LinuxSampler { namespace gig {
181      }      }
182    
183      /**      /**
184         * Similar to @c Disable() but this method additionally kills all voices
185         * and disk streams and blocks until all voices and disk streams are actually
186         * killed / deleted.
187         *
188         * @e Note: only the original calling thread is able to re-enable the
189         * engine afterwards by calling @c ResumeAll() later on!
190         */
191        void Engine::SuspendAll() {
192            dmsg(2,("gig::Engine: Suspending all ...\n"));
193            // stop the engine, so we can safely modify the engine's
194            // data structures from this foreign thread
195            DisableAndLock();
196            // we could also use the respective class member variable here,
197            // but this is probably safer and cleaner
198            int iPendingStreamDeletions = 0;
199            // kill all voices on all engine channels the *die hard* way
200            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
201                EngineChannel* pEngineChannel = engineChannels[iChannel];
202                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
203                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
204                for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
205                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
206                    RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
207                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
208                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
209                        // request a notification from disk thread side for stream deletion
210                        const Stream::Handle hStream = itVoice->KillImmediately(true);
211                        if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
212                            iPendingStreamDeletions++;
213                        }
214                    }
215                }
216            }
217            // wait until all streams were actually deleted by the disk thread
218            while (iPendingStreamDeletions) {
219                while (
220                    iPendingStreamDeletions &&
221                    pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
222                ) iPendingStreamDeletions--;
223                if (!iPendingStreamDeletions) break;
224                usleep(10000); // sleep for 10ms
225            }
226            dmsg(2,("gig::Engine: Everything suspended.\n"));
227        }
228    
229        /**
230         * At the moment same as calling @c Enable() directly, but this might
231         * change in future, so better call this method as counterpart to
232         * @c SuspendAll() instead of @c Enable() !
233         */
234        void Engine::ResumeAll() {
235            Enable();
236        }
237    
238        /**
239         * Order the engine to stop rendering audio for the given region.
240         * Additionally this method will block until all voices and their disk
241         * streams associated with that region are actually killed / deleted, so
242         * one can i.e. safely modify the region with an instrument editor after
243         * returning from this method.
244         *
245         * @param pRegion - region the engine shall stop using
246         */
247        void Engine::Suspend(::gig::Region* pRegion) {
248            dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
249            SuspendedRegionsMutex.Lock();
250            SuspensionChangeOngoing.Set(true);
251            pPendingRegionSuspension = pRegion;
252            SuspensionChangeOngoing.WaitAndUnlockIf(true);
253            SuspendedRegionsMutex.Unlock();
254            dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
255        }
256    
257        /**
258         * Orders the engine to resume playing back the given region, previously
259         * suspended with @c Suspend() .
260         *
261         * @param pRegion - region the engine shall be allowed to use again
262         */
263        void Engine::Resume(::gig::Region* pRegion) {
264            dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
265            SuspendedRegionsMutex.Lock();
266            SuspensionChangeOngoing.Set(true);
267            pPendingRegionResumption = pRegion;
268            SuspensionChangeOngoing.WaitAndUnlockIf(true);
269            SuspendedRegionsMutex.Unlock();
270            dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
271        }
272    
273        /**
274       *  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
275       *  control and status variables.       *  control and status variables.
276       */       */
# Line 178  namespace LinuxSampler { namespace gig { Line 283  namespace LinuxSampler { namespace gig {
283    
284      /**      /**
285       *  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
286       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
287       */       */
288      void Engine::ResetInternal() {      void Engine::ResetInternal() {
289            ResetInternalMutex.Lock();
290    
291            // make sure that the engine does not get any sysex messages
292            // while it's reseting
293            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
294          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
295          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
296    
# Line 203  namespace LinuxSampler { namespace gig { Line 313  namespace LinuxSampler { namespace gig {
313    
314          // delete all input events          // delete all input events
315          pEventQueue->init();          pEventQueue->init();
316            pSysexBuffer->init();
317            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
318            ResetInternalMutex.Unlock();
319      }      }
320    
321      /**      /**
# Line 212  namespace LinuxSampler { namespace gig { Line 325  namespace LinuxSampler { namespace gig {
325          memset(&ScaleTuning[0], 0x00, 12);          memset(&ScaleTuning[0], 0x00, 12);
326      }      }
327    
328        void Engine::ResetSuspendedRegions() {
329            SuspendedRegions.clear();
330            iPendingStreamDeletions = 0;
331            pPendingRegionSuspension = pPendingRegionResumption = NULL;
332            SuspensionChangeOngoing.Set(false);
333        }
334    
335      /**      /**
336       * Connect this engine instance with the given audio output device.       * Connect this engine instance with the given audio output device.
337       * This method will be called when an Engine instance is created.       * This method will be called when an Engine instance is created.
# Line 232  namespace LinuxSampler { namespace gig { Line 352  namespace LinuxSampler { namespace gig {
352          }          }
353          catch (AudioOutputException e) {          catch (AudioOutputException e) {
354              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();
355              throw LinuxSamplerException(msg);              throw Exception(msg);
356          }          }
357    
358          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
# Line 240  namespace LinuxSampler { namespace gig { Line 360  namespace LinuxSampler { namespace gig {
360    
361          // FIXME: audio drivers with varying fragment sizes might be a problem here          // FIXME: audio drivers with varying fragment sizes might be a problem here
362          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
363          if (MaxFadeOutPos < 0)          if (MaxFadeOutPos < 0) {
364              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 "
365                          << "too big for current audio fragment size & sampling rate! "
366                          << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
367                // force volume ramp downs at the beginning of each fragment
368                MaxFadeOutPos = 0;
369                // lower minimum release time
370                const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
371                for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
372                    iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
373                }
374                pVoicePool->clear();
375            }
376    
377          // (re)create disk thread          // (re)create disk thread
378          if (this->pDiskThread) {          if (this->pDiskThread) {
# Line 250  namespace LinuxSampler { namespace gig { Line 381  namespace LinuxSampler { namespace gig {
381              delete this->pDiskThread;              delete this->pDiskThread;
382              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
383          }          }
384          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
385                                               &instruments);
386          if (!pDiskThread) {          if (!pDiskThread) {
387              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
388              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 266  namespace LinuxSampler { namespace gig { Line 398  namespace LinuxSampler { namespace gig {
398          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
399          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
400    
         // (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()];  
   
401          dmsg(1,("Starting disk thread..."));          dmsg(1,("Starting disk thread..."));
402          pDiskThread->StartThread();          pDiskThread->StartThread();
403          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
# Line 296  namespace LinuxSampler { namespace gig { Line 411  namespace LinuxSampler { namespace gig {
411      }      }
412    
413      /**      /**
414         * Called by the engine's (audio) thread once per cycle to process requests
415         * from the outer world to suspend or resume a given @c gig::Region .
416         */
417        void Engine::ProcessSuspensionsChanges() {
418            // process request for suspending one region
419            if (pPendingRegionSuspension) {
420                // kill all voices on all engine channels that use this region
421                for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
422                    EngineChannel* pEngineChannel = engineChannels[iChannel];
423                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
424                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
425                    for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
426                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
427                        RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
428                        // if current key is not associated with this region, skip this key
429                        if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
430                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
431                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
432                            // request a notification from disk thread side for stream deletion
433                            const Stream::Handle hStream = itVoice->KillImmediately(true);
434                            if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
435                                iPendingStreamDeletions++;
436                            }
437                        }
438                    }
439                }
440                // make sure the region is not yet on the list
441                bool bAlreadySuspended = false;
442                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
443                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
444                for (; iter != end; ++iter) { // iterate through all suspended regions
445                    if (*iter == pPendingRegionSuspension) { // found
446                        bAlreadySuspended = true;
447                        dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
448                        break;
449                    }
450                }
451                if (!bAlreadySuspended) {
452                    // put the region on the list of suspended regions
453                    RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
454                    if (iter) {
455                        *iter = pPendingRegionSuspension;
456                    } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
457                }
458                // 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)
460                pPendingRegionSuspension = NULL;
461                // if no disk stream deletions are pending, awaken other side, as
462                // we're done in this case
463                if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
464            }
465    
466            // process request for resuming one region
467            if (pPendingRegionResumption) {
468                // remove region from the list of suspended regions
469                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
470                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
471                for (; iter != end; ++iter) { // iterate through all suspended regions
472                    if (*iter == pPendingRegionResumption) { // found
473                        SuspendedRegions.free(iter);
474                        break; // done
475                    }
476                }
477                // free request slot for next caller
478                pPendingRegionResumption = NULL;
479                // awake other side as we're done
480                SuspensionChangeOngoing.Set(false);
481            }
482        }
483    
484        /**
485         * Called by the engine's (audio) thread once per cycle to check if
486         * streams of voices that were killed due to suspension request have
487         * finally really been deleted by the disk thread.
488         */
489        void Engine::ProcessPendingStreamDeletions() {
490            if (!iPendingStreamDeletions) return;
491            //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
492            while (
493                iPendingStreamDeletions &&
494                pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
495            ) iPendingStreamDeletions--;
496            // just for safety ...
497            while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
498            // now that all disk streams are deleted, awake other side as
499            // we're finally done with suspending the requested region
500            if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
501        }
502    
503        /**
504         * Returns @c true if the given region is currently set to be suspended
505         * from being used, @c false otherwise.
506         */
507        bool Engine::RegionSuspended(::gig::Region* pRegion) {
508            if (SuspendedRegions.isEmpty()) return false;
509            //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
510            RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
511            RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
512            for (; iter != end; ++iter)  // iterate through all suspended regions
513                if (*iter == pRegion) return true;
514            return false;
515        }
516    
517        /**
518       * Clear all engine global event lists.       * Clear all engine global event lists.
519       */       */
520      void Engine::ClearEventLists() {      void Engine::ClearEventLists() {
# Line 316  namespace LinuxSampler { namespace gig { Line 535  namespace LinuxSampler { namespace gig {
535       *                  current audio cycle       *                  current audio cycle
536       */       */
537      void Engine::ImportEvents(uint Samples) {      void Engine::ImportEvents(uint Samples) {
538          RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
539          Event* pEvent;          Event* pEvent;
540          while (true) {          while (true) {
541              // get next event from input event queue              // get next event from input event queue
# Line 339  namespace LinuxSampler { namespace gig { Line 558  namespace LinuxSampler { namespace gig {
558      }      }
559    
560      /**      /**
561       *  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.
562       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
563       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
564       *  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
565       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
566         * respective engine channel.
567       *       *
568       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
569       *  @returns       0 on success       *  @returns       0 on success
570       */       */
571      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
572          dmsg(5,("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 357  namespace LinuxSampler { namespace gig { Line 577  namespace LinuxSampler { namespace gig {
577              return 0;              return 0;
578          }          }
579    
580            // process requests for suspending / resuming regions (i.e. to avoid
581            // crashes while these regions are modified by an instrument editor)
582            ProcessSuspensionsChanges();
583    
584          // update time of start and end of this audio fragment (as events' time stamps relate to this)          // update time of start and end of this audio fragment (as events' time stamps relate to this)
585          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
586    
587            // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned
588            // in each audio fragment. All subsequent request for spawning new
589            // voices in the same audio fragment will be ignored.
590            VoiceSpawnsLeft = CONFIG_MAX_VOICES;
591    
592          // get all events from the engine's global input event queue which belong to the current fragment          // get all events from the engine's global input event queue which belong to the current fragment
593          // (these are usually just SysEx messages)          // (these are usually just SysEx messages)
594          ImportEvents(Samples);          ImportEvents(Samples);
# Line 378  namespace LinuxSampler { namespace gig { Line 607  namespace LinuxSampler { namespace gig {
607              }              }
608          }          }
609    
         // We only allow a maximum of CONFIG_MAX_VOICES voices to be stolen  
         // in each audio fragment. All subsequent request for spawning new  
         // voices in the same audio fragment will be ignored.  
         VoiceTheftsLeft = CONFIG_MAX_VOICES;  
   
610          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
611          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
612    
613            // handle instrument change commands
614            bool instrumentChanged = false;
615            for (int i = 0; i < engineChannels.size(); i++) {
616                EngineChannel* pEngineChannel = engineChannels[i];
617    
618                // as we're going to (carefully) write some status to the
619                // synchronized struct, we cast away the const
620                EngineChannel::instrument_change_command_t& cmd =
621                    const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
622    
623                pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
624                pEngineChannel->pDimRegionsInUse->clear();
625    
626                if (cmd.bChangeInstrument) {
627                    // 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();
645                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
646                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
647                            itVoice->Orphan = true;
648                        }
649                    }
650                }
651            }
652            if (instrumentChanged) {
653                //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                ResetSuspendedRegions();
655            }
656    
657          // handle events on all engine channels          // handle events on all engine channels
658          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  
659              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
660          }          }
661    
662          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
663          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  
664              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
665          }          }
666    
667          // 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
668          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
669    
670            // handle audio routing for engine channels with FX sends
671            for (int i = 0; i < engineChannels.size(); i++) {
672                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
673                RouteAudio(engineChannels[i], Samples);
674            }
675    
676          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
677          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  
678              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
679          }          }
680    
# Line 419  namespace LinuxSampler { namespace gig { Line 689  namespace LinuxSampler { namespace gig {
689          ActiveVoiceCount = ActiveVoiceCountTemp;          ActiveVoiceCount = ActiveVoiceCountTemp;
690          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
691    
692            // in case regions were previously suspended and we killed voices
693            // with disk streams due to that, check if those streams have finally
694            // been deleted by the disk thread
695            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 482  namespace LinuxSampler { namespace gig { Line 760  namespace LinuxSampler { namespace gig {
760       *                         this audio fragment cycle       *                         this audio fragment cycle
761       */       */
762      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
763            #if !CONFIG_PROCESS_MUTED_CHANNELS
764            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
765            #endif
766    
767            uint voiceCount = 0;
768            uint streamCount = 0;
769          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
770          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
771          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 493  namespace LinuxSampler { namespace gig { Line 777  namespace LinuxSampler { namespace gig {
777              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
778                  // now render current voice                  // now render current voice
779                  itVoice->Render(Samples);                  itVoice->Render(Samples);
780                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
781                  else { // voice reached end, is now inactive                      if (!itVoice->Orphan) {
782                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
783                        }
784                        ActiveVoiceCountTemp++;
785                        voiceCount++;
786    
787                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
788                            if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;
789                        }
790                    }  else { // voice reached end, is now inactive
791                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
792                  }                  }
793              }              }
794          }          }
795    
796            pEngineChannel->SetVoiceCount(voiceCount);
797            pEngineChannel->SetDiskStreamCount(streamCount);
798      }      }
799    
800      /**      /**
# Line 519  namespace LinuxSampler { namespace gig { Line 815  namespace LinuxSampler { namespace gig {
815          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
816          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
817              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
818                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
819              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
820                  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);
821              if (itNewVoice) {              if (itNewVoice) {
822                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
823                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
824                  else { // voice reached end, is now inactive                      *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
825                        ActiveVoiceCountTemp++;
826                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
827    
828                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
829                            if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
830                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
831                            }
832                        }
833                    } else { // voice reached end, is now inactive
834                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
835                  }                  }
836              }              }
# Line 538  namespace LinuxSampler { namespace gig { Line 844  namespace LinuxSampler { namespace gig {
844      }      }
845    
846      /**      /**
847         * Will be called in case the respective engine channel sports FX send
848         * channels. In this particular case, engine channel local buffers are
849         * used to render and mix all voices to. This method is responsible for
850         * copying the audio data from those local buffers to the master audio
851         * output channels as well as to the FX send audio output channels with
852         * their respective FX send levels.
853         *
854         * @param pEngineChannel - engine channel from which audio should be
855         *                         routed
856         * @param Samples        - amount of sample points to be routed in
857         *                         this audio fragment cycle
858         */
859        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
860            // route dry signal
861            {
862                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
863                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
864                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
865                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
866            }
867            // route FX send signal
868            {
869                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
870                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
871                    for (int iChan = 0; iChan < 2; ++iChan) {
872                        AudioChannel* pSource =
873                            (iChan)
874                                ? pEngineChannel->pChannelRight
875                                : pEngineChannel->pChannelLeft;
876                        const int iDstChan = pFxSend->DestinationChannel(iChan);
877                        if (iDstChan < 0) {
878                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
879                            goto channel_cleanup;
880                        }
881                        AudioChannel* pDstChan = NULL;
882                        if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
883                            EffectChain* pEffectChain =
884                                pAudioOutputDevice->MasterEffectChain(
885                                    pFxSend->DestinationMasterEffectChain()
886                                );
887                            if (!pEffectChain) {
888                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
889                                goto channel_cleanup;
890                            }
891                            Effect* pEffect =
892                                pEffectChain->GetEffect(
893                                    pFxSend->DestinationMasterEffect()
894                                );
895                            if (!pEffect) {
896                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
897                                goto channel_cleanup;
898                            }
899                            pDstChan = pEffect->InputChannel(iDstChan);
900                        } else { // FX send routed directly to an audio output channel
901                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
902                        }
903                        if (!pDstChan) {
904                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
905                            goto channel_cleanup;
906                        }
907                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
908                    }
909                }
910            }
911            channel_cleanup:
912            // reset buffers with silence (zero out) for the next audio cycle
913            pEngineChannel->pChannelLeft->Clear();
914            pEngineChannel->pChannelRight->Clear();
915        }
916    
917        /**
918       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
919       * 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
920       * channel.       * channel.
# Line 610  namespace LinuxSampler { namespace gig { Line 987  namespace LinuxSampler { namespace gig {
987       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
988       */       */
989      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
990            #if !CONFIG_PROCESS_MUTED_CHANNELS
991            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
992            #endif
993    
994            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
995    
996            //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
997            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
998    
999          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
1000            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
1001    
1002            // move note on event to the key's own event list
1003            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1004    
1005            // if Solo Mode then kill all already active voices
1006            if (pEngineChannel->SoloMode) {
1007                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
1008                if (itYoungestKey) {
1009                    const int iYoungestKey = *itYoungestKey;
1010                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
1011                    if (pOtherKey->Active) {
1012                        // get final portamento position of currently active voice
1013                        if (pEngineChannel->PortamentoMode) {
1014                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
1015                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1016                        }
1017                        // kill all voices on the (other) key
1018                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1019                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1020                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1021                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1022                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1023                        }
1024                    }
1025                }
1026                // set this key as 'currently active solo key'
1027                pEngineChannel->SoloKey = key;
1028            }
1029    
1030          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
1031          {          {
1032              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1033              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1034                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1035                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1036          }          }
1037    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
1038          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
1039          pKey->Velocity   = itNoteOnEvent->Param.Note.Velocity;          pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1040          pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length          pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1041    
1042          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
1043          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
1044              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1045              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
1046                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1047                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1048              }              }
1049              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
1050          }          }
1051    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
1052          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
1053          {          {
1054              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
1055              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1056              if (pRegion) {              if (pRegion && !RegionSuspended(pRegion)) {
1057                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
1058                  // now launch the required amount of voices                  // now launch the required amount of voices
1059                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
1060                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true);                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1061              }              }
1062          }          }
1063    
# Line 656  namespace LinuxSampler { namespace gig { Line 1065  namespace LinuxSampler { namespace gig {
1065          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
1066              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
1067    
1068            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1069          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
1070      }      }
1071    
# Line 669  namespace LinuxSampler { namespace gig { Line 1079  namespace LinuxSampler { namespace gig {
1079       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
1080       */       */
1081      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1082          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
1083            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1084            #endif
1085    
1086            //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
1087            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1088    
1089            const int iKey = itNoteOffEvent->Param.Note.Key;
1090            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1091          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
1092    
1093          // release voices on this key if needed          // move event to the key's own event list
1094          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
             itNoteOffEvent->Type = Event::type_release; // transform event type  
1095    
1096              // move event to the key's own event list          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1097              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);  
1098            // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1099            if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1100                bool bOtherKeysPressed = false;
1101                if (iKey == pEngineChannel->SoloKey) {
1102                    pEngineChannel->SoloKey = -1;
1103                    // if there's still a key pressed down, respawn a voice (group) on the highest key
1104                    for (int i = 127; i > 0; i--) {
1105                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1106                        if (pOtherKey->KeyPressed) {
1107                            bOtherKeysPressed = true;
1108                            // make the other key the new 'currently active solo key'
1109                            pEngineChannel->SoloKey = i;
1110                            // get final portamento position of currently active voice
1111                            if (pEngineChannel->PortamentoMode) {
1112                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1113                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1114                            }
1115                            // create a pseudo note on event
1116                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1117                            if (itPseudoNoteOnEvent) {
1118                                // copy event
1119                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1120                                // transform event to a note on event
1121                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
1122                                itPseudoNoteOnEvent->Param.Note.Key      = i;
1123                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1124                                // allocate and trigger new voice(s) for the other key
1125                                {
1126                                    // first, get total amount of required voices (dependant on amount of layers)
1127                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1128                                    if (pRegion) {
1129                                        int voicesRequired = pRegion->Layers;
1130                                        // now launch the required amount of voices
1131                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1132                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1133                                    }
1134                                }
1135                                // if neither a voice was spawned or postponed then remove note on event from key again
1136                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1137                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1138    
1139                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
1140                            break; // done
1141                        }
1142                    }
1143                }
1144                if (bOtherKeysPressed) {
1145                    if (pKey->Active) { // kill all voices on this key
1146                        bShouldRelease = false; // no need to release, as we kill it here
1147                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1148                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
1149                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1150                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1151                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1152                        }
1153                    }
1154                } else pEngineChannel->PortamentoPos = -1.0f;
1155            }
1156    
1157            // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1158            if (bShouldRelease) {
1159                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1160    
1161              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
1162              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1163                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
1164                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1165                  if (pRegion) {                  if (pRegion) {
# Line 692  namespace LinuxSampler { namespace gig { Line 1170  namespace LinuxSampler { namespace gig {
1170    
1171                      // now launch the required amount of voices                      // now launch the required amount of voices
1172                      for (int i = 0; i < voicesRequired; i++)                      for (int i = 0; i < voicesRequired; i++)
1173                          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
1174                  }                  }
1175                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
1176              }              }
   
             // 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);  
1177          }          }
1178    
1179            // if neither a voice was spawned or postponed on this key then remove note off event from key again
1180            if (!pKey->Active && !pKey->VoiceTheftsQueued)
1181                pKey->pEvents->free(itNoteOffEventOnKeyList);
1182      }      }
1183    
1184      /**      /**
1185       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
1186       *  event list.       *  channel's event list. It will actually processed later by the
1187         *  respective voice.
1188       *       *
1189       *  @param pEngineChannel - engine channel on which this event occured on       *  @param pEngineChannel - engine channel on which this event occured on
1190       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
1191       */       */
1192      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1193          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]);  
1194      }      }
1195    
1196      /**      /**
# Line 729  namespace LinuxSampler { namespace gig { Line 1207  namespace LinuxSampler { namespace gig {
1207       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
1208       *                               when there is no free voice       *                               when there is no free voice
1209       *                               (optional, default = true)       *                               (optional, default = true)
1210         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
1211         *                                   key group conflict
1212       *  @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
1213       *           if the voice wasn't triggered (for example when no region is       *           if the voice wasn't triggered (for example when no region is
1214       *           defined for the given key).       *           defined for the given key).
1215       */       */
1216      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) {
1217          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
1218            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1219            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1220    
1221            // if nothing defined for this key
1222            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1223    
1224            // only mark the first voice of a layered voice (group) to be in a
1225            // key group, so the layered voices won't kill each other
1226            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1227    
1228            // handle key group (a.k.a. exclusive group) conflicts
1229            if (HandleKeyGroupConflicts) {
1230                if (iKeyGroup) { // if this voice / key belongs to a key group
1231                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1232                    if (*ppKeyGroup) { // if there's already an active key in that key group
1233                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1234                        // kill all voices on the (other) key
1235                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1236                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1237                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1238                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1239                                itVoiceToBeKilled->Kill(itNoteOnEvent);
1240                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1241                            }
1242                        }
1243                    }
1244                }
1245            }
1246    
1247            Voice::type_t VoiceType = Voice::type_normal;
1248    
1249            // get current dimension values to select the right dimension region
1250            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1251            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1252            uint DimValues[8] = { 0 };
1253            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1254                switch (pRegion->pDimensionDefinitions[i].dimension) {
1255                    case ::gig::dimension_samplechannel:
1256                        DimValues[i] = 0; //TODO: we currently ignore this dimension
1257                        break;
1258                    case ::gig::dimension_layer:
1259                        DimValues[i] = iLayer;
1260                        break;
1261                    case ::gig::dimension_velocity:
1262                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1263                        break;
1264                    case ::gig::dimension_channelaftertouch:
1265                        DimValues[i] = pEngineChannel->ControllerTable[128];
1266                        break;
1267                    case ::gig::dimension_releasetrigger:
1268                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1269                        DimValues[i] = (uint) ReleaseTriggerVoice;
1270                        break;
1271                    case ::gig::dimension_keyboard:
1272                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1273                        break;
1274                    case ::gig::dimension_roundrobin:
1275                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1276                        break;
1277                    case ::gig::dimension_random:
1278                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1279                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1280                        break;
1281                    case ::gig::dimension_modwheel:
1282                        DimValues[i] = pEngineChannel->ControllerTable[1];
1283                        break;
1284                    case ::gig::dimension_breath:
1285                        DimValues[i] = pEngineChannel->ControllerTable[2];
1286                        break;
1287                    case ::gig::dimension_foot:
1288                        DimValues[i] = pEngineChannel->ControllerTable[4];
1289                        break;
1290                    case ::gig::dimension_portamentotime:
1291                        DimValues[i] = pEngineChannel->ControllerTable[5];
1292                        break;
1293                    case ::gig::dimension_effect1:
1294                        DimValues[i] = pEngineChannel->ControllerTable[12];
1295                        break;
1296                    case ::gig::dimension_effect2:
1297                        DimValues[i] = pEngineChannel->ControllerTable[13];
1298                        break;
1299                    case ::gig::dimension_genpurpose1:
1300                        DimValues[i] = pEngineChannel->ControllerTable[16];
1301                        break;
1302                    case ::gig::dimension_genpurpose2:
1303                        DimValues[i] = pEngineChannel->ControllerTable[17];
1304                        break;
1305                    case ::gig::dimension_genpurpose3:
1306                        DimValues[i] = pEngineChannel->ControllerTable[18];
1307                        break;
1308                    case ::gig::dimension_genpurpose4:
1309                        DimValues[i] = pEngineChannel->ControllerTable[19];
1310                        break;
1311                    case ::gig::dimension_sustainpedal:
1312                        DimValues[i] = pEngineChannel->ControllerTable[64];
1313                        break;
1314                    case ::gig::dimension_portamento:
1315                        DimValues[i] = pEngineChannel->ControllerTable[65];
1316                        break;
1317                    case ::gig::dimension_sostenutopedal:
1318                        DimValues[i] = pEngineChannel->ControllerTable[66];
1319                        break;
1320                    case ::gig::dimension_softpedal:
1321                        DimValues[i] = pEngineChannel->ControllerTable[67];
1322                        break;
1323                    case ::gig::dimension_genpurpose5:
1324                        DimValues[i] = pEngineChannel->ControllerTable[80];
1325                        break;
1326                    case ::gig::dimension_genpurpose6:
1327                        DimValues[i] = pEngineChannel->ControllerTable[81];
1328                        break;
1329                    case ::gig::dimension_genpurpose7:
1330                        DimValues[i] = pEngineChannel->ControllerTable[82];
1331                        break;
1332                    case ::gig::dimension_genpurpose8:
1333                        DimValues[i] = pEngineChannel->ControllerTable[83];
1334                        break;
1335                    case ::gig::dimension_effect1depth:
1336                        DimValues[i] = pEngineChannel->ControllerTable[91];
1337                        break;
1338                    case ::gig::dimension_effect2depth:
1339                        DimValues[i] = pEngineChannel->ControllerTable[92];
1340                        break;
1341                    case ::gig::dimension_effect3depth:
1342                        DimValues[i] = pEngineChannel->ControllerTable[93];
1343                        break;
1344                    case ::gig::dimension_effect4depth:
1345                        DimValues[i] = pEngineChannel->ControllerTable[94];
1346                        break;
1347                    case ::gig::dimension_effect5depth:
1348                        DimValues[i] = pEngineChannel->ControllerTable[95];
1349                        break;
1350                    case ::gig::dimension_none:
1351                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1352                        break;
1353                    default:
1354                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1355                }
1356            }
1357    
1358            // return if this is a release triggered voice and there is no
1359            // releasetrigger dimension (could happen if an instrument
1360            // change has occured between note on and off)
1361            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1362    
1363            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1364    
1365            // no need to continue if sample is silent
1366            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1367    
1368          // allocate a new voice for the key          // allocate a new voice for the key
1369          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1370          if (itNewVoice) {          if (itNewVoice) {
1371              // launch the new voice              // launch the new voice
1372              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pEngineChannel->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1373                  dmsg(4,("Voice not triggered\n"));                  dmsg(4,("Voice not triggered\n"));
1374                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1375              }              }
1376              else { // on success              else { // on success
1377                  uint** ppKeyGroup = NULL;                  --VoiceSpawnsLeft;
                 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);  
                         }  
                     }  
                 }  
1378                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1379                      pKey->Active = true;                      pKey->Active = true;
1380                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1381                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1382                  }                  }
1383                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1384                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1385                      *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
1386                  }                  }
1387                  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 800  namespace LinuxSampler { namespace gig { Line 1418  namespace LinuxSampler { namespace gig {
1418       *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing       *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1419       */       */
1420      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1421          if (!VoiceTheftsLeft) {          if (VoiceSpawnsLeft <= 0) {
1422              dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));              dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1423              return -1;              return -1;
1424          }          }
# Line 819  namespace LinuxSampler { namespace gig { Line 1437  namespace LinuxSampler { namespace gig {
1437                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1438                      itSelectedVoice = pSelectedKey->pActiveVoices->first();                      itSelectedVoice = pSelectedKey->pActiveVoices->first();
1439                      // proceed iterating if voice was created in this fragment cycle                      // proceed iterating if voice was created in this fragment cycle
1440                      while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                      while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1441                      // if we haven't found a voice then proceed with algorithm 'oldestkey'                      // if we haven't found a voice then proceed with algorithm 'oldestkey'
1442                      if (itSelectedVoice && itSelectedVoice->hasRendered()) break;                      if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
1443                  } // no break - intentional !                  } // no break - intentional !
1444    
1445                  // try to pick the oldest voice on the oldest active key                  // try to pick the oldest voice on the oldest active key
# Line 833  namespace LinuxSampler { namespace gig { Line 1451  namespace LinuxSampler { namespace gig {
1451                          itSelectedVoice = this->itLastStolenVoice;                          itSelectedVoice = this->itLastStolenVoice;
1452                          do {                          do {
1453                              ++itSelectedVoice;                              ++itSelectedVoice;
1454                          } while (itSelectedVoice && !itSelectedVoice->hasRendered()); // proceed iterating if voice was created in this fragment cycle                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1455                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1456                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1457                              // remember which voice we stole, so we can simply proceed on next voice stealing                              // remember which voice we stole, so we can simply proceed on next voice stealing
1458                              this->itLastStolenVoice = itSelectedVoice;                              this->itLastStolenVoice = itSelectedVoice;
1459                              break; // selection succeeded                              break; // selection succeeded
# Line 847  namespace LinuxSampler { namespace gig { Line 1465  namespace LinuxSampler { namespace gig {
1465                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1466                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          itSelectedVoice = pSelectedKey->pActiveVoices->first();
1467                          // proceed iterating if voice was created in this fragment cycle                          // proceed iterating if voice was created in this fragment cycle
1468                          while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1469                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1470                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1471                              // remember which voice on which key we stole, so we can simply proceed on next voice stealing                              // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1472                              this->iuiLastStolenKey  = iuiSelectedKey;                              this->iuiLastStolenKey  = iuiSelectedKey;
1473                              this->itLastStolenVoice = itSelectedVoice;                              this->itLastStolenVoice = itSelectedVoice;
# Line 871  namespace LinuxSampler { namespace gig { Line 1489  namespace LinuxSampler { namespace gig {
1489              // if we couldn't steal a voice from the same engine channel then              // if we couldn't steal a voice from the same engine channel then
1490              // steal oldest voice on the oldest key from any other engine channel              // steal oldest voice on the oldest key from any other engine channel
1491              // (the smaller engine channel number, the higher priority)              // (the smaller engine channel number, the higher priority)
1492              if (!itSelectedVoice || !itSelectedVoice->hasRendered()) {              if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1493                  EngineChannel* pSelectedChannel;                  EngineChannel* pSelectedChannel;
1494                  int            iChannelIndex;                  int            iChannelIndex;
1495                  // select engine channel                  // select engine channel
# Line 882  namespace LinuxSampler { namespace gig { Line 1500  namespace LinuxSampler { namespace gig {
1500                      iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1501                      pSelectedChannel = engineChannels[iChannelIndex];                      pSelectedChannel = engineChannels[iChannelIndex];
1502                  }                  }
1503                  // iterate through engine channels  
1504                  while (true) {                  // if we already stole in this fragment, try to proceed on same key
1505                      // if we already stole in this fragment, try to proceed on same key                  if (this->itLastStolenVoiceGlobally) {
1506                      if (this->itLastStolenVoiceGlobally) {                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1507                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      do {
1508                          do {                          ++itSelectedVoice;
1509                              ++itSelectedVoice;                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1510                          } while (itSelectedVoice && !itSelectedVoice->hasRendered()); // proceed iterating if voice was created in this fragment cycle                  }
1511                          // break if selection succeeded  
1512                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                  #if CONFIG_DEVMODE
1513                              // remember which voice we stole, so we can simply proceed on next voice stealing                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1514                              this->itLastStolenVoiceGlobally = itSelectedVoice;                  #endif // CONFIG_DEVMODE
1515                              break; // selection succeeded  
1516                          }                  // did we find a 'stealable' voice?
1517                      }                  if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1518                        // remember which voice we stole, so we can simply proceed on next voice stealing
1519                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1520                    } else while (true) { // iterate through engine channels
1521                      // get (next) oldest key                      // get (next) oldest key
1522                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pSelectedChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1523                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1524                      while (iuiSelectedKey) {                      while (iuiSelectedKey) {
1525                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];                          midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1526                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          itSelectedVoice = pSelectedKey->pActiveVoices->first();
1527                          // proceed iterating if voice was created in this fragment cycle                          // proceed iterating if voice was created in this fragment cycle
1528                          while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1529                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1530                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1531                              // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing                              // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1532                              this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                              this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1533                              this->itLastStolenVoiceGlobally = itSelectedVoice;                              this->itLastStolenVoiceGlobally = itSelectedVoice;
1534                              this->pLastStolenChannel        = pSelectedChannel;                              this->pLastStolenChannel        = pSelectedChannel;
1535                              break; // selection succeeded                              goto stealable_voice_found; // selection succeeded
1536                          }                          }
1537                          ++iuiSelectedKey; // get next key on current engine channel                          ++iuiSelectedKey; // get next key on current engine channel
1538                      }                      }
1539                      // get next engine channel                      // get next engine channel
1540                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1541                      pSelectedChannel = engineChannels[iChannelIndex];                      pSelectedChannel = engineChannels[iChannelIndex];
1542    
1543                        #if CONFIG_DEVMODE
1544                        if (pSelectedChannel == pBegin) {
1545                            dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1546                            dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1547                            dmsg(1,("Exiting.\n"));
1548                            exit(-1);
1549                        }
1550                        #endif // CONFIG_DEVMODE
1551                  }                  }
1552              }              }
1553    
1554                // jump point if a 'stealable' voice was found
1555                stealable_voice_found:
1556    
1557              #if CONFIG_DEVMODE              #if CONFIG_DEVMODE
1558              if (!itSelectedVoice->IsActive()) {              if (!itSelectedVoice->IsActive()) {
1559                  dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));                  dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
# Line 930  namespace LinuxSampler { namespace gig { Line 1564  namespace LinuxSampler { namespace gig {
1564              // now kill the selected voice              // now kill the selected voice
1565              itSelectedVoice->Kill(itNoteOnEvent);              itSelectedVoice->Kill(itNoteOnEvent);
1566    
1567              --VoiceTheftsLeft;              --VoiceSpawnsLeft;
1568    
1569              return 0; // success              return 0; // success
1570          }          }
# Line 955  namespace LinuxSampler { namespace gig { Line 1589  namespace LinuxSampler { namespace gig {
1589    
1590              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1591    
1592                // if the sample and dimension region belong to an
1593                // instrument that is unloaded, tell the disk thread to
1594                // release them
1595                if (itVoice->Orphan) {
1596                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1597                }
1598    
1599              // free the voice object              // free the voice object
1600              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1601    
# Line 996  namespace LinuxSampler { namespace gig { Line 1637  namespace LinuxSampler { namespace gig {
1637      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1638          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1639    
1640            // handle the "control triggered" MIDI rule: a control change
1641            // event can trigger a new note on or note off event
1642            if (pEngineChannel->pInstrument) {
1643    
1644                ::gig::MidiRule* rule;
1645                for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1646    
1647                    if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1648                        dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1649                        if (itControlChangeEvent->Param.CC.Controller ==
1650                            ctrlTrigger->ControllerNumber) {
1651    
1652                            uint8_t oldCCValue = pEngineChannel->ControllerTable[
1653                                itControlChangeEvent->Param.CC.Controller];
1654                            uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1655    
1656                            for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1657                                ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1658                                      &ctrlTrigger->pTriggers[i];
1659    
1660                                // check if the controller has passed the
1661                                // trigger point in the right direction
1662                                if ((pTrigger->Descending &&
1663                                     oldCCValue > pTrigger->TriggerPoint &&
1664                                     newCCValue <= pTrigger->TriggerPoint) ||
1665                                    (!pTrigger->Descending &&
1666                                     oldCCValue < pTrigger->TriggerPoint &&
1667                                     newCCValue >= pTrigger->TriggerPoint)) {
1668    
1669                                    RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1670                                    if (itNewEvent) {
1671                                        *itNewEvent = *itControlChangeEvent;
1672                                        itNewEvent->Param.Note.Key = pTrigger->Key;
1673    
1674                                        if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1675                                            itNewEvent->Type = Event::type_note_off;
1676                                            itNewEvent->Param.Note.Velocity = 100;
1677    
1678                                            ProcessNoteOff(pEngineChannel, itNewEvent);
1679                                        } else {
1680                                            itNewEvent->Type = Event::type_note_on;
1681                                            //TODO: if Velocity is 255, the triggered velocity should
1682                                            // depend on how fast the controller is moving
1683                                            itNewEvent->Param.Note.Velocity =
1684                                                pTrigger->Velocity == 255 ? 100 :
1685                                                pTrigger->Velocity;
1686    
1687                                            ProcessNoteOn(pEngineChannel, itNewEvent);
1688                                        }
1689                                    }
1690                                    else dmsg(1,("Event pool emtpy!\n"));
1691                                }
1692                            }
1693                        }
1694                    }
1695                }
1696            }
1697    
1698          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1699          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1700    
1701          // move event from the unsorted event list to the control change event list          // handle hard coded MIDI controllers
1702          Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pCCEvents);          switch (itControlChangeEvent->Param.CC.Controller) {
1703                case 5: { // portamento time
1704          switch (itControlChangeEventOnCCList->Param.CC.Controller) {                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1705                    break;
1706                }
1707                case 6: { // data entry (currently only used for RPN controllers)
1708                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1709                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1710                        // limit to +- two octaves for now
1711                        transpose = RTMath::Min(transpose,  24);
1712                        transpose = RTMath::Max(transpose, -24);
1713                        pEngineChannel->GlobalTranspose = transpose;
1714                        // workaround, so we won't have hanging notes
1715                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1716                    }
1717                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1718                    pEngineChannel->ResetMidiRpnController();
1719                    break;
1720                }
1721              case 7: { // volume              case 7: { // volume
1722                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1723                  pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1724                    pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1725                  break;                  break;
1726              }              }
1727              case 10: { // panpot              case 10: { // panpot
1728                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1729                  const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1730                  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;  
1731                  break;                  break;
1732              }              }
1733              case 64: { // sustain              case 64: { // sustain
1734                  if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1735                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1736                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1737    
1738                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1739                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1740                        #endif
1741    
1742                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1743                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1744                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
# Line 1027  namespace LinuxSampler { namespace gig { Line 1746  namespace LinuxSampler { namespace gig {
1746                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed) {
1747                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1748                              if (itNewEvent) {                              if (itNewEvent) {
1749                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1750                                  itNewEvent->Type = Event::type_cancel_release; // transform event type                                  itNewEvent->Type = Event::type_cancel_release; // transform event type
1751                              }                              }
1752                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
1753                          }                          }
1754                      }                      }
1755                  }                  }
1756                  if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1757                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1758                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1759    
1760                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1761                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1762                        #endif
1763    
1764                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1765                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1766                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1767                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1768                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1769                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1770                                if (itNewEvent) {
1771                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1772                                    itNewEvent->Type = Event::type_release; // transform event type
1773                                }
1774                                else dmsg(1,("Event pool emtpy!\n"));
1775                            }
1776                        }
1777                    }
1778                    break;
1779                }
1780                case 65: { // portamento on / off
1781                    const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1782                    if (bPortamento != pEngineChannel->PortamentoMode)
1783                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1784                    pEngineChannel->PortamentoMode = bPortamento;
1785                    break;
1786                }
1787                case 66: { // sostenuto
1788                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1789                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1790                        pEngineChannel->SostenutoPedal = true;
1791    
1792                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1793                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1794                        #endif
1795    
1796                        SostenutoKeyCount = 0;
1797                        // Remeber the pressed keys
1798                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1799                        for (; iuiKey; ++iuiKey) {
1800                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1801                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1802                        }
1803                    }
1804                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1805                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1806                        pEngineChannel->SostenutoPedal = false;
1807    
1808                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1809                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1810                        #endif
1811    
1812                        // release voices if the damper pedal is up and their respective key is not pressed
1813                        for (int i = 0; i < SostenutoKeyCount; i++) {
1814                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1815                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1816                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1817                              if (itNewEvent) {                              if (itNewEvent) {
1818                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1819                                  itNewEvent->Type = Event::type_release; // transform event type                                  itNewEvent->Type = Event::type_release; // transform event type
1820                              }                              }
1821                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
# Line 1054  namespace LinuxSampler { namespace gig { Line 1824  namespace LinuxSampler { namespace gig {
1824                  }                  }
1825                  break;                  break;
1826              }              }
1827                case 100: { // RPN controller LSB
1828                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1829                    break;
1830                }
1831                case 101: { // RPN controller MSB
1832                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1833                    break;
1834                }
1835    
1836    
1837              // Channel Mode Messages              // Channel Mode Messages
1838    
1839              case 120: { // all sound off              case 120: { // all sound off
1840                  KillAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1841                  break;                  break;
1842              }              }
1843              case 121: { // reset all controllers              case 121: { // reset all controllers
# Line 1067  namespace LinuxSampler { namespace gig { Line 1845  namespace LinuxSampler { namespace gig {
1845                  break;                  break;
1846              }              }
1847              case 123: { // all notes off              case 123: { // all notes off
1848                  ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  #if CONFIG_PROCESS_ALL_NOTES_OFF
1849                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1850                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1851                    break;
1852                }
1853                case 126: { // mono mode on
1854                    if (!pEngineChannel->SoloMode)
1855                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1856                    pEngineChannel->SoloMode = true;
1857                    break;
1858                }
1859                case 127: { // poly mode on
1860                    if (pEngineChannel->SoloMode)
1861                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1862                    pEngineChannel->SoloMode = false;
1863                  break;                  break;
1864              }              }
1865          }          }
1866    
1867            // handle FX send controllers
1868            if (!pEngineChannel->fxSends.empty()) {
1869                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1870                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1871                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1872                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1873                        pFxSend->SetInfoChanged(true);
1874                    }
1875                }
1876            }
1877      }      }
1878    
1879      /**      /**
# Line 1079  namespace LinuxSampler { namespace gig { Line 1882  namespace LinuxSampler { namespace gig {
1882       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1883       */       */
1884      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1885          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1886    
1887          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1888          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1098  namespace LinuxSampler { namespace gig { Line 1901  namespace LinuxSampler { namespace gig {
1901    
1902                  // command address                  // command address
1903                  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)
1904                  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
1905                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1906                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1907                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
# Line 1145  namespace LinuxSampler { namespace gig { Line 1948  namespace LinuxSampler { namespace gig {
1948       *                     question       *                     question
1949       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1950       */       */
1951      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) {
1952          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1953          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1954          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1955          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1205  namespace LinuxSampler { namespace gig { Line 2008  namespace LinuxSampler { namespace gig {
2008              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
2009              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
2010                  itVoice->Kill(itKillEvent);                  itVoice->Kill(itKillEvent);
2011                    --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2012              }              }
2013          }          }
2014      }      }
2015    
2016      /**      /**
2017       * Initialize the parameter sequence for the modulation destination given by       * Determines whether the specified voice should be released.
2018       * by 'dst' with the constant value given by val.       *
2019         * @param pEngineChannel - The engine channel on which the voice should be checked
2020         * @param Key - The key number
2021         * @returns true if the specified should be released, false otherwise.
2022       */       */
2023      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
2024          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          if (pEngineChannel->SustainPedal) return false;
2025          float* m = &pSynthesisParameters[dst][0];  
2026          for (int i = 0; i < maxsamples; i += 4) {          if (pEngineChannel->SostenutoPedal) {
2027             m[i]   = val;              for (int i = 0; i < SostenutoKeyCount; i++)
2028             m[i+1] = val;                  if (Key == SostenutoKeys[i]) return false;
            m[i+2] = val;  
            m[i+3] = val;  
2029          }          }
2030    
2031            return true;
2032      }      }
2033    
2034      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
# Line 1257  namespace LinuxSampler { namespace gig { Line 2064  namespace LinuxSampler { namespace gig {
2064      }      }
2065    
2066      String Engine::Description() {      String Engine::Description() {
2067          return "Gigasampler Engine";          return "Gigasampler Format Engine";
2068      }      }
2069    
2070      String Engine::Version() {      String Engine::Version() {
2071          String s = "$Revision: 1.42 $";          String s = "$Revision: 1.90 $";
2072          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
2073      }      }
2074    
2075        InstrumentManager* Engine::GetInstrumentManager() {
2076            return &instruments;
2077        }
2078    
2079        // static constant initializers
2080        const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2081        const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2082        const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2083    
2084        float* Engine::InitVolumeCurve() {
2085            // line-segment approximation
2086            const float segments[] = {
2087                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2088                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2089            };
2090            return InitCurve(segments);
2091        }
2092    
2093        float* Engine::InitPanCurve() {
2094            // line-segment approximation
2095            const float segments[] = {
2096                0, 0, 1, 0,
2097                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2098                127, 1.41, 128, 1.41
2099            };
2100            return InitCurve(segments, 129);
2101        }
2102    
2103        float* Engine::InitCrossfadeCurve() {
2104            // line-segment approximation
2105            const float segments[] = {
2106                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2107            };
2108            return InitCurve(segments);
2109        }
2110    
2111        float* Engine::InitCurve(const float* segments, int size) {
2112            float* y = new float[size];
2113            for (int x = 0 ; x < size ; x++) {
2114                if (x > segments[2]) segments += 2;
2115                y[x] = segments[1] + (x - segments[0]) *
2116                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
2117            }
2118            return y;
2119        }
2120    
2121  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.659  
changed lines
  Added in v.1722

  ViewVC Help
Powered by ViewVC