/[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 1348 by schoenebeck, Fri Sep 14 14:45:11 2007 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005-2007 Christian Schoenebeck                        *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 29  Line 29 
29    
30  #include "Engine.h"  #include "Engine.h"
31    
 #if defined(__APPLE__)  
 # include <stdlib.h>  
 #else  
 # include <malloc.h>  
 #endif  
   
32  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
33    
34      InstrumentResourceManager Engine::instruments;      InstrumentResourceManager Engine::instruments;
# Line 57  namespace LinuxSampler { namespace gig { Line 51  namespace LinuxSampler { namespace gig {
51          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
52              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
53              pEngine = engines[pDevice];              pEngine = engines[pDevice];
54    
55                // Disable the engine while the new engine channel is
56                // added and initialized. The engine will be enabled again
57                // in EngineChannel::Connect.
58                pEngine->DisableAndLock();
59          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
60              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
61              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 99  namespace LinuxSampler { namespace gig { Line 98  namespace LinuxSampler { namespace gig {
98      /**      /**
99       * Constructor       * Constructor
100       */       */
101      Engine::Engine() {      Engine::Engine() : SuspendedRegions(128) {
102          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
103          pDiskThread        = NULL;          pDiskThread        = NULL;
104          pEventGenerator    = NULL;          pEventGenerator    = NULL;
105          pSysexBuffer       = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
106          pEventQueue        = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
107          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
108          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
109            pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];
110          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
111          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
112            InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);
113            InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);
114    
115          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
116              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
117          }          }
118          pVoicePool->clear();          pVoicePool->clear();
119    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
120          ResetInternal();          ResetInternal();
121          ResetScaleTuning();          ResetScaleTuning();
122            ResetSuspendedRegions();
123      }      }
124    
125      /**      /**
126       * Destructor       * Destructor
127       */       */
128      Engine::~Engine() {      Engine::~Engine() {
129            MidiInputPort::RemoveSysexListener(this);
130          if (pDiskThread) {          if (pDiskThread) {
131              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
132              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 139  namespace LinuxSampler { namespace gig { Line 140  namespace LinuxSampler { namespace gig {
140              delete pVoicePool;              delete pVoicePool;
141          }          }
142          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
143          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
144          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
145          EngineFactory::Destroy(this);          if (pGlobalEvents) delete pGlobalEvents;
146            if (InstrumentChangeQueue) delete InstrumentChangeQueue;
147            if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;
148            if (pDimRegionsInUse) delete[] pDimRegionsInUse;
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(1,("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(1,("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(1,("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(1,("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(1,("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(1,("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, awaker 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(7,("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            instrument_change_command_t command;
615            if (InstrumentChangeQueue->pop(&command) > 0) {
616                EngineChannel* pEngineChannel = command.pEngineChannel;
617                pEngineChannel->pInstrument = command.pInstrument;
618    
619                //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
620                ResetSuspendedRegions();
621    
622                // iterate through all active voices and mark their
623                // dimension regions as "in use". The instrument resource
624                // manager may delete all of the instrument except the
625                // dimension regions and samples that are in use.
626                int i = 0;
627                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
628                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
629                while (iuiKey != end) { // iterate through all active keys
630                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
631                    ++iuiKey;
632    
633                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
634                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
635                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
636                        if (!itVoice->Orphan) {
637                            itVoice->Orphan = true;
638                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
639                        }
640                    }
641                }
642                pDimRegionsInUse[i] = 0; // end of list
643    
644                // send a reply to the calling thread, which is waiting
645                instrument_change_reply_t reply;
646                InstrumentChangeReplyQueue->push(&reply);
647            }
648    
649          // handle events on all engine channels          // handle events on all engine channels
650          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  
651              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
652          }          }
653    
654          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
655          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  
656              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
657          }          }
658    
659          // 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
660          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
661    
662            // handle audio routing for engine channels with FX sends
663            for (int i = 0; i < engineChannels.size(); i++) {
664                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
665                RouteAudio(engineChannels[i], Samples);
666            }
667    
668          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
669          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  
670              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
671          }          }
672    
# Line 419  namespace LinuxSampler { namespace gig { Line 681  namespace LinuxSampler { namespace gig {
681          ActiveVoiceCount = ActiveVoiceCountTemp;          ActiveVoiceCount = ActiveVoiceCountTemp;
682          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
683    
684            // in case regions were previously suspended and we killed voices
685            // with disk streams due to that, check if those streams have finally
686            // been deleted by the disk thread
687            if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
688    
689          FrameTime += Samples;          FrameTime += Samples;
690    
691          return 0;          return 0;
# Line 482  namespace LinuxSampler { namespace gig { Line 749  namespace LinuxSampler { namespace gig {
749       *                         this audio fragment cycle       *                         this audio fragment cycle
750       */       */
751      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
752            #if !CONFIG_PROCESS_MUTED_CHANNELS
753            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
754            #endif
755    
756            uint voiceCount = 0;
757            uint streamCount = 0;
758          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
759          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
760          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 493  namespace LinuxSampler { namespace gig { Line 766  namespace LinuxSampler { namespace gig {
766              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
767                  // now render current voice                  // now render current voice
768                  itVoice->Render(Samples);                  itVoice->Render(Samples);
769                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
770                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
771                        voiceCount++;
772    
773                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
774                            if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;
775                        }
776                    }  else { // voice reached end, is now inactive
777                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
778                  }                  }
779              }              }
780          }          }
781    
782            pEngineChannel->SetVoiceCount(voiceCount);
783            pEngineChannel->SetDiskStreamCount(streamCount);
784      }      }
785    
786      /**      /**
# Line 519  namespace LinuxSampler { namespace gig { Line 801  namespace LinuxSampler { namespace gig {
801          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
802          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
803              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
804                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
805              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
806                  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);
807              if (itNewVoice) {              if (itNewVoice) {
808                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
809                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
810                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
811                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
812    
813                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
814                            if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
815                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
816                            }
817                        }
818                    } else { // voice reached end, is now inactive
819                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
820                  }                  }
821              }              }
# Line 538  namespace LinuxSampler { namespace gig { Line 829  namespace LinuxSampler { namespace gig {
829      }      }
830    
831      /**      /**
832         * Will be called in case the respective engine channel sports FX send
833         * channels. In this particular case, engine channel local buffers are
834         * used to render and mix all voices to. This method is responsible for
835         * copying the audio data from those local buffers to the master audio
836         * output channels as well as to the FX send audio output channels with
837         * their respective FX send levels.
838         *
839         * @param pEngineChannel - engine channel from which audio should be
840         *                         routed
841         * @param Samples        - amount of sample points to be routed in
842         *                         this audio fragment cycle
843         */
844        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
845            // route master signal
846            {
847                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
848                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
849                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
850                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
851            }
852            // route FX send signal
853            {
854                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
855                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
856                    // left channel
857                    const int iDstL = pFxSend->DestinationChannel(0);
858                    if (iDstL < 0) {
859                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
860                    } else {
861                        AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
862                        if (!pDstL) {
863                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
864                        } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
865                    }
866                    // right channel
867                    const int iDstR = pFxSend->DestinationChannel(1);
868                    if (iDstR < 0) {
869                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
870                    } else {
871                        AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
872                        if (!pDstR) {
873                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
874                        } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
875                    }
876                }
877            }
878            // reset buffers with silence (zero out) for the next audio cycle
879            pEngineChannel->pChannelLeft->Clear();
880            pEngineChannel->pChannelRight->Clear();
881        }
882    
883        /**
884       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
885       * 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
886       * channel.       * channel.
# Line 610  namespace LinuxSampler { namespace gig { Line 953  namespace LinuxSampler { namespace gig {
953       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
954       */       */
955      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
956            #if !CONFIG_PROCESS_MUTED_CHANNELS
957            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
958            #endif
959    
960            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
961    
962            //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
963            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
964    
965          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
966            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
967    
968            // move note on event to the key's own event list
969            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
970    
971            // if Solo Mode then kill all already active voices
972            if (pEngineChannel->SoloMode) {
973                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
974                if (itYoungestKey) {
975                    const int iYoungestKey = *itYoungestKey;
976                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
977                    if (pOtherKey->Active) {
978                        // get final portamento position of currently active voice
979                        if (pEngineChannel->PortamentoMode) {
980                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
981                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
982                        }
983                        // kill all voices on the (other) key
984                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
985                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
986                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
987                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
988                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
989                        }
990                    }
991                }
992                // set this key as 'currently active solo key'
993                pEngineChannel->SoloKey = key;
994            }
995    
996          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
997          {          {
998              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
999              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1000                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1001                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1002          }          }
1003    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
1004          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
1005          pKey->Velocity   = itNoteOnEvent->Param.Note.Velocity;          pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1006          pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length          pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1007    
1008          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
1009          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
1010              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1011              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
1012                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1013                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1014              }              }
1015              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
1016          }          }
1017    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
1018          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
1019          {          {
1020              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
1021              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1022              if (pRegion) {              if (pRegion && !RegionSuspended(pRegion)) {
1023                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
1024                  // now launch the required amount of voices                  // now launch the required amount of voices
1025                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
1026                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true);                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1027              }              }
1028          }          }
1029    
# Line 656  namespace LinuxSampler { namespace gig { Line 1031  namespace LinuxSampler { namespace gig {
1031          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
1032              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
1033    
1034            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1035          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
1036      }      }
1037    
# Line 669  namespace LinuxSampler { namespace gig { Line 1045  namespace LinuxSampler { namespace gig {
1045       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
1046       */       */
1047      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1048          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
1049            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1050            #endif
1051    
1052            //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
1053            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1054    
1055            const int iKey = itNoteOffEvent->Param.Note.Key;
1056            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1057          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
1058    
1059          // release voices on this key if needed          // move event to the key's own event list
1060          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1061              itNoteOffEvent->Type = Event::type_release; // transform event type  
1062            bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1063    
1064            // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1065            if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1066                bool bOtherKeysPressed = false;
1067                if (iKey == pEngineChannel->SoloKey) {
1068                    pEngineChannel->SoloKey = -1;
1069                    // if there's still a key pressed down, respawn a voice (group) on the highest key
1070                    for (int i = 127; i > 0; i--) {
1071                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1072                        if (pOtherKey->KeyPressed) {
1073                            bOtherKeysPressed = true;
1074                            // make the other key the new 'currently active solo key'
1075                            pEngineChannel->SoloKey = i;
1076                            // get final portamento position of currently active voice
1077                            if (pEngineChannel->PortamentoMode) {
1078                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1079                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1080                            }
1081                            // create a pseudo note on event
1082                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1083                            if (itPseudoNoteOnEvent) {
1084                                // copy event
1085                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1086                                // transform event to a note on event
1087                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
1088                                itPseudoNoteOnEvent->Param.Note.Key      = i;
1089                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1090                                // allocate and trigger new voice(s) for the other key
1091                                {
1092                                    // first, get total amount of required voices (dependant on amount of layers)
1093                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1094                                    if (pRegion) {
1095                                        int voicesRequired = pRegion->Layers;
1096                                        // now launch the required amount of voices
1097                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1098                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1099                                    }
1100                                }
1101                                // if neither a voice was spawned or postponed then remove note on event from key again
1102                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1103                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1104    
1105                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
1106                            break; // done
1107                        }
1108                    }
1109                }
1110                if (bOtherKeysPressed) {
1111                    if (pKey->Active) { // kill all voices on this key
1112                        bShouldRelease = false; // no need to release, as we kill it here
1113                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1114                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
1115                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1116                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1117                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1118                        }
1119                    }
1120                } else pEngineChannel->PortamentoPos = -1.0f;
1121            }
1122    
1123              // move event to the key's own event list          // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1124              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          if (bShouldRelease) {
1125                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1126    
1127              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
1128              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1129                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
1130                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1131                  if (pRegion) {                  if (pRegion) {
# Line 692  namespace LinuxSampler { namespace gig { Line 1136  namespace LinuxSampler { namespace gig {
1136    
1137                      // now launch the required amount of voices                      // now launch the required amount of voices
1138                      for (int i = 0; i < voicesRequired; i++)                      for (int i = 0; i < voicesRequired; i++)
1139                          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
1140                  }                  }
1141                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
1142              }              }
   
             // 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);  
