/[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 497 by persson, Sun Apr 10 11:55:44 2005 UTC revision 1646 by persson, Sun Jan 20 15:04:51 2008 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 29  Line 29 
29    
30  #include "Engine.h"  #include "Engine.h"
31    
32  #if defined(__APPLE__)  #include "../../common/global_private.h"
 # include <stdlib.h>  
 #else  
 # include <malloc.h>  
 #endif  
33    
34  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
35    
# Line 57  namespace LinuxSampler { namespace gig { Line 53  namespace LinuxSampler { namespace gig {
53          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
54              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
55              pEngine = engines[pDevice];              pEngine = engines[pDevice];
56    
57                // Disable the engine while the new engine channel is
58                // added and initialized. The engine will be enabled again
59                // in EngineChannel::Connect.
60                pEngine->DisableAndLock();
61          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
62              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
63              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 73  namespace LinuxSampler { namespace gig { Line 74  namespace LinuxSampler { namespace gig {
74    
75      /**      /**
76       * Once an engine channel is disconnected from an audio output device,       * Once an engine channel is disconnected from an audio output device,
77       * it wil immediately call this method to unregister itself from the       * it will immediately call this method to unregister itself from the
78       * engine instance and if that engine instance is not used by any other       * engine instance and if that engine instance is not used by any other
79       * engine channel anymore, then that engine instance will be destroyed.       * engine channel anymore, then that engine instance will be destroyed.
80       *       *
# Line 99  namespace LinuxSampler { namespace gig { Line 100  namespace LinuxSampler { namespace gig {
100      /**      /**
101       * Constructor       * Constructor
102       */       */
103      Engine::Engine() {      Engine::Engine() : SuspendedRegions(128) {
104          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
105          pDiskThread        = NULL;          pDiskThread        = NULL;
106          pEventGenerator    = NULL;          pEventGenerator    = NULL;
107          pSysexBuffer       = new RingBuffer<uint8_t>(SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
108          pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109          pEventPool         = new Pool<Event>(MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110          pVoicePool         = new Pool<Voice>(MAX_AUDIO_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
111            pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
112            pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
115    
116          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
117              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
118          }          }
119          pVoicePool->clear();          pVoicePool->clear();
120    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
121          ResetInternal();          ResetInternal();
122            ResetScaleTuning();
123            ResetSuspendedRegions();
124      }      }
125    
126      /**      /**
127       * Destructor       * Destructor
128       */       */
129      Engine::~Engine() {      Engine::~Engine() {
130            MidiInputPort::RemoveSysexListener(this);
131          if (pDiskThread) {          if (pDiskThread) {
132              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
133              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 138  namespace LinuxSampler { namespace gig { Line 141  namespace LinuxSampler { namespace gig {
141              delete pVoicePool;              delete pVoicePool;
142          }          }
143          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
144          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
145          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
146          EngineFactory::Destroy(this);          if (pGlobalEvents) delete pGlobalEvents;
147            if (pDimRegionPool[0]) delete pDimRegionPool[0];
148            if (pDimRegionPool[1]) delete pDimRegionPool[1];
149            ResetSuspendedRegions();
150            Unregister();
151      }      }
152    
153      void Engine::Enable() {      void Engine::Enable() {
# Line 152  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 165  namespace LinuxSampler { namespace gig { Line 181  namespace LinuxSampler { namespace gig {
181      }      }
182    
183      /**      /**
184         * Similar to @c Disable() but this method additionally kills all voices
185         * and disk streams and blocks until all voices and disk streams are actually
186         * killed / deleted.
187         *
188         * @e Note: only the original calling thread is able to re-enable the
189         * engine afterwards by calling @c ResumeAll() later on!
190         */
191        void Engine::SuspendAll() {
192            dmsg(2,("gig::Engine: Suspending all ...\n"));
193            // stop the engine, so we can safely modify the engine's
194            // data structures from this foreign thread
195            DisableAndLock();
196            // we could also use the respective class member variable here,
197            // but this is probably safer and cleaner
198            int iPendingStreamDeletions = 0;
199            // kill all voices on all engine channels the *die hard* way
200            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
201                EngineChannel* pEngineChannel = engineChannels[iChannel];
202                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
203                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
204                for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
205                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
206                    RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
207                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
208                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
209                        // request a notification from disk thread side for stream deletion
210                        const Stream::Handle hStream = itVoice->KillImmediately(true);
211                        if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
212                            iPendingStreamDeletions++;
213                        }
214                    }
215                }
216            }
217            // wait until all streams were actually deleted by the disk thread
218            while (iPendingStreamDeletions) {
219                while (
220                    iPendingStreamDeletions &&
221                    pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
222                ) iPendingStreamDeletions--;
223                if (!iPendingStreamDeletions) break;
224                usleep(10000); // sleep for 10ms
225            }
226            dmsg(2,("gig::Engine: Everything suspended.\n"));
227        }
228    
229        /**
230         * At the moment same as calling @c Enable() directly, but this might
231         * change in future, so better call this method as counterpart to
232         * @c SuspendAll() instead of @c Enable() !
233         */
234        void Engine::ResumeAll() {
235            Enable();
236        }
237    
238        /**
239         * Order the engine to stop rendering audio for the given region.
240         * Additionally this method will block until all voices and their disk
241         * streams associated with that region are actually killed / deleted, so
242         * one can i.e. safely modify the region with an instrument editor after
243         * returning from this method.
244         *
245         * @param pRegion - region the engine shall stop using
246         */
247        void Engine::Suspend(::gig::Region* pRegion) {
248            dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
249            SuspendedRegionsMutex.Lock();
250            SuspensionChangeOngoing.Set(true);
251            pPendingRegionSuspension = pRegion;
252            SuspensionChangeOngoing.WaitAndUnlockIf(true);
253            SuspendedRegionsMutex.Unlock();
254            dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
255        }
256    
257        /**
258         * Orders the engine to resume playing back the given region, previously
259         * suspended with @c Suspend() .
260         *
261         * @param pRegion - region the engine shall be allowed to use again
262         */
263        void Engine::Resume(::gig::Region* pRegion) {
264            dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
265            SuspendedRegionsMutex.Lock();
266            SuspensionChangeOngoing.Set(true);
267            pPendingRegionResumption = pRegion;
268            SuspensionChangeOngoing.WaitAndUnlockIf(true);
269            SuspendedRegionsMutex.Unlock();
270            dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
271        }
272    
273        /**
274       *  Reset all voices and disk thread and clear input event queue and all       *  Reset all voices and disk thread and clear input event queue and all
275       *  control and status variables.       *  control and status variables.
276       */       */
277      void Engine::Reset() {      void Engine::Reset() {
278          DisableAndLock();          DisableAndLock();
279          ResetInternal();          ResetInternal();
280            ResetScaleTuning();
281          Enable();          Enable();
282      }      }
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    
297          // reset voice stealing parameters          // reset voice stealing parameters
298          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
299          itLastStolenVoice  = RTList<Voice>::Iterator();          itLastStolenVoice          = RTList<Voice>::Iterator();
300          iuiLastStolenKey   = RTList<uint>::Iterator();          itLastStolenVoiceGlobally  = RTList<Voice>::Iterator();
301          pLastStolenChannel = NULL;          iuiLastStolenKey           = RTList<uint>::Iterator();
302            iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
303          // reset to normal chromatic scale (means equal temper)          pLastStolenChannel         = NULL;
         memset(&ScaleTuning[0], 0x00, 12);  
304    
305          // reset all voices          // reset all voices
306          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()) {
# Line 202  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        /**
322         * Reset to normal, chromatic scale (means equal tempered).
323         */
324        void Engine::ResetScaleTuning() {
325            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      /**      /**
# Line 224  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();
359          this->SampleRate         = pAudioOutputDevice->SampleRate();          this->SampleRate         = pAudioOutputDevice->SampleRate();
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) * 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("EG_MIN_RELEASE_TIME in EGADSR.h 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 242  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() << 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 258  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 288  namespace LinuxSampler { namespace gig { Line 411  namespace LinuxSampler { namespace gig {
411      }      }
412    
413      /**      /**
414         * Called by the engine's (audio) thread once per cycle to process requests
415         * from the outer world to suspend or resume a given @c gig::Region .
416         */
417        void Engine::ProcessSuspensionsChanges() {
418            // process request for suspending one region
419            if (pPendingRegionSuspension) {
420                // kill all voices on all engine channels that use this region
421                for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
422                    EngineChannel* pEngineChannel = engineChannels[iChannel];
423                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
424                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
425                    for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
426                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
427                        RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
428                        // if current key is not associated with this region, skip this key
429                        if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
430                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
431                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
432                            // request a notification from disk thread side for stream deletion
433                            const Stream::Handle hStream = itVoice->KillImmediately(true);
434                            if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
435                                iPendingStreamDeletions++;
436                            }
437                        }
438                    }
439                }
440                // make sure the region is not yet on the list
441                bool bAlreadySuspended = false;
442                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
443                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
444                for (; iter != end; ++iter) { // iterate through all suspended regions
445                    if (*iter == pPendingRegionSuspension) { // found
446                        bAlreadySuspended = true;
447                        dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
448                        break;
449                    }
450                }
451                if (!bAlreadySuspended) {
452                    // put the region on the list of suspended regions
453                    RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
454                    if (iter) {
455                        *iter = pPendingRegionSuspension;
456                    } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
457                }
458                // free request slot for next caller (and to make sure that
459                // we're not going to process the same request in the next cycle)
460                pPendingRegionSuspension = NULL;
461                // if no disk stream deletions are pending, awaken other side, as
462                // we're done in this case
463                if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
464            }
465    
466            // process request for resuming one region
467            if (pPendingRegionResumption) {
468                // remove region from the list of suspended regions
469                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
470                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
471                for (; iter != end; ++iter) { // iterate through all suspended regions
472                    if (*iter == pPendingRegionResumption) { // found
473                        SuspendedRegions.free(iter);
474                        break; // done
475                    }
476                }
477                // free request slot for next caller
478                pPendingRegionResumption = NULL;
479                // awake other side as we're done
480                SuspensionChangeOngoing.Set(false);
481            }
482        }
483    
484        /**
485         * Called by the engine's (audio) thread once per cycle to check if
486         * streams of voices that were killed due to suspension request have
487         * finally really been deleted by the disk thread.
488         */
489        void Engine::ProcessPendingStreamDeletions() {
490            if (!iPendingStreamDeletions) return;
491            //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
492            while (
493                iPendingStreamDeletions &&
494                pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
495            ) iPendingStreamDeletions--;
496            // just for safety ...
497            while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
498            // now that all disk streams are deleted, awake other side as
499            // we're finally done with suspending the requested region
500            if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
501        }
502    
503        /**
504         * Returns @c true if the given region is currently set to be suspended
505         * from being used, @c false otherwise.
506         */
507        bool Engine::RegionSuspended(::gig::Region* pRegion) {
508            if (SuspendedRegions.isEmpty()) return false;
509            //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
510            RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
511            RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
512            for (; iter != end; ++iter)  // iterate through all suspended regions
513                if (*iter == pRegion) return true;
514            return false;
515        }
516    
517        /**
518       * Clear all engine global event lists.       * Clear all engine global event lists.
519       */       */
520      void Engine::ClearEventLists() {      void Engine::ClearEventLists() {
# Line 308  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 331  namespace LinuxSampler { namespace gig { Line 558  namespace LinuxSampler { namespace gig {
558      }      }
559    
560      /**      /**
561       *  Let this engine proceed to render the given amount of sample points. The       * Let this engine proceed to render the given amount of sample points.
562       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
563       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
564       *  converted to the appropriate value range by the audio output class (e.g.       * all voices of each engine channel will be placed into the audio sum
565       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
566         * respective engine channel.
567       *       *
568       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
569       *  @returns       0 on success       *  @returns       0 on success
570       */       */
571      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
572          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
573    
574          // return if engine disabled          // return if engine disabled
575          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 349  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 370  namespace LinuxSampler { namespace gig { Line 607  namespace LinuxSampler { namespace gig {
607              }              }
608          }          }
609    
         // We only allow a maximum of MAX_AUDIO_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 = MAX_AUDIO_VOICES;  
   
610          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
611          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
612    
613            // handle instrument change commands
614            bool instrumentChanged = false;
615            for (int i = 0; i < engineChannels.size(); i++) {
616                EngineChannel* pEngineChannel = engineChannels[i];
617    
618                // as we're going to (carefully) write some status to the
619                // synchronized struct, we cast away the const
620                EngineChannel::instrument_change_command_t& cmd =
621                    const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
622    
623                pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
624                pEngineChannel->pDimRegionsInUse->clear();
625    
626                if (cmd.bChangeInstrument) {
627                    // change instrument
628                    dmsg(5,("Engine: instrument change command received\n"));
629                    cmd.bChangeInstrument = false;
630                    pEngineChannel->pInstrument = cmd.pInstrument;
631                    instrumentChanged = true;
632    
633                    // Iterate through all active voices and mark them as
634                    // "orphans", which means that the dimension regions
635                    // and samples they use should be released to the
636                    // instrument resource manager when the voices die.
637                    int i = 0;
638                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
639                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
640                    while (iuiKey != end) { // iterate through all active keys
641                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
642                        ++iuiKey;
643    
644                        RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
645                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
646                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
647                            itVoice->Orphan = true;
648                        }
649                    }
650                }
651            }
652            if (instrumentChanged) {
653                //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
654                ResetSuspendedRegions();
655            }
656    
657          // handle events on all engine channels          // handle events on all engine channels
658          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
659              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
660          }          }
661    
662          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
663          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
664              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
665          }          }
666    
667          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
668          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
669    
670            // handle audio routing for engine channels with FX sends
671            for (int i = 0; i < engineChannels.size(); i++) {
672                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
673                RouteAudio(engineChannels[i], Samples);
674            }
675    
676          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
677          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
678              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
679          }          }
680    
# Line 406  namespace LinuxSampler { namespace gig { Line 684  namespace LinuxSampler { namespace gig {
684    
685          // reset voice stealing for the next audio fragment          // reset voice stealing for the next audio fragment
686          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
         itLastStolenVoice  = RTList<Voice>::Iterator();  
         iuiLastStolenKey   = RTList<uint>::Iterator();  
         pLastStolenChannel = NULL;  
687    
688          // just some statistics about this engine instance          // just some statistics about this engine instance
689          ActiveVoiceCount = ActiveVoiceCountTemp;          ActiveVoiceCount = ActiveVoiceCountTemp;
690          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
691    
692            // in case regions were previously suspended and we killed voices
693            // with disk streams due to that, check if those streams have finally
694            // been deleted by the disk thread
695            if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
696    
697            for (int i = 0; i < engineChannels.size(); i++) {
698                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
699            }
700            FrameTime += Samples;
701    
702          return 0;          return 0;
703      }      }
704    
# Line 456  namespace LinuxSampler { namespace gig { Line 741  namespace LinuxSampler { namespace gig {
741                  }                  }
742              }              }
743          }          }
744    
745            // reset voice stealing for the next engine channel (or next audio fragment)
746            itLastStolenVoice         = RTList<Voice>::Iterator();
747            itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
748            iuiLastStolenKey          = RTList<uint>::Iterator();
749            iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
750            pLastStolenChannel        = NULL;
751      }      }
752    
753      /**      /**
# Line 468  namespace LinuxSampler { namespace gig { Line 760  namespace LinuxSampler { namespace gig {
760       *                         this audio fragment cycle       *                         this audio fragment cycle
761       */       */
762      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
763            #if !CONFIG_PROCESS_MUTED_CHANNELS
764            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
765            #endif
766    
767            uint voiceCount = 0;
768            uint streamCount = 0;
769          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
770          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
771          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 479  namespace LinuxSampler { namespace gig { Line 777  namespace LinuxSampler { namespace gig {
777              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
778                  // now render current voice                  // now render current voice
779                  itVoice->Render(Samples);                  itVoice->Render(Samples);
780                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
781                  else { // voice reached end, is now inactive                      if (!itVoice->Orphan) {
782                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
783                        }
784                        ActiveVoiceCountTemp++;
785                        voiceCount++;
786    
787                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
788                            if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;
789                        }
790                    }  else { // voice reached end, is now inactive
791                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
792                  }                  }
793              }              }
794          }          }
795    
796            pEngineChannel->SetVoiceCount(voiceCount);
797            pEngineChannel->SetDiskStreamCount(streamCount);
798      }      }
799    
800      /**      /**
# Line 505  namespace LinuxSampler { namespace gig { Line 815  namespace LinuxSampler { namespace gig {
815          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
816          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
817              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
818                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
819              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
820                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false);                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
821              if (itNewVoice) {              if (itNewVoice) {
822                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
823                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
824                  else { // voice reached end, is now inactive                      *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
825                        ActiveVoiceCountTemp++;
826                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
827    
828                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
829                            if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
830                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
831                            }
832                        }
833                    } else { // voice reached end, is now inactive
834                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
835                  }                  }
836              }              }
# Line 524  namespace LinuxSampler { namespace gig { Line 844  namespace LinuxSampler { namespace gig {
844      }      }
845    
846      /**      /**
847         * Will be called in case the respective engine channel sports FX send
848         * channels. In this particular case, engine channel local buffers are
849         * used to render and mix all voices to. This method is responsible for
850         * copying the audio data from those local buffers to the master audio
851         * output channels as well as to the FX send audio output channels with
852         * their respective FX send levels.
853         *
854         * @param pEngineChannel - engine channel from which audio should be
855         *                         routed
856         * @param Samples        - amount of sample points to be routed in
857         *                         this audio fragment cycle
858         */
859        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
860            // route master signal
861            {
862                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
863                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
864                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
865                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
866            }
867            // route FX send signal
868            {
869                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
870                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
871                    // left channel
872                    const int iDstL = pFxSend->DestinationChannel(0);
873                    if (iDstL < 0) {
874                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
875                    } else {
876                        AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
877                        if (!pDstL) {
878                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
879                        } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
880                    }
881                    // right channel
882                    const int iDstR = pFxSend->DestinationChannel(1);
883                    if (iDstR < 0) {
884                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
885                    } else {
886                        AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
887                        if (!pDstR) {
888                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
889                        } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
890                    }
891                }
892            }
893            // reset buffers with silence (zero out) for the next audio cycle
894            pEngineChannel->pChannelLeft->Clear();
895            pEngineChannel->pChannelRight->Clear();
896        }
897    
898        /**
899       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
900       * 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
901       * channel.       * channel.
# Line 539  namespace LinuxSampler { namespace gig { Line 911  namespace LinuxSampler { namespace gig {
911                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
912                  ++iuiKey;                  ++iuiKey;
913                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
914                  #if DEVMODE                  #if CONFIG_DEVMODE
915                  else { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)                  else { // just a sanity check for debugging
916                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
917                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
918                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
# Line 549  namespace LinuxSampler { namespace gig { Line 921  namespace LinuxSampler { namespace gig {
921                          }                          }
922                      }                      }
923                  }                  }
924                  #endif // DEVMODE                  #endif // CONFIG_DEVMODE
925              }              }
926          }          }
927    
# Line 584  namespace LinuxSampler { namespace gig { Line 956  namespace LinuxSampler { namespace gig {
956                  // finally place sysex event into input event queue                  // finally place sysex event into input event queue
957                  pEventQueue->push(&event);                  pEventQueue->push(&event);
958              }              }
959              else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,SYSEX_BUFFER_SIZE));              else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,CONFIG_SYSEX_BUFFER_SIZE));
960          }          }
961          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
962      }      }
# Line 596  namespace LinuxSampler { namespace gig { Line 968  namespace LinuxSampler { namespace gig {
968       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
969       */       */
970      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
971            #if !CONFIG_PROCESS_MUTED_CHANNELS
972            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
973            #endif
974    
975            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
976    
977            //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
978            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
979    
980          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
981            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
982    
983            // move note on event to the key's own event list
984            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
985    
986            // if Solo Mode then kill all already active voices
987            if (pEngineChannel->SoloMode) {
988                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
989                if (itYoungestKey) {
990                    const int iYoungestKey = *itYoungestKey;
991                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
992                    if (pOtherKey->Active) {
993                        // get final portamento position of currently active voice
994                        if (pEngineChannel->PortamentoMode) {
995                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
996                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
997                        }
998                        // kill all voices on the (other) key
999                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1000                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1001                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1002                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1003                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1004                        }
1005                    }
1006                }
1007                // set this key as 'currently active solo key'
1008                pEngineChannel->SoloKey = key;
1009            }
1010    
1011          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
1012          {          {
1013              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1014              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1015                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1016                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1017          }          }
1018    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
1019          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
1020            pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1021            pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1022    
1023          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
1024          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
1025              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1026              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
1027                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1028                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1029              }              }
1030              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
1031          }          }
1032    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
1033          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
1034          {          {
1035              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
1036              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1037              if (pRegion) {              if (pRegion && !RegionSuspended(pRegion)) {
1038                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
1039                  // now launch the required amount of voices                  // now launch the required amount of voices
1040                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
1041                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true);                      LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1042              }              }
1043          }          }
1044    
# Line 640  namespace LinuxSampler { namespace gig { Line 1046  namespace LinuxSampler { namespace gig {
1046          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
1047              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
1048    
1049            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1050          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
1051      }      }
1052    
# Line 653  namespace LinuxSampler { namespace gig { Line 1060  namespace LinuxSampler { namespace gig {
1060       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
1061       */       */
1062      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1063          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
1064            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1065            #endif
1066    
1067            //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
1068            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1069    
1070            const int iKey = itNoteOffEvent->Param.Note.Key;
1071            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1072          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
1073    
1074          // release voices on this key if needed          // move event to the key's own event list
1075          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
             itNoteOffEvent->Type = Event::type_release; // transform event type  