1143          }          }
1144    
1145            // if neither a voice was spawned or postponed on this key then remove note off event from key again
1146            if (!pKey->Active && !pKey->VoiceTheftsQueued)
1147                pKey->pEvents->free(itNoteOffEventOnKeyList);
1148      }      }
1149    
1150      /**      /**
1151       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
1152       *  event list.       *  channel's event list. It will actually processed later by the
1153         *  respective voice.
1154       *       *
1155       *  @param pEngineChannel - engine channel on which this event occured on       *  @param pEngineChannel - engine channel on which this event occured on
1156       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
1157       */       */
1158      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1159          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]);  
1160      }      }
1161    
1162      /**      /**
# Line 729  namespace LinuxSampler { namespace gig { Line 1173  namespace LinuxSampler { namespace gig {
1173       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
1174       *                               when there is no free voice       *                               when there is no free voice
1175       *                               (optional, default = true)       *                               (optional, default = true)
1176         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
1177         *                                   key group conflict
1178       *  @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
1179       *           if the voice wasn't triggered (for example when no region is       *           if the voice wasn't triggered (for example when no region is
1180       *           defined for the given key).       *           defined for the given key).
1181       */       */
1182      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) {
1183          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
1184            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1185            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1186    
1187            // if nothing defined for this key
1188            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1189    
1190            // only mark the first voice of a layered voice (group) to be in a
1191            // key group, so the layered voices won't kill each other
1192            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1193    
1194            // handle key group (a.k.a. exclusive group) conflicts
1195            if (HandleKeyGroupConflicts) {
1196                if (iKeyGroup) { // if this voice / key belongs to a key group
1197                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1198                    if (*ppKeyGroup) { // if there's already an active key in that key group
1199                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1200                        // kill all voices on the (other) key
1201                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1202                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1203                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1204                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1205                                itVoiceToBeKilled->Kill(itNoteOnEvent);
1206                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1207                            }
1208                        }
1209                    }
1210                }
1211            }
1212    
1213            Voice::type_t VoiceType = Voice::type_normal;
1214    
1215            // get current dimension values to select the right dimension region
1216            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1217            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1218            uint DimValues[8] = { 0 };
1219            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1220                switch (pRegion->pDimensionDefinitions[i].dimension) {
1221                    case ::gig::dimension_samplechannel:
1222                        DimValues[i] = 0; //TODO: we currently ignore this dimension
1223                        break;
1224                    case ::gig::dimension_layer:
1225                        DimValues[i] = iLayer;
1226                        break;
1227                    case ::gig::dimension_velocity:
1228                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1229                        break;
1230                    case ::gig::dimension_channelaftertouch:
1231                        DimValues[i] = pEngineChannel->ControllerTable[128];
1232                        break;
1233                    case ::gig::dimension_releasetrigger:
1234                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1235                        DimValues[i] = (uint) ReleaseTriggerVoice;
1236                        break;
1237                    case ::gig::dimension_keyboard:
1238                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1239                        break;
1240                    case ::gig::dimension_roundrobin:
1241                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1242                        break;
1243                    case ::gig::dimension_random:
1244                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1245                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1246                        break;
1247                    case ::gig::dimension_modwheel:
1248                        DimValues[i] = pEngineChannel->ControllerTable[1];
1249                        break;
1250                    case ::gig::dimension_breath:
1251                        DimValues[i] = pEngineChannel->ControllerTable[2];
1252                        break;
1253                    case ::gig::dimension_foot:
1254                        DimValues[i] = pEngineChannel->ControllerTable[4];
1255                        break;
1256                    case ::gig::dimension_portamentotime:
1257                        DimValues[i] = pEngineChannel->ControllerTable[5];
1258                        break;
1259                    case ::gig::dimension_effect1:
1260                        DimValues[i] = pEngineChannel->ControllerTable[12];
1261                        break;
1262                    case ::gig::dimension_effect2:
1263                        DimValues[i] = pEngineChannel->ControllerTable[13];
1264                        break;
1265                    case ::gig::dimension_genpurpose1:
1266                        DimValues[i] = pEngineChannel->ControllerTable[16];
1267                        break;
1268                    case ::gig::dimension_genpurpose2:
1269                        DimValues[i] = pEngineChannel->ControllerTable[17];
1270                        break;
1271                    case ::gig::dimension_genpurpose3:
1272                        DimValues[i] = pEngineChannel->ControllerTable[18];
1273                        break;
1274                    case ::gig::dimension_genpurpose4:
1275                        DimValues[i] = pEngineChannel->ControllerTable[19];
1276                        break;
1277                    case ::gig::dimension_sustainpedal:
1278                        DimValues[i] = pEngineChannel->ControllerTable[64];
1279                        break;
1280                    case ::gig::dimension_portamento:
1281                        DimValues[i] = pEngineChannel->ControllerTable[65];
1282                        break;
1283                    case ::gig::dimension_sostenutopedal:
1284                        DimValues[i] = pEngineChannel->ControllerTable[66];
1285                        break;
1286                    case ::gig::dimension_softpedal:
1287                        DimValues[i] = pEngineChannel->ControllerTable[67];
1288                        break;
1289                    case ::gig::dimension_genpurpose5:
1290                        DimValues[i] = pEngineChannel->ControllerTable[80];
1291                        break;
1292                    case ::gig::dimension_genpurpose6:
1293                        DimValues[i] = pEngineChannel->ControllerTable[81];
1294                        break;
1295                    case ::gig::dimension_genpurpose7:
1296                        DimValues[i] = pEngineChannel->ControllerTable[82];
1297                        break;
1298                    case ::gig::dimension_genpurpose8:
1299                        DimValues[i] = pEngineChannel->ControllerTable[83];
1300                        break;
1301                    case ::gig::dimension_effect1depth:
1302                        DimValues[i] = pEngineChannel->ControllerTable[91];
1303                        break;
1304                    case ::gig::dimension_effect2depth:
1305                        DimValues[i] = pEngineChannel->ControllerTable[92];
1306                        break;
1307                    case ::gig::dimension_effect3depth:
1308                        DimValues[i] = pEngineChannel->ControllerTable[93];
1309                        break;
1310                    case ::gig::dimension_effect4depth:
1311                        DimValues[i] = pEngineChannel->ControllerTable[94];
1312                        break;
1313                    case ::gig::dimension_effect5depth:
1314                        DimValues[i] = pEngineChannel->ControllerTable[95];
1315                        break;
1316                    case ::gig::dimension_none:
1317                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1318                        break;
1319                    default:
1320                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1321                }
1322            }
1323    
1324            // return if this is a release triggered voice and there is no
1325            // releasetrigger dimension (could happen if an instrument
1326            // change has occured between note on and off)
1327            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1328    
1329            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1330    
1331            // no need to continue if sample is silent
1332            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1333    
1334          // allocate a new voice for the key          // allocate a new voice for the key
1335          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1336          if (itNewVoice) {          if (itNewVoice) {
1337              // launch the new voice              // launch the new voice
1338              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pEngineChannel->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1339                  dmsg(4,("Voice not triggered\n"));                  dmsg(4,("Voice not triggered\n"));
1340                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1341              }              }
1342              else { // on success              else { // on success
1343                  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);  
                         }  
                     }  
                 }  