1076    
1077              // move event to the key's own event list          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1078              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);  
1079            // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1080            if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1081                bool bOtherKeysPressed = false;
1082                if (iKey == pEngineChannel->SoloKey) {
1083                    pEngineChannel->SoloKey = -1;
1084                    // if there's still a key pressed down, respawn a voice (group) on the highest key
1085                    for (int i = 127; i > 0; i--) {
1086                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1087                        if (pOtherKey->KeyPressed) {
1088                            bOtherKeysPressed = true;
1089                            // make the other key the new 'currently active solo key'
1090                            pEngineChannel->SoloKey = i;
1091                            // get final portamento position of currently active voice
1092                            if (pEngineChannel->PortamentoMode) {
1093                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1094                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1095                            }
1096                            // create a pseudo note on event
1097                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1098                            if (itPseudoNoteOnEvent) {
1099                                // copy event
1100                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1101                                // transform event to a note on event
1102                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
1103                                itPseudoNoteOnEvent->Param.Note.Key      = i;
1104                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1105                                // allocate and trigger new voice(s) for the other key
1106                                {
1107                                    // first, get total amount of required voices (dependant on amount of layers)
1108                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1109                                    if (pRegion) {
1110                                        int voicesRequired = pRegion->Layers;
1111                                        // now launch the required amount of voices
1112                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1113                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1114                                    }
1115                                }
1116                                // if neither a voice was spawned or postponed then remove note on event from key again
1117                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1118                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1119    
1120                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
1121                            break; // done
1122                        }
1123                    }
1124                }
1125                if (bOtherKeysPressed) {
1126                    if (pKey->Active) { // kill all voices on this key
1127                        bShouldRelease = false; // no need to release, as we kill it here
1128                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1129                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
1130                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1131                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1132                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1133                        }
1134                    }
1135                } else pEngineChannel->PortamentoPos = -1.0f;
1136            }
1137    
1138            // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1139            if (bShouldRelease) {
1140                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1141    
1142              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
1143              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1144                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
1145                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1146                  if (pRegion) {                  if (pRegion) {
1147                      int voicesRequired = pRegion->Layers;                      int voicesRequired = pRegion->Layers;
1148    
1149                        // MIDI note-on velocity is used instead of note-off velocity
1150                        itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
1151    
1152                      // now launch the required amount of voices                      // now launch the required amount of voices
1153                      for (int i = 0; i < voicesRequired; i++)                      for (int i = 0; i < voicesRequired; i++)
1154                          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
1155                  }                  }
1156                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
1157              }              }
   
             // 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);  
1158          }          }
1159    
1160            // if neither a voice was spawned or postponed on this key then remove note off event from key again
1161            if (!pKey->Active && !pKey->VoiceTheftsQueued)
1162                pKey->pEvents->free(itNoteOffEventOnKeyList);
1163      }      }
1164    
1165      /**      /**
1166       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
1167       *  event list.       *  channel's event list. It will actually processed later by the
1168         *  respective voice.
1169       *       *
1170       *  @param pEngineChannel - engine channel on which this event occured on       *  @param pEngineChannel - engine channel on which this event occured on
1171       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
1172       */       */
1173      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1174          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]);  
1175      }      }
1176    
1177      /**      /**
# Line 709  namespace LinuxSampler { namespace gig { Line 1188  namespace LinuxSampler { namespace gig {
1188       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
1189       *                               when there is no free voice       *                               when there is no free voice
1190       *                               (optional, default = true)       *                               (optional, default = true)
1191         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
1192         *                                   key group conflict
1193       *  @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
1194       *           if the voice wasn't triggered (for example when no region is       *           if the voice wasn't triggered (for example when no region is
1195       *           defined for the given key).       *           defined for the given key).
1196       */       */
1197      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) {
1198          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
1199            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1200            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1201    
1202            // if nothing defined for this key
1203            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1204    
1205            // only mark the first voice of a layered voice (group) to be in a
1206            // key group, so the layered voices won't kill each other
1207            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1208    
1209            // handle key group (a.k.a. exclusive group) conflicts
1210            if (HandleKeyGroupConflicts) {
1211                if (iKeyGroup) { // if this voice / key belongs to a key group
1212                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1213                    if (*ppKeyGroup) { // if there's already an active key in that key group
1214                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1215                        // kill all voices on the (other) key
1216                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1217                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1218                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1219                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1220                                itVoiceToBeKilled->Kill(itNoteOnEvent);
1221                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1222                            }
1223                        }
1224                    }
1225                }
1226            }
1227    
1228            Voice::type_t VoiceType = Voice::type_normal;
1229    
1230            // get current dimension values to select the right dimension region
1231            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1232            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1233            uint DimValues[8] = { 0 };
1234            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1235                switch (pRegion->pDimensionDefinitions[i].dimension) {
1236                    case ::gig::dimension_samplechannel:
1237                        DimValues[i] = 0; //TODO: we currently ignore this dimension
1238                        break;
1239                    case ::gig::dimension_layer:
1240                        DimValues[i] = iLayer;
1241                        break;
1242                    case ::gig::dimension_velocity:
1243                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1244                        break;
1245                    case ::gig::dimension_channelaftertouch:
1246                        DimValues[i] = pEngineChannel->ControllerTable[128];
1247                        break;
1248                    case ::gig::dimension_releasetrigger:
1249                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1250                        DimValues[i] = (uint) ReleaseTriggerVoice;
1251                        break;
1252                    case ::gig::dimension_keyboard:
1253                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1254                        break;
1255                    case ::gig::dimension_roundrobin:
1256                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1257                        break;
1258                    case ::gig::dimension_random:
1259                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1260                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1261                        break;
1262                    case ::gig::dimension_modwheel:
1263                        DimValues[i] = pEngineChannel->ControllerTable[1];
1264                        break;
1265                    case ::gig::dimension_breath:
1266                        DimValues[i] = pEngineChannel->ControllerTable[2];
1267                        break;
1268                    case ::gig::dimension_foot:
1269                        DimValues[i] = pEngineChannel->ControllerTable[4];
1270                        break;
1271                    case ::gig::dimension_portamentotime:
1272                        DimValues[i] = pEngineChannel->ControllerTable[5];
1273                        break;
1274                    case ::gig::dimension_effect1:
1275                        DimValues[i] = pEngineChannel->ControllerTable[12];
1276                        break;
1277                    case ::gig::dimension_effect2:
1278                        DimValues[i] = pEngineChannel->ControllerTable[13];
1279                        break;
1280                    case ::gig::dimension_genpurpose1:
1281                        DimValues[i] = pEngineChannel->ControllerTable[16];
1282                        break;
1283                    case ::gig::dimension_genpurpose2:
1284                        DimValues[i] = pEngineChannel->ControllerTable[17];
1285                        break;
1286                    case ::gig::dimension_genpurpose3:
1287                        DimValues[i] = pEngineChannel->ControllerTable[18];
1288                        break;
1289                    case ::gig::dimension_genpurpose4:
1290                        DimValues[i] = pEngineChannel->ControllerTable[19];
1291                        break;
1292                    case ::gig::dimension_sustainpedal:
1293                        DimValues[i] = pEngineChannel->ControllerTable[64];
1294                        break;
1295                    case ::gig::dimension_portamento:
1296                        DimValues[i] = pEngineChannel->ControllerTable[65];
1297                        break;
1298                    case ::gig::dimension_sostenutopedal:
1299                        DimValues[i] = pEngineChannel->ControllerTable[66];
1300                        break;
1301                    case ::gig::dimension_softpedal:
1302                        DimValues[i] = pEngineChannel->ControllerTable[67];
1303                        break;
1304                    case ::gig::dimension_genpurpose5:
1305                        DimValues[i] = pEngineChannel->ControllerTable[80];
1306                        break;
1307                    case ::gig::dimension_genpurpose6:
1308                        DimValues[i] = pEngineChannel->ControllerTable[81];
1309                        break;
1310                    case ::gig::dimension_genpurpose7:
1311                        DimValues[i] = pEngineChannel->ControllerTable[82];
1312                        break;
1313                    case ::gig::dimension_genpurpose8:
1314                        DimValues[i] = pEngineChannel->ControllerTable[83];
1315                        break;
1316                    case ::gig::dimension_effect1depth:
1317                        DimValues[i] = pEngineChannel->ControllerTable[91];
1318                        break;
1319                    case ::gig::dimension_effect2depth:
1320                        DimValues[i] = pEngineChannel->ControllerTable[92];
1321                        break;
1322                    case ::gig::dimension_effect3depth:
1323                        DimValues[i] = pEngineChannel->ControllerTable[93];
1324                        break;
1325                    case ::gig::dimension_effect4depth:
1326                        DimValues[i] = pEngineChannel->ControllerTable[94];
1327                        break;
1328                    case ::gig::dimension_effect5depth:
1329                        DimValues[i] = pEngineChannel->ControllerTable[95];
1330                        break;
1331                    case ::gig::dimension_none:
1332                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1333                        break;
1334                    default:
1335                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1336                }
1337            }
1338    
1339            // return if this is a release triggered voice and there is no
1340            // releasetrigger dimension (could happen if an instrument
1341            // change has occured between note on and off)
1342            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1343    
1344            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1345    
1346            // no need to continue if sample is silent
1347            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1348    
1349          // allocate a new voice for the key          // allocate a new voice for the key
1350          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1351          if (itNewVoice) {          if (itNewVoice) {
1352              // launch the new voice              // launch the new voice
1353              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pEngineChannel->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1354                  dmsg(4,("Voice not triggered\n"));                  dmsg(4,("Voice not triggered\n"));
1355                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1356              }              }
1357              else { // on success              else { // on success
1358                  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);  
                         }  
                     }  
                 }  