1344                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1345                      pKey->Active = true;                      pKey->Active = true;
1346                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1347                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1348                  }                  }
1349                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1350                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1351                      *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
1352                  }                  }
1353                  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 1384  namespace LinuxSampler { namespace gig {
1384       *  @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
1385       */       */
1386      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1387          if (!VoiceTheftsLeft) {          if (VoiceSpawnsLeft <= 0) {
1388              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"));
1389              return -1;              return -1;
1390          }          }
# Line 819  namespace LinuxSampler { namespace gig { Line 1403  namespace LinuxSampler { namespace gig {
1403                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1404                      itSelectedVoice = pSelectedKey->pActiveVoices->first();                      itSelectedVoice = pSelectedKey->pActiveVoices->first();
1405                      // proceed iterating if voice was created in this fragment cycle                      // proceed iterating if voice was created in this fragment cycle
1406                      while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                      while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1407                      // if we haven't found a voice then proceed with algorithm 'oldestkey'                      // if we haven't found a voice then proceed with algorithm 'oldestkey'
1408                      if (itSelectedVoice && itSelectedVoice->hasRendered()) break;                      if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
1409                  } // no break - intentional !                  } // no break - intentional !
1410    
1411                  // 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 1417  namespace LinuxSampler { namespace gig {
1417                          itSelectedVoice = this->itLastStolenVoice;                          itSelectedVoice = this->itLastStolenVoice;
1418                          do {                          do {
1419                              ++itSelectedVoice;                              ++itSelectedVoice;
1420                          } 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
1421                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1422                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1423                              // 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
1424                              this->itLastStolenVoice = itSelectedVoice;                              this->itLastStolenVoice = itSelectedVoice;
1425                              break; // selection succeeded                              break; // selection succeeded
# Line 847  namespace LinuxSampler { namespace gig { Line 1431  namespace LinuxSampler { namespace gig {
1431                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1432                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          itSelectedVoice = pSelectedKey->pActiveVoices->first();
1433                          // proceed iterating if voice was created in this fragment cycle                          // proceed iterating if voice was created in this fragment cycle
1434                          while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1435                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1436                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1437                              // 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
1438                              this->iuiLastStolenKey  = iuiSelectedKey;                              this->iuiLastStolenKey  = iuiSelectedKey;
1439                              this->itLastStolenVoice = itSelectedVoice;                              this->itLastStolenVoice = itSelectedVoice;
# Line 871  namespace LinuxSampler { namespace gig { Line 1455  namespace LinuxSampler { namespace gig {
1455              // 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
1456              // steal oldest voice on the oldest key from any other engine channel              // steal oldest voice on the oldest key from any other engine channel
1457              // (the smaller engine channel number, the higher priority)              // (the smaller engine channel number, the higher priority)
1458              if (!itSelectedVoice || !itSelectedVoice->hasRendered()) {              if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1459                  EngineChannel* pSelectedChannel;                  EngineChannel* pSelectedChannel;
1460                  int            iChannelIndex;                  int            iChannelIndex;
1461                  // select engine channel                  // select engine channel
# Line 882  namespace LinuxSampler { namespace gig { Line 1466  namespace LinuxSampler { namespace gig {
1466                      iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1467                      pSelectedChannel = engineChannels[iChannelIndex];                      pSelectedChannel = engineChannels[iChannelIndex];
1468                  }                  }
1469                  // iterate through engine channels  
1470                  while (true) {                  // if we already stole in this fragment, try to proceed on same key
1471                      // if we already stole in this fragment, try to proceed on same key                  if (this->itLastStolenVoiceGlobally) {
1472                      if (this->itLastStolenVoiceGlobally) {                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1473                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      do {
1474                          do {                          ++itSelectedVoice;
1475                              ++itSelectedVoice;                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1476                          } while (itSelectedVoice && !itSelectedVoice->hasRendered()); // proceed iterating if voice was created in this fragment cycle                  }
1477                          // break if selection succeeded  
1478                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                  #if CONFIG_DEVMODE
1479                              // remember which voice we stole, so we can simply proceed on next voice stealing                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1480                              this->itLastStolenVoiceGlobally = itSelectedVoice;                  #endif // CONFIG_DEVMODE
1481                              break; // selection succeeded  
1482                          }                  // did we find a 'stealable' voice?
1483                      }                  if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1484                        // remember which voice we stole, so we can simply proceed on next voice stealing
1485                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1486                    } else while (true) { // iterate through engine channels
1487                      // get (next) oldest key                      // get (next) oldest key
1488                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pSelectedChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1489                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1490                      while (iuiSelectedKey) {                      while (iuiSelectedKey) {
1491                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];                          midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1492                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          itSelectedVoice = pSelectedKey->pActiveVoices->first();
1493                          // proceed iterating if voice was created in this fragment cycle                          // proceed iterating if voice was created in this fragment cycle
1494                          while (itSelectedVoice && !itSelectedVoice->hasRendered()) ++itSelectedVoice;                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1495                          // found a "stealable" voice ?                          // found a "stealable" voice ?
1496                          if (itSelectedVoice && itSelectedVoice->hasRendered()) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1497                              // 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
1498                              this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                              this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1499                              this->itLastStolenVoiceGlobally = itSelectedVoice;                              this->itLastStolenVoiceGlobally = itSelectedVoice;
1500                              this->pLastStolenChannel        = pSelectedChannel;                              this->pLastStolenChannel        = pSelectedChannel;
1501                              break; // selection succeeded                              goto stealable_voice_found; // selection succeeded
1502                          }                          }
1503                          ++iuiSelectedKey; // get next key on current engine channel                          ++iuiSelectedKey; // get next key on current engine channel
1504                      }                      }
1505                      // get next engine channel                      // get next engine channel
1506                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1507                      pSelectedChannel = engineChannels[iChannelIndex];                      pSelectedChannel = engineChannels[iChannelIndex];
1508    
1509                        #if CONFIG_DEVMODE
1510                        if (pSelectedChannel == pBegin) {
1511                            dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1512                            dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1513                            dmsg(1,("Exiting.\n"));
1514                            exit(-1);
1515                        }
1516                        #endif // CONFIG_DEVMODE
1517                  }                  }
1518              }              }
1519    
1520                // jump point if a 'stealable' voice was found
1521                stealable_voice_found:
1522    
1523              #if CONFIG_DEVMODE              #if CONFIG_DEVMODE
1524              if (!itSelectedVoice->IsActive()) {              if (!itSelectedVoice->IsActive()) {
1525                  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 1530  namespace LinuxSampler { namespace gig {
1530              // now kill the selected voice              // now kill the selected voice
1531              itSelectedVoice->Kill(itNoteOnEvent);              itSelectedVoice->Kill(itNoteOnEvent);
1532    
1533              --VoiceTheftsLeft;              --VoiceSpawnsLeft;
1534    
1535              return 0; // success              return 0; // success
1536          }          }
# Line 955  namespace LinuxSampler { namespace gig { Line 1555  namespace LinuxSampler { namespace gig {
1555    
1556              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1557    
1558                // if the sample and dimension region belong to an
1559                // instrument that is unloaded, tell the disk thread to
1560                // release them
1561                if (itVoice->Orphan) {
1562                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1563                }
1564    
1565              // free the voice object              // free the voice object
1566              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1567    
# Line 999  namespace LinuxSampler { namespace gig { Line 1606  namespace LinuxSampler { namespace gig {
1606          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1607          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1608    
1609          // move event from the unsorted event list to the control change event list          // handle hard coded MIDI controllers
1610          Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pCCEvents);          switch (itControlChangeEvent->Param.CC.Controller) {
1611                case 5: { // portamento time
1612          switch (itControlChangeEventOnCCList->Param.CC.Controller) {                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1613                    break;
1614                }
1615                case 6: { // data entry (currently only used for RPN controllers)
1616                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1617                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1618                        // limit to +- two octaves for now
1619                        transpose = RTMath::Min(transpose,  24);
1620                        transpose = RTMath::Max(transpose, -24);
1621                        pEngineChannel->GlobalTranspose = transpose;
1622                        // workaround, so we won't have hanging notes
1623                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1624                    }
1625                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1626                    pEngineChannel->ResetMidiRpnController();
1627                    break;
1628                }
1629              case 7: { // volume              case 7: { // volume
1630                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1631                  pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1632                    pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1633                  break;                  break;
1634              }              }
1635              case 10: { // panpot              case 10: { // panpot
1636                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1637                  const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1638                  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;  
1639                  break;                  break;
1640              }              }
1641              case 64: { // sustain              case 64: { // sustain
1642                  if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1643                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1644                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1645    
1646                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1647                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1648                        #endif
1649    
1650                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1651                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1652                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
# Line 1027  namespace LinuxSampler { namespace gig { Line 1654  namespace LinuxSampler { namespace gig {
1654                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed) {
1655                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1656                              if (itNewEvent) {                              if (itNewEvent) {
1657                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1658                                  itNewEvent->Type = Event::type_cancel_release; // transform event type                                  itNewEvent->Type = Event::type_cancel_release; // transform event type
1659                              }                              }
1660                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
1661                          }                          }
1662                      }                      }
1663                  }                  }
1664                  if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1665                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1666                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1667    
1668                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1669                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1670                        #endif
1671    
1672                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1673                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1674                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1675                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1676                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1677                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1678                              if (itNewEvent) {                              if (itNewEvent) {
1679                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1680                                  itNewEvent->Type = Event::type_release; // transform event type                                  itNewEvent->Type = Event::type_release; // transform event type
1681                              }                              }
1682                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
# Line 1054  namespace LinuxSampler { namespace gig { Line 1685  namespace LinuxSampler { namespace gig {
1685                  }                  }
1686                  break;                  break;
1687              }              }
1688                case 65: { // portamento on / off
1689                    const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1690                    if (bPortamento != pEngineChannel->PortamentoMode)
1691                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1692                    pEngineChannel->PortamentoMode = bPortamento;
1693                    break;
1694                }
1695                case 66: { // sostenuto
1696                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1697                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1698                        pEngineChannel->SostenutoPedal = true;
1699    
1700                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1701                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1702                        #endif
1703    
1704                        SostenutoKeyCount = 0;
1705                        // Remeber the pressed keys
1706                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1707                        for (; iuiKey; ++iuiKey) {
1708                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1709                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1710                        }
1711                    }
1712                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1713                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1714                        pEngineChannel->SostenutoPedal = false;
1715    
1716                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1717                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1718                        #endif
1719    
1720                        // release voices if the damper pedal is up and their respective key is not pressed
1721                        for (int i = 0; i < SostenutoKeyCount; i++) {
1722                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1723                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1724                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1725                                if (itNewEvent) {
1726                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1727                                    itNewEvent->Type = Event::type_release; // transform event type
1728                                }
1729                                else dmsg(1,("Event pool emtpy!\n"));
1730                            }
1731                        }
1732                    }
1733                    break;
1734                }
1735                case 100: { // RPN controller LSB
1736                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1737                    break;
1738                }
1739                case 101: { // RPN controller MSB
1740                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1741                    break;
1742                }
1743    
1744    
1745              // Channel Mode Messages              // Channel Mode Messages
1746    
1747              case 120: { // all sound off              case 120: { // all sound off
1748                  KillAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1749                  break;                  break;
1750              }              }
1751              case 121: { // reset all controllers              case 121: { // reset all controllers
# Line 1067  namespace LinuxSampler { namespace gig { Line 1753  namespace LinuxSampler { namespace gig {
1753                  break;                  break;
1754              }              }
1755              case 123: { // all notes off              case 123: { // all notes off
1756                  ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  #if CONFIG_PROCESS_ALL_NOTES_OFF
1757                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1758                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1759                    break;
1760                }
1761                case 126: { // mono mode on
1762                    if (!pEngineChannel->SoloMode)
1763                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1764                    pEngineChannel->SoloMode = true;
1765                    break;
1766                }
1767                case 127: { // poly mode on
1768                    if (pEngineChannel->SoloMode)
1769                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1770                    pEngineChannel->SoloMode = false;
1771                  break;                  break;
1772              }              }
1773          }          }
1774    
1775            // handle FX send controllers
1776            if (!pEngineChannel->fxSends.empty()) {
1777                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1778                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1779                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1780                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1781                        pFxSend->SetInfoChanged(true);
1782                }
1783            }
1784      }      }
1785    
1786      /**      /**
# Line 1079  namespace LinuxSampler { namespace gig { Line 1789  namespace LinuxSampler { namespace gig {
1789       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1790       */       */
1791      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1792          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1793    
1794          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1795          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 1808  namespace LinuxSampler { namespace gig {
1808    
1809                  // command address                  // command address
1810                  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)
1811                  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
1812                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1813                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1814                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
# Line 1145  namespace LinuxSampler { namespace gig { Line 1855  namespace LinuxSampler { namespace gig {
1855       *                     question       *                     question
1856       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1857       */       */
1858      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) {
1859          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1860          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1861          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1862          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1205  namespace LinuxSampler { namespace gig { Line 1915  namespace LinuxSampler { namespace gig {
1915              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
1916              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
1917                  itVoice->Kill(itKillEvent);                  itVoice->Kill(itKillEvent);
1918                    --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1919              }              }
1920          }          }
1921      }      }
1922    
1923      /**      /**
1924       * Initialize the parameter sequence for the modulation destination given by       * Determines whether the specified voice should be released.
1925       * by 'dst' with the constant value given by val.       *
1926         * @param pEngineChannel - The engine channel on which the voice should be checked
1927         * @param Key - The key number
1928         * @returns true if the specified should be released, false otherwise.
1929       */       */
1930      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
1931          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          if (pEngineChannel->SustainPedal) return false;
1932          float* m = &pSynthesisParameters[dst][0];  
1933          for (int i = 0; i < maxsamples; i += 4) {          if (pEngineChannel->SostenutoPedal) {
1934             m[i]   = val;              for (int i = 0; i < SostenutoKeyCount; i++)
1935             m[i+1] = val;                  if (Key == SostenutoKeys[i]) return false;
            m[i+2] = val;  
            m[i+3] = val;  
1936          }          }
1937    
1938            return true;
1939      }      }
1940    
1941      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
# Line 1261  namespace LinuxSampler { namespace gig { Line 1975  namespace LinuxSampler { namespace gig {
1975      }      }
1976    
1977      String Engine::Version() {      String Engine::Version() {
1978          String s = "$Revision: 1.42 $";          String s = "$Revision: 1.81 $";
1979          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
1980      }      }
1981    
1982        InstrumentManager* Engine::GetInstrumentManager() {
1983            return &instruments;
1984        }
1985    
1986        // static constant initializers
1987        const float* Engine::VolumeCurve(InitVolumeCurve());
1988        const float* Engine::PanCurve(InitPanCurve());
1989        const float* Engine::CrossfadeCurve(InitCrossfadeCurve());
1990    
1991        float* Engine::InitVolumeCurve() {
1992            // line-segment approximation
1993            const float segments[] = {
1994                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
1995                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
1996            };
1997            return InitCurve(segments);
1998        }
1999    
2000        float* Engine::InitPanCurve() {
2001            // line-segment approximation
2002            const float segments[] = {
2003                0, 0, 1, 0,
2004                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2005                127, 1.41, 128, 1.41
2006            };
2007            return InitCurve(segments, 129);
2008        }
2009    
2010        float* Engine::InitCrossfadeCurve() {
2011            // line-segment approximation
2012            const float segments[] = {
2013                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2014            };
2015            return InitCurve(segments);
2016        }
2017    
2018        float* Engine::InitCurve(const float* segments, int size) {
2019            float* y = new float[size];
2020            for (int x = 0 ; x < size ; x++) {
2021                if (x > segments[2]) segments += 2;
2022                y[x] = segments[1] + (x - segments[0]) *
2023                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
2024            }
2025            return y;
2026        }
2027    
2028        /**
2029         * Changes the instrument for an engine channel.
2030         *
2031         * @param pEngineChannel - engine channel on which the instrument
2032         *                         should be changed
2033         * @param pInstrument - new instrument
2034         * @returns a list of dimension regions from the old instrument
2035         *          that are still in use
2036         */
2037        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
2038            instrument_change_command_t command;
2039            command.pEngineChannel = pEngineChannel;
2040            command.pInstrument = pInstrument;
2041            InstrumentChangeQueue->push(&command);
2042    
2043            // wait for the audio thread to confirm that the instrument
2044            // change has been done
2045            instrument_change_reply_t reply;
2046            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
2047                usleep(10000);
2048            }
2049            return pDimRegionsInUse;
2050        }
2051    
2052  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

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

  ViewVC Help
Powered by ViewVC