1359                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1360                      pKey->Active = true;                      pKey->Active = true;
1361                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1362                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1363                  }                  }
1364                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1365                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1366                      *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
1367                  }                  }
1368                  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 780  namespace LinuxSampler { namespace gig { Line 1399  namespace LinuxSampler { namespace gig {
1399       *  @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
1400       */       */
1401      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1402          if (!VoiceTheftsLeft) {          if (VoiceSpawnsLeft <= 0) {
1403              dmsg(1,("Max. voice thefts per audio fragment reached (you may raise MAX_AUDIO_VOICES).\n"));              dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1404              return -1;              return -1;
1405          }          }
1406          if (!pEventPool->poolIsEmpty()) {          if (!pEventPool->poolIsEmpty()) {
# Line 789  namespace LinuxSampler { namespace gig { Line 1408  namespace LinuxSampler { namespace gig {
1408              RTList<Voice>::Iterator itSelectedVoice;              RTList<Voice>::Iterator itSelectedVoice;
1409    
1410              // Select one voice for voice stealing              // Select one voice for voice stealing
1411              switch (VOICE_STEAL_ALGORITHM) {              switch (CONFIG_VOICE_STEAL_ALGO) {
1412    
1413                  // try to pick the oldest voice on the key where the new                  // try to pick the oldest voice on the key where the new
1414                  // voice should be spawned, if there is no voice on that                  // voice should be spawned, if there is no voice on that
1415                  // key, or no voice left to kill there, then procceed with                  // key, or no voice left to kill, then procceed with
1416                  // 'oldestkey' algorithm                  // 'oldestkey' algorithm
1417                  case voice_steal_algo_oldestvoiceonkey: {                  case voice_steal_algo_oldestvoiceonkey: {
                 #if 0 // FIXME: broken  
1418                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1419                      if (this->itLastStolenVoice) {                      itSelectedVoice = pSelectedKey->pActiveVoices->first();
1420                          itSelectedVoice = this->itLastStolenVoice;                      // proceed iterating if voice was created in this fragment cycle
1421                          ++itSelectedVoice;                      while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1422                      }                      // if we haven't found a voice then proceed with algorithm 'oldestkey'
1423                      else { // no voice stolen in this audio fragment cycle yet                      if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
                         itSelectedVoice = pSelectedKey->pActiveVoices->first();  
                     }  
                     if (itSelectedVoice) {  
                         iuiSelectedKey = pSelectedKey->itSelf;  
                         break; // selection succeeded  
                     }  
                 #endif  
1424                  } // no break - intentional !                  } // no break - intentional !
1425    
1426                  // try to pick the oldest voice on the oldest active key                  // try to pick the oldest voice on the oldest active key
1427                    // from the same engine channel
1428                  // (caution: must stay after 'oldestvoiceonkey' algorithm !)                  // (caution: must stay after 'oldestvoiceonkey' algorithm !)
1429                  case voice_steal_algo_oldestkey: {                  case voice_steal_algo_oldestkey: {
1430                        // if we already stole in this fragment, try to proceed on same key
1431                      if (this->itLastStolenVoice) {                      if (this->itLastStolenVoice) {
1432                          itSelectedVoice = this->itLastStolenVoice;                          itSelectedVoice = this->itLastStolenVoice;
1433                          ++itSelectedVoice;                          do {
1434                          if (itSelectedVoice) break; // selection succeeded                              ++itSelectedVoice;
1435                          RTList<uint>::Iterator iuiSelectedKey = this->iuiLastStolenKey;                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1436                          ++iuiSelectedKey;                          // found a "stealable" voice ?
1437                          if (iuiSelectedKey) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1438                              this->iuiLastStolenKey = iuiSelectedKey;                              // remember which voice we stole, so we can simply proceed on next voice stealing
1439                              midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];                              this->itLastStolenVoice = itSelectedVoice;
1440                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                              break; // selection succeeded
1441                            }
1442                        }
1443                        // get (next) oldest key
1444                        RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
1445                        while (iuiSelectedKey) {
1446                            midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1447                            itSelectedVoice = pSelectedKey->pActiveVoices->first();
1448                            // proceed iterating if voice was created in this fragment cycle
1449                            while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1450                            // found a "stealable" voice ?
1451                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1452                                // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1453                                this->iuiLastStolenKey  = iuiSelectedKey;
1454                                this->itLastStolenVoice = itSelectedVoice;
1455                              break; // selection succeeded                              break; // selection succeeded
1456                          }                          }
1457                            ++iuiSelectedKey; // get next oldest key
1458                      }                      }
1459                      break;                      break;
1460                  }                  }
# Line 839  namespace LinuxSampler { namespace gig { Line 1467  namespace LinuxSampler { namespace gig {
1467                  }                  }
1468              }              }
1469    
1470              // steal oldest voice on the oldest key from this or any other engine channel              // if we couldn't steal a voice from the same engine channel then
1471              if (!itSelectedVoice) {              // steal oldest voice on the oldest key from any other engine channel
1472                  EngineChannel* pSelectedChannel = (pLastStolenChannel) ? pLastStolenChannel : pEngineChannel;              // (the smaller engine channel number, the higher priority)
1473                  int iChannelIndex = pSelectedChannel->iEngineIndexSelf;              if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1474                  while (true) {                  EngineChannel* pSelectedChannel;
1475                      RTList<uint>::Iterator iuiSelectedKey = pSelectedChannel->pActiveKeys->first();                  int            iChannelIndex;
1476                      if (iuiSelectedKey) {                  // select engine channel
1477                    if (pLastStolenChannel) {
1478                        pSelectedChannel = pLastStolenChannel;
1479                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1480                    } else { // pick the engine channel followed by this engine channel
1481                        iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1482                        pSelectedChannel = engineChannels[iChannelIndex];
1483                    }
1484    
1485                    // if we already stole in this fragment, try to proceed on same key
1486                    if (this->itLastStolenVoiceGlobally) {
1487                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1488                        do {
1489                            ++itSelectedVoice;
1490                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1491                    }
1492    
1493                    #if CONFIG_DEVMODE
1494                    EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1495                    #endif // CONFIG_DEVMODE
1496    
1497                    // did we find a 'stealable' voice?
1498                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1499                        // remember which voice we stole, so we can simply proceed on next voice stealing
1500                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1501                    } else while (true) { // iterate through engine channels
1502                        // get (next) oldest key
1503                        RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1504                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1505                        while (iuiSelectedKey) {
1506                          midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                          midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1507                          itSelectedVoice    = pSelectedKey->pActiveVoices->first();                          itSelectedVoice = pSelectedKey->pActiveVoices->first();
1508                          iuiLastStolenKey   = iuiSelectedKey;                          // proceed iterating if voice was created in this fragment cycle
1509                          pLastStolenChannel = pSelectedChannel;                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1510                          break; // selection succeeded                          // found a "stealable" voice ?
1511                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1512                                // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1513                                this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1514                                this->itLastStolenVoiceGlobally = itSelectedVoice;
1515                                this->pLastStolenChannel        = pSelectedChannel;
1516                                goto stealable_voice_found; // selection succeeded
1517                            }
1518                            ++iuiSelectedKey; // get next key on current engine channel
1519                      }                      }
1520                        // get next engine channel
1521                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1522                      pSelectedChannel =  engineChannels[iChannelIndex];                      pSelectedChannel = engineChannels[iChannelIndex];
1523    
1524                        #if CONFIG_DEVMODE
1525                        if (pSelectedChannel == pBegin) {
1526                            dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1527                            dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1528                            dmsg(1,("Exiting.\n"));
1529                            exit(-1);
1530                        }
1531                        #endif // CONFIG_DEVMODE
1532                  }                  }
1533              }              }
1534    
1535              //FIXME: can be removed, just a sanity check for debugging              // jump point if a 'stealable' voice was found
1536                stealable_voice_found:
1537    
1538                #if CONFIG_DEVMODE
1539              if (!itSelectedVoice->IsActive()) {              if (!itSelectedVoice->IsActive()) {
1540                  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"));
1541                  return -1;                  return -1;
1542              }              }
1543                #endif // CONFIG_DEVMODE
1544    
1545              // now kill the selected voice              // now kill the selected voice
1546              itSelectedVoice->Kill(itNoteOnEvent);              itSelectedVoice->Kill(itNoteOnEvent);
1547    
1548              // remember which voice we stole, so we can simply proceed for the next voice stealing              --VoiceSpawnsLeft;
             itLastStolenVoice = itSelectedVoice;  
   
             --VoiceTheftsLeft;  
1549    
1550              return 0; // success              return 0; // success
1551          }          }
# Line 894  namespace LinuxSampler { namespace gig { Line 1570  namespace LinuxSampler { namespace gig {
1570    
1571              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1572    
1573                // if the sample and dimension region belong to an
1574                // instrument that is unloaded, tell the disk thread to
1575                // release them
1576                if (itVoice->Orphan) {
1577                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1578                }
1579    
1580              // free the voice object              // free the voice object
1581              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1582    
# Line 938  namespace LinuxSampler { namespace gig { Line 1621  namespace LinuxSampler { namespace gig {
1621          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1622          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1623    
1624          // move event from the unsorted event list to the control change event list          // handle hard coded MIDI controllers
1625          Pool<Event>::Iterator itControlChangeEventOnCCList = itControlChangeEvent.moveToEndOf(pEngineChannel->pCCEvents);          switch (itControlChangeEvent->Param.CC.Controller) {
1626                case 5: { // portamento time
1627          switch (itControlChangeEventOnCCList->Param.CC.Controller) {                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1628                    break;
1629                }
1630                case 6: { // data entry (currently only used for RPN controllers)
1631                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1632                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1633                        // limit to +- two octaves for now
1634                        transpose = RTMath::Min(transpose,  24);
1635                        transpose = RTMath::Max(transpose, -24);
1636                        pEngineChannel->GlobalTranspose = transpose;
1637                        // workaround, so we won't have hanging notes
1638                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1639                    }
1640                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1641                    pEngineChannel->ResetMidiRpnController();
1642                    break;
1643                }
1644              case 7: { // volume              case 7: { // volume
1645                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1646                  pEngineChannel->GlobalVolume = (float) itControlChangeEventOnCCList->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1647                    pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1648                  break;                  break;
1649              }              }
1650              case 10: { // panpot              case 10: { // panpot
1651                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1652                  const int pan = (int) itControlChangeEventOnCCList->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1653                  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;  
1654                  break;                  break;
1655              }              }
1656              case 64: { // sustain              case 64: { // sustain
1657                  if (itControlChangeEventOnCCList->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1658                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1659                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1660    
1661                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1662                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1663                        #endif
1664    
1665                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1666                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1667                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
# Line 966  namespace LinuxSampler { namespace gig { Line 1669  namespace LinuxSampler { namespace gig {
1669                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed) {
1670                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1671                              if (itNewEvent) {                              if (itNewEvent) {
1672                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1673                                  itNewEvent->Type = Event::type_cancel_release; // transform event type                                  itNewEvent->Type = Event::type_cancel_release; // transform event type
1674                              }                              }
1675                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
1676                          }                          }
1677                      }                      }
1678                  }                  }
1679                  if (itControlChangeEventOnCCList->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1680                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1681                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1682    
1683                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1684                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1685                        #endif
1686    
1687                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1688                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1689                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1690                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1691                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1692                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1693                                if (itNewEvent) {
1694                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1695                                    itNewEvent->Type = Event::type_release; // transform event type
1696                                }
1697                                else dmsg(1,("Event pool emtpy!\n"));
1698                            }
1699                        }
1700                    }
1701                    break;
1702                }
1703                case 65: { // portamento on / off
1704                    const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1705                    if (bPortamento != pEngineChannel->PortamentoMode)
1706                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1707                    pEngineChannel->PortamentoMode = bPortamento;
1708                    break;
1709                }
1710                case 66: { // sostenuto
1711                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1712                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1713                        pEngineChannel->SostenutoPedal = true;
1714    
1715                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1716                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1717                        #endif
1718    
1719                        SostenutoKeyCount = 0;
1720                        // Remeber the pressed keys
1721                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1722                        for (; iuiKey; ++iuiKey) {
1723                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1724                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1725                        }
1726                    }
1727                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1728                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1729                        pEngineChannel->SostenutoPedal = false;
1730    
1731                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1732                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1733                        #endif
1734    
1735                        // release voices if the damper pedal is up and their respective key is not pressed
1736                        for (int i = 0; i < SostenutoKeyCount; i++) {
1737                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1738                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1739                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1740                              if (itNewEvent) {                              if (itNewEvent) {
1741                                  *itNewEvent = *itControlChangeEventOnCCList; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1742                                  itNewEvent->Type = Event::type_release; // transform event type                                  itNewEvent->Type = Event::type_release; // transform event type
1743                              }                              }
1744                              else dmsg(1,("Event pool emtpy!\n"));                              else dmsg(1,("Event pool emtpy!\n"));
# Line 993  namespace LinuxSampler { namespace gig { Line 1747  namespace LinuxSampler { namespace gig {
1747                  }                  }
1748                  break;                  break;
1749              }              }
1750                case 100: { // RPN controller LSB
1751                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1752                    break;
1753                }
1754                case 101: { // RPN controller MSB
1755                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1756                    break;
1757                }
1758    
1759    
1760              // Channel Mode Messages              // Channel Mode Messages
1761    
1762              case 120: { // all sound off              case 120: { // all sound off
1763                  KillAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1764                  break;                  break;
1765              }              }
1766              case 121: { // reset all controllers              case 121: { // reset all controllers
# Line 1006  namespace LinuxSampler { namespace gig { Line 1768  namespace LinuxSampler { namespace gig {
1768                  break;                  break;
1769              }              }
1770              case 123: { // all notes off              case 123: { // all notes off
1771                  ReleaseAllVoices(pEngineChannel, itControlChangeEventOnCCList);                  #if CONFIG_PROCESS_ALL_NOTES_OFF
1772                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1773                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1774                    break;
1775                }
1776                case 126: { // mono mode on
1777                    if (!pEngineChannel->SoloMode)
1778                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1779                    pEngineChannel->SoloMode = true;
1780                    break;
1781                }
1782                case 127: { // poly mode on
1783                    if (pEngineChannel->SoloMode)
1784                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1785                    pEngineChannel->SoloMode = false;
1786                  break;                  break;
1787              }              }
1788          }          }
1789    
1790            // handle FX send controllers
1791            if (!pEngineChannel->fxSends.empty()) {
1792                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1793                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1794                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1795                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1796                        pFxSend->SetInfoChanged(true);
1797                }
1798            }
1799      }      }
1800    
1801      /**      /**
# Line 1018  namespace LinuxSampler { namespace gig { Line 1804  namespace LinuxSampler { namespace gig {
1804       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1805       */       */
1806      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1807          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1808    
1809          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1810          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1037  namespace LinuxSampler { namespace gig { Line 1823  namespace LinuxSampler { namespace gig {
1823    
1824                  // command address                  // command address
1825                  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)
1826                  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
1827                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1828                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1829                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
# Line 1054  namespace LinuxSampler { namespace gig { Line 1840  namespace LinuxSampler { namespace gig {
1840                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1841                              uint8_t checksum;                              uint8_t checksum;
1842                              if (!reader.pop(&checksum)) goto free_sysex_data;                              if (!reader.pop(&checksum)) goto free_sysex_data;
1843                              // some are not sending a GS checksum, so we ignore it for now                              #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1844                              //if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;                              if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1845                                #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1846                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1847                              AdjustScale((int8_t*) scale_tunes);                              AdjustScale((int8_t*) scale_tunes);
1848                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
# Line 1083  namespace LinuxSampler { namespace gig { Line 1870  namespace LinuxSampler { namespace gig {
1870       *                     question       *                     question
1871       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1872       */       */
1873      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) {
1874          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1875          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1876          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1877          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1143  namespace LinuxSampler { namespace gig { Line 1930  namespace LinuxSampler { namespace gig {
1930              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
1931              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
1932                  itVoice->Kill(itKillEvent);                  itVoice->Kill(itKillEvent);
1933                    --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1934              }              }
1935          }          }
1936      }      }
1937    
1938      /**      /**
1939       * Initialize the parameter sequence for the modulation destination given by       * Determines whether the specified voice should be released.
1940       * by 'dst' with the constant value given by val.       *
1941         * @param pEngineChannel - The engine channel on which the voice should be checked
1942         * @param Key - The key number
1943         * @returns true if the specified should be released, false otherwise.
1944       */       */
1945      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
1946          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          if (pEngineChannel->SustainPedal) return false;
1947          float* m = &pSynthesisParameters[dst][0];  
1948          for (int i = 0; i < maxsamples; i += 4) {          if (pEngineChannel->SostenutoPedal) {
1949             m[i]   = val;              for (int i = 0; i < SostenutoKeyCount; i++)
1950             m[i+1] = val;                  if (Key == SostenutoKeys[i]) return false;
            m[i+2] = val;  
            m[i+3] = val;  
1951          }          }
1952    
1953            return true;
1954      }      }
1955    
1956      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
# Line 1195  namespace LinuxSampler { namespace gig { Line 1986  namespace LinuxSampler { namespace gig {
1986      }      }
1987    
1988      String Engine::Description() {      String Engine::Description() {
1989          return "Gigasampler Engine";          return "Gigasampler Format Engine";
1990      }      }
1991    
1992      String Engine::Version() {      String Engine::Version() {
1993          String s = "$Revision: 1.36 $";          String s = "$Revision: 1.87 $";
1994          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
1995      }      }
1996    
1997        InstrumentManager* Engine::GetInstrumentManager() {
1998            return &instruments;
1999        }
2000    
2001        // static constant initializers
2002        const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2003        const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2004        const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2005    
2006        float* Engine::InitVolumeCurve() {
2007            // line-segment approximation
2008            const float segments[] = {
2009                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2010                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2011            };
2012            return InitCurve(segments);
2013        }
2014    
2015        float* Engine::InitPanCurve() {
2016            // line-segment approximation
2017            const float segments[] = {
2018                0, 0, 1, 0,
2019                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2020                127, 1.41, 128, 1.41
2021            };
2022            return InitCurve(segments, 129);
2023        }
2024    
2025        float* Engine::InitCrossfadeCurve() {
2026            // line-segment approximation
2027            const float segments[] = {
2028                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2029            };
2030            return InitCurve(segments);
2031        }
2032    
2033        float* Engine::InitCurve(const float* segments, int size) {
2034            float* y = new float[size];
2035            for (int x = 0 ; x < size ; x++) {
2036                if (x > segments[2]) segments += 2;
2037                y[x] = segments[1] + (x - segments[0]) *
2038                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
2039            }
2040            return y;
2041        }
2042    
2043  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

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

  ViewVC Help
Powered by ViewVC