/[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 376 by senkov, Sat Feb 12 23:48:50 2005 UTC revision 1800 by schoenebeck, Sun Dec 7 01:26:46 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-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 24  Line 25 
25  #include "DiskThread.h"  #include "DiskThread.h"
26  #include "Voice.h"  #include "Voice.h"
27  #include "EGADSR.h"  #include "EGADSR.h"
28    #include "../EngineFactory.h"
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    
36      InstrumentResourceManager Engine::Instruments;      InstrumentResourceManager Engine::instruments;
37    
38      Engine::Engine() {      std::map<AudioOutputDevice*,Engine*> Engine::engines;
39          pRIFF              = NULL;  
40          pGig               = NULL;      /**
41          pInstrument        = NULL;       * Get a gig::Engine object for the given gig::EngineChannel and the
42         * given AudioOutputDevice. All engine channels which are connected to
43         * the same audio output device will use the same engine instance. This
44         * method will be called by a gig::EngineChannel whenever it's
45         * connecting to a audio output device.
46         *
47         * @param pChannel - engine channel which acquires an engine object
48         * @param pDevice  - the audio output device \a pChannel is connected to
49         */
50        Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
51            Engine* pEngine = NULL;
52            // check if there's already an engine for the given audio output device
53            if (engines.count(pDevice)) {
54                dmsg(4,("Using existing gig::Engine.\n"));
55                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
62                dmsg(4,("Creating new gig::Engine.\n"));
63                pEngine = (Engine*) EngineFactory::Create("gig");
64                pEngine->Connect(pDevice);
65                engines[pDevice] = pEngine;
66            }
67            // register engine channel to the engine instance
68            pEngine->engineChannels.add(pChannel);
69            // remember index in the ArrayList
70            pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
71            dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
72            return pEngine;
73        }
74    
75        /**
76         * Once an engine channel is disconnected from an audio output device,
77         * 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
79         * engine channel anymore, then that engine instance will be destroyed.
80         *
81         * @param pChannel - engine channel which wants to disconnect from it's
82         *                   engine instance
83         * @param pDevice  - audio output device \a pChannel was connected to
84         */
85        void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
86            dmsg(4,("Disconnecting EngineChannel from gig::Engine.\n"));
87            Engine* pEngine = engines[pDevice];
88            // unregister EngineChannel from the Engine instance
89            pEngine->engineChannels.remove(pChannel);
90            // if the used Engine instance is not used anymore, then destroy it
91            if (pEngine->engineChannels.empty()) {
92                pDevice->Disconnect(pEngine);
93                engines.erase(pDevice);
94                delete pEngine;
95                dmsg(4,("Destroying gig::Engine.\n"));
96            }
97            else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
98        }
99    
100        /**
101         * Constructor
102         */
103        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>(GLOBAL_MAX_VOICES);
111          pActiveKeys        = new Pool<uint>(128);          pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
112            pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pEvents            = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
115          pCCEvents          = new RTList<Event>(pEventPool);          iMaxDiskStreams    = GLOBAL_MAX_STREAMS;
116          for (uint i = 0; i < Event::destination_count; i++) {  
             pSynthesisEvents[i] = new RTList<Event>(pEventPool);  
         }  
         for (uint i = 0; i < 128; i++) {  
             pMIDIKeyInfo[i].pActiveVoices  = new RTList<Voice>(pVoicePool);  
             pMIDIKeyInfo[i].KeyPressed     = false;  
             pMIDIKeyInfo[i].Active         = false;  
             pMIDIKeyInfo[i].ReleaseTrigger = false;  
             pMIDIKeyInfo[i].pEvents        = new RTList<Event>(pEventPool);  
         }  
117          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()) {
118              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
119          }          }
120          pVoicePool->clear();          pVoicePool->clear();
121    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
         InstrumentIdx = -1;  
         InstrumentStat = -1;  
   
         AudioDeviceChannelLeft  = -1;  
         AudioDeviceChannelRight = -1;  
   
122          ResetInternal();          ResetInternal();
123            ResetScaleTuning();
124            ResetSuspendedRegions();
125      }      }
126    
127        /**
128         * Destructor
129         */
130      Engine::~Engine() {      Engine::~Engine() {
131            MidiInputPort::RemoveSysexListener(this);
132          if (pDiskThread) {          if (pDiskThread) {
133              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
134              pDiskThread->StopThread();              pDiskThread->StopThread();
135              delete pDiskThread;              delete pDiskThread;
136              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
137          }          }
   
         if (pInstrument) Instruments.HandBack(pInstrument, this);  
   
         if (pGig)  delete pGig;  
         if (pRIFF) delete pRIFF;  
         for (uint i = 0; i < 128; i++) {  
             if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices;  
             if (pMIDIKeyInfo[i].pEvents)       delete pMIDIKeyInfo[i].pEvents;  
         }  
         for (uint i = 0; i < Event::destination_count; i++) {  
             if (pSynthesisEvents[i]) delete pSynthesisEvents[i];  
         }  
         if (pEvents)     delete pEvents;  
         if (pCCEvents)   delete pCCEvents;  
138          if (pEventQueue) delete pEventQueue;          if (pEventQueue) delete pEventQueue;
139          if (pEventPool)  delete pEventPool;          if (pEventPool)  delete pEventPool;
140          if (pVoicePool) {          if (pVoicePool) {
141                  pVoicePool->clear();              pVoicePool->clear();
142                  delete pVoicePool;              delete pVoicePool;
143          }          }
         if (pActiveKeys) delete pActiveKeys;  
         if (pSysexBuffer) delete pSysexBuffer;  
144          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
145          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
146            if (pSysexBuffer) delete pSysexBuffer;
147            if (pGlobalEvents) delete pGlobalEvents;
148            if (pDimRegionPool[0]) delete pDimRegionPool[0];
149            if (pDimRegionPool[1]) delete pDimRegionPool[1];
150            ResetSuspendedRegions();
151            Unregister();
152      }      }
153    
154      void Engine::Enable() {      void Engine::Enable() {
# Line 122  namespace LinuxSampler { namespace gig { Line 157  namespace LinuxSampler { namespace gig {
157          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
158      }      }
159    
160        /**
161         * Temporarily stop the engine to not do anything. The engine will just be
162         * frozen during that time, that means after enabling it again it will
163         * continue where it was, with all its voices and playback state it had at
164         * the point of disabling. Notice that the engine's (audio) thread will
165         * continue to run, it just remains in an inactive loop during that time.
166         *
167         * If you need to be sure that all voices and disk streams are killed as
168         * well, use @c SuspendAll() instead.
169         *
170         * @see Enable(), SuspendAll()
171         */
172      void Engine::Disable() {      void Engine::Disable() {
173          dmsg(3,("gig::Engine: disabling\n"));          dmsg(3,("gig::Engine: disabling\n"));
174          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
# Line 135  namespace LinuxSampler { namespace gig { Line 182  namespace LinuxSampler { namespace gig {
182      }      }
183    
184      /**      /**
185       *  Reset all voices and disk thread and clear input event queue and all       * Similar to @c Disable() but this method additionally kills all voices
186       *  control and status variables.       * and disk streams and blocks until all voices and disk streams are actually
187         * killed / deleted.
188         *
189         * @e Note: only the original calling thread is able to re-enable the
190         * engine afterwards by calling @c ResumeAll() later on!
191       */       */
192      void Engine::Reset() {      void Engine::SuspendAll() {
193            dmsg(2,("gig::Engine: Suspending all ...\n"));
194            // stop the engine, so we can safely modify the engine's
195            // data structures from this foreign thread
196          DisableAndLock();          DisableAndLock();
197            // we could also use the respective class member variable here,
198            // but this is probably safer and cleaner
199            int iPendingStreamDeletions = 0;
200            // kill all voices on all engine channels the *die hard* way
201            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
202                EngineChannel* pEngineChannel = engineChannels[iChannel];
203                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
204                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
205                for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
206                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
207                    RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
208                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
209                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
210                        // request a notification from disk thread side for stream deletion
211                        const Stream::Handle hStream = itVoice->KillImmediately(true);
212                        if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
213                            iPendingStreamDeletions++;
214                        }
215                    }
216                }
217            }
218            // wait until all streams were actually deleted by the disk thread
219            while (iPendingStreamDeletions) {
220                while (
221                    iPendingStreamDeletions &&
222                    pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
223                ) iPendingStreamDeletions--;
224                if (!iPendingStreamDeletions) break;
225                usleep(10000); // sleep for 10ms
226            }
227            dmsg(2,("gig::Engine: Everything suspended.\n"));
228        }
229    
230          //if (pAudioOutputDevice->IsPlaying()) { // if already running      /**
231              /*       * At the moment same as calling @c Enable() directly, but this might
232              // signal audio thread not to enter render part anymore       * change in future, so better call this method as counterpart to
233              SuspensionRequested = true;       * @c SuspendAll() instead of @c Enable() !
234              // sleep until wakened by audio thread       */
235              pthread_mutex_lock(&__render_state_mutex);      void Engine::ResumeAll() {
236              pthread_cond_wait(&__render_exit_condition, &__render_state_mutex);          Enable();
237              pthread_mutex_unlock(&__render_state_mutex);      }
             */  
         //}  
238    
239          //if (wasplaying) pAudioOutputDevice->Stop();      /**
240         * Order the engine to stop rendering audio for the given region.
241         * Additionally this method will block until all voices and their disk
242         * streams associated with that region are actually killed / deleted, so
243         * one can i.e. safely modify the region with an instrument editor after
244         * returning from this method.
245         *
246         * @param pRegion - region the engine shall stop using
247         */
248        void Engine::Suspend(::gig::Region* pRegion) {
249            dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
250            SuspendedRegionsMutex.Lock();
251            SuspensionChangeOngoing.Set(true);
252            pPendingRegionSuspension = pRegion;
253            SuspensionChangeOngoing.WaitAndUnlockIf(true);
254            SuspendedRegionsMutex.Unlock();
255            dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
256        }
257    
258          ResetInternal();      /**
259         * Orders the engine to resume playing back the given region, previously
260         * suspended with @c Suspend() .
261         *
262         * @param pRegion - region the engine shall be allowed to use again
263         */
264        void Engine::Resume(::gig::Region* pRegion) {
265            dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
266            SuspendedRegionsMutex.Lock();
267            SuspensionChangeOngoing.Set(true);
268            pPendingRegionResumption = pRegion;
269            SuspensionChangeOngoing.WaitAndUnlockIf(true);
270            SuspendedRegionsMutex.Unlock();
271            dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
272        }
273    
274          // signal audio thread to continue with rendering      /**
275          //SuspensionRequested = false;       *  Reset all voices and disk thread and clear input event queue and all
276         *  control and status variables.
277         */
278        void Engine::Reset() {
279            DisableAndLock();
280            ResetInternal();
281            ResetScaleTuning();
282          Enable();          Enable();
283      }      }
284    
285      /**      /**
286       *  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
287       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
288       */       */
289      void Engine::ResetInternal() {      void Engine::ResetInternal() {
290          Pitch               = 0;          ResetInternalMutex.Lock();
291          SustainPedal        = false;  
292          ActiveVoiceCount    = 0;          // make sure that the engine does not get any sysex messages
293            // while it's reseting
294            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
295            SetVoiceCount(0);
296          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
         GlobalVolume        = 1.0;  
         CurrentKeyDimension = 0;  
297    
298          // reset voice stealing parameters          // reset voice stealing parameters
         itLastStolenVoice = RTList<Voice>::Iterator();  
         iuiLastStolenKey  = RTList<uint>::Iterator();  
299          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
300            itLastStolenVoice          = RTList<Voice>::Iterator();
301          // reset to normal chromatic scale (means equal temper)          itLastStolenVoiceGlobally  = RTList<Voice>::Iterator();
302          memset(&ScaleTuning[0], 0x00, 12);          iuiLastStolenKey           = RTList<uint>::Iterator();
303            iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
304          // set all MIDI controller values to zero          pLastStolenChannel         = NULL;
         memset(ControllerTable, 0x00, 128);  
   
         // reset key info  
         for (uint i = 0; i < 128; i++) {  
             pMIDIKeyInfo[i].pActiveVoices->clear();  
             pMIDIKeyInfo[i].pEvents->clear();  
             pMIDIKeyInfo[i].KeyPressed     = false;  
             pMIDIKeyInfo[i].Active         = false;  
             pMIDIKeyInfo[i].ReleaseTrigger = false;  
             pMIDIKeyInfo[i].itSelf         = Pool<uint>::Iterator();  
         }  
   
         // reset all key groups  
         map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();  
         for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;  
305    
306          // reset all voices          // reset all voices
307          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 204  namespace LinuxSampler { namespace gig { Line 309  namespace LinuxSampler { namespace gig {
309          }          }
310          pVoicePool->clear();          pVoicePool->clear();
311    
         // free all active keys  
         pActiveKeys->clear();  
   
312          // reset disk thread          // reset disk thread
313          if (pDiskThread) pDiskThread->Reset();          if (pDiskThread) pDiskThread->Reset();
314    
315          // delete all input events          // delete all input events
316          pEventQueue->init();          pEventQueue->init();
317            pSysexBuffer->init();
318            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
319            ResetInternalMutex.Unlock();
320      }      }
321    
322      /**      /**
323       *  Load an instrument from a .gig file.       * Reset to normal, chromatic scale (means equal tempered).
      *  
      *  @param FileName   - file name of the Gigasampler instrument file  
      *  @param Instrument - index of the instrument in the .gig file  
      *  @throws LinuxSamplerException  on error  
      *  @returns          detailed description of the method call result  
324       */       */
325      void Engine::LoadInstrument(const char* FileName, uint Instrument) {      void Engine::ResetScaleTuning() {
326            memset(&ScaleTuning[0], 0x00, 12);
         DisableAndLock();  
   
         ResetInternal(); // reset engine  
   
         // free old instrument  
         if (pInstrument) {  
             // give old instrument back to instrument manager  
             Instruments.HandBack(pInstrument, this);  
         }  
   
         InstrumentFile = FileName;  
         InstrumentIdx = Instrument;  
         InstrumentStat = 0;  
   
         // delete all key groups  
         ActiveKeyGroups.clear();  
   
         // request gig instrument from instrument manager  
         try {  
             instrument_id_t instrid;  
             instrid.FileName    = FileName;  
             instrid.iInstrument = Instrument;  
             pInstrument = Instruments.Borrow(instrid, this);  
             if (!pInstrument) {  
                 InstrumentStat = -1;  
                 dmsg(1,("no instrument loaded!!!\n"));  
                 exit(EXIT_FAILURE);  
             }  
         }  
         catch (RIFF::Exception e) {  
             InstrumentStat = -2;  
             String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message;  
             throw LinuxSamplerException(msg);  
         }  
         catch (InstrumentResourceManagerException e) {  
             InstrumentStat = -3;  
             String msg = "gig::Engine error: Failed to load instrument, cause: " + e.Message();  
             throw LinuxSamplerException(msg);  
         }  
         catch (...) {  
             InstrumentStat = -4;  
             throw LinuxSamplerException("gig::Engine error: Failed to load instrument, cause: Unknown exception while trying to parse gig file.");  
         }  
   
         // rebuild ActiveKeyGroups map with key groups of current instrument  
         for (::gig::Region* pRegion = pInstrument->GetFirstRegion(); pRegion; pRegion = pInstrument->GetNextRegion())  
             if (pRegion->KeyGroup) ActiveKeyGroups[pRegion->KeyGroup] = NULL;  
   
         InstrumentIdxName = pInstrument->pInfo->Name;  
         InstrumentStat = 100;  
   
         // inform audio driver for the need of two channels  
         try {  
             if (pAudioOutputDevice) pAudioOutputDevice->AcquireChannels(2); // gig Engine only stereo  
         }  
         catch (AudioOutputException e) {  
             String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message();  
             throw LinuxSamplerException(msg);  
         }  
   
         Enable();  
327      }      }
328    
329      /**      void Engine::ResetSuspendedRegions() {
330       * Will be called by the InstrumentResourceManager when the instrument          SuspendedRegions.clear();
331       * we are currently using in this engine is going to be updated, so we          iPendingStreamDeletions = 0;
332       * can stop playback before that happens.          pPendingRegionSuspension = pPendingRegionResumption = NULL;
333       */          SuspensionChangeOngoing.Set(false);
     void Engine::ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {  
         dmsg(3,("gig::Engine: Received instrument update message.\n"));  
         DisableAndLock();  
         ResetInternal();  
         this->pInstrument = NULL;  
334      }      }
335    
336      /**      /**
337       * Will be called by the InstrumentResourceManager when the instrument       * Connect this engine instance with the given audio output device.
338       * update process was completed, so we can continue with playback.       * This method will be called when an Engine instance is created.
339         * All of the engine's data structures which are dependant to the used
340         * audio output device / driver will be (re)allocated and / or
341         * adjusted appropriately.
342         *
343         * @param pAudioOut - audio output device to connect to
344       */       */
     void Engine::ResourceUpdated(::gig::Instrument* pOldResource, ::gig::Instrument* pNewResource, void* pUpdateArg) {  
         this->pInstrument = pNewResource; //TODO: there are couple of engine parameters we should update here as well if the instrument was updated (see LoadInstrument())  
         Enable();  
     }  
   
345      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
346            // caution: don't ignore if connecting to the same device here,
347            // because otherwise SetMaxDiskStreams() implementation won't work anymore!
348    
349          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
350    
351          ResetInternal();          ResetInternal();
# Line 319  namespace LinuxSampler { namespace gig { Line 356  namespace LinuxSampler { namespace gig {
356          }          }
357          catch (AudioOutputException e) {          catch (AudioOutputException e) {
358              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();
359              throw LinuxSamplerException(msg);              throw Exception(msg);
360          }          }
361    
362          this->AudioDeviceChannelLeft  = 0;          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
363          this->AudioDeviceChannelRight = 1;          this->SampleRate         = pAudioOutputDevice->SampleRate();
364          this->pOutputLeft             = pAudioOutputDevice->Channel(0)->Buffer();  
365          this->pOutputRight            = pAudioOutputDevice->Channel(1)->Buffer();          MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
366          this->MaxSamplesPerCycle      = pAudioOutputDevice->MaxSamplesPerCycle();          if (MaxSamplesPerCycle < MinFadeOutSamples) {
367          this->SampleRate              = pAudioOutputDevice->SampleRate();              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
368                          << "too big for current audio fragment size & sampling rate! "
369          // FIXME: audio drivers with varying fragment sizes might be a problem here                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
370          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * EG_MIN_RELEASE_TIME) - 1;              // force volume ramp downs at the beginning of each fragment
371          if (MaxFadeOutPos < 0)              MinFadeOutSamples = MaxSamplesPerCycle;
372              throw LinuxSamplerException("EG_MIN_RELEASE_TIME in EGADSR.h to big for current audio fragment size / sampling rate!");              // lower minimum release time
373                const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
374                for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
375                    iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
376                }
377                pVoicePool->clear();
378            }
379    
380          // (re)create disk thread          // (re)create disk thread
381          if (this->pDiskThread) {          if (this->pDiskThread) {
# Line 341  namespace LinuxSampler { namespace gig { Line 384  namespace LinuxSampler { namespace gig {
384              delete this->pDiskThread;              delete this->pDiskThread;
385              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
386          }          }
387          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread =
388                new DiskThread(
389                    iMaxDiskStreams,
390                    ((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
391                    &instruments
392                );
393    
394          if (!pDiskThread) {          if (!pDiskThread) {
395              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
396              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 357  namespace LinuxSampler { namespace gig { Line 406  namespace LinuxSampler { namespace gig {
406          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
407          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
408    
         // (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()];  
   
409          dmsg(1,("Starting disk thread..."));          dmsg(1,("Starting disk thread..."));
410          pDiskThread->StartThread();          pDiskThread->StartThread();
411          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
# Line 384  namespace LinuxSampler { namespace gig { Line 416  namespace LinuxSampler { namespace gig {
416                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
417              }              }
418          }          }
419            pVoicePool->clear();
420        }
421    
422        /**
423         * Called by the engine's (audio) thread once per cycle to process requests
424         * from the outer world to suspend or resume a given @c gig::Region .
425         */
426        void Engine::ProcessSuspensionsChanges() {
427            // process request for suspending one region
428            if (pPendingRegionSuspension) {
429                // kill all voices on all engine channels that use this region
430                for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
431                    EngineChannel* pEngineChannel = engineChannels[iChannel];
432                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
433                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
434                    for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
435                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
436                        RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
437                        // if current key is not associated with this region, skip this key
438                        if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
439                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
440                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
441                            // request a notification from disk thread side for stream deletion
442                            const Stream::Handle hStream = itVoice->KillImmediately(true);
443                            if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
444                                iPendingStreamDeletions++;
445                            }
446                        }
447                    }
448                }
449                // make sure the region is not yet on the list
450                bool bAlreadySuspended = false;
451                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
452                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
453                for (; iter != end; ++iter) { // iterate through all suspended regions
454                    if (*iter == pPendingRegionSuspension) { // found
455                        bAlreadySuspended = true;
456                        dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
457                        break;
458                    }
459                }
460                if (!bAlreadySuspended) {
461                    // put the region on the list of suspended regions
462                    RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
463                    if (iter) {
464                        *iter = pPendingRegionSuspension;
465                    } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
466                }
467                // free request slot for next caller (and to make sure that
468                // we're not going to process the same request in the next cycle)
469                pPendingRegionSuspension = NULL;
470                // if no disk stream deletions are pending, awaken other side, as
471                // we're done in this case
472                if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
473            }
474    
475            // process request for resuming one region
476            if (pPendingRegionResumption) {
477                // remove region from the list of suspended regions
478                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
479                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
480                for (; iter != end; ++iter) { // iterate through all suspended regions
481                    if (*iter == pPendingRegionResumption) { // found
482                        SuspendedRegions.free(iter);
483                        break; // done
484                    }
485                }
486                // free request slot for next caller
487                pPendingRegionResumption = NULL;
488                // awake other side as we're done
489                SuspensionChangeOngoing.Set(false);
490            }
491        }
492    
493        /**
494         * Called by the engine's (audio) thread once per cycle to check if
495         * streams of voices that were killed due to suspension request have
496         * finally really been deleted by the disk thread.
497         */
498        void Engine::ProcessPendingStreamDeletions() {
499            if (!iPendingStreamDeletions) return;
500            //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
501            while (
502                iPendingStreamDeletions &&
503                pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
504            ) iPendingStreamDeletions--;
505            // just for safety ...
506            while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
507            // now that all disk streams are deleted, awake other side as
508            // we're finally done with suspending the requested region
509            if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
510        }
511    
512        /**
513         * Returns @c true if the given region is currently set to be suspended
514         * from being used, @c false otherwise.
515         */
516        bool Engine::RegionSuspended(::gig::Region* pRegion) {
517            if (SuspendedRegions.isEmpty()) return false;
518            //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
519            RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
520            RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
521            for (; iter != end; ++iter)  // iterate through all suspended regions
522                if (*iter == pRegion) return true;
523            return false;
524      }      }
525    
526      void Engine::DisconnectAudioOutputDevice() {      /**
527          if (pAudioOutputDevice) { // if clause to prevent disconnect loops       * Clear all engine global event lists.
528              AudioOutputDevice* olddevice = pAudioOutputDevice;       */
529              pAudioOutputDevice = NULL;      void Engine::ClearEventLists() {
530              olddevice->Disconnect(this);          pGlobalEvents->clear();
531              AudioDeviceChannelLeft  = -1;      }
532              AudioDeviceChannelRight = -1;  
533        /**
534         * Copy all events from the engine's global input queue buffer to the
535         * engine's internal event list. This will be done at the beginning of
536         * each audio cycle (that is each RenderAudio() call) to distinguish
537         * all global events which have to be processed in the current audio
538         * cycle. These events are usually just SysEx messages. Every
539         * EngineChannel has it's own input event queue buffer and event list
540         * to handle common events like NoteOn, NoteOff and ControlChange
541         * events.
542         *
543         * @param Samples - number of sample points to be processed in the
544         *                  current audio cycle
545         */
546        void Engine::ImportEvents(uint Samples) {
547            RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
548            Event* pEvent;
549            while (true) {
550                // get next event from input event queue
551                if (!(pEvent = eventQueueReader.pop())) break;
552                // if younger event reached, ignore that and all subsequent ones for now
553                if (pEvent->FragmentPos() >= Samples) {
554                    eventQueueReader--;
555                    dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
556                    pEvent->ResetFragmentPos();
557                    break;
558                }
559                // copy event to internal event list
560                if (pGlobalEvents->poolIsEmpty()) {
561                    dmsg(1,("Event pool emtpy!\n"));
562                    break;
563                }
564                *pGlobalEvents->allocAppend() = *pEvent;
565          }          }
566            eventQueueReader.free(); // free all copied events from input queue
567      }      }
568    
569      /**      /**
570       *  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.
571       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
572       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
573       *  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
574       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
575         * respective engine channel.
576       *       *
577       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
578       *  @returns       0 on success       *  @returns       0 on success
579       */       */
580      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
581          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
582    
583          // return if no instrument loaded or engine disabled          // return if engine disabled
584          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
585              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
586              return 0;              EngineDisabled.RttDone();
         }  
         if (!pInstrument) {  
             dmsg(5,("gig::Engine: no instrument loaded\n"));  
587              return 0;              return 0;
588          }          }
589    
590            // process requests for suspending / resuming regions (i.e. to avoid
591            // crashes while these regions are modified by an instrument editor)
592            ProcessSuspensionsChanges();
593    
594          // 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)
595          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
596    
597            // We only allow the given maximum number of voices to be spawned
598            // in each audio fragment. All subsequent request for spawning new
599            // voices in the same audio fragment will be ignored.
600            VoiceSpawnsLeft = MaxVoices();
601    
602            // get all events from the engine's global input event queue which belong to the current fragment
603            // (these are usually just SysEx messages)
604            ImportEvents(Samples);
605    
606          // empty the event lists for the new fragment          // process engine global events (these are currently only MIDI System Exclusive messages)
         pEvents->clear();  
         pCCEvents->clear();  
         for (uint i = 0; i < Event::destination_count; i++) {  
             pSynthesisEvents[i]->clear();  
         }  
607          {          {
608              RTList<uint>::Iterator iuiKey = pActiveKeys->first();              RTList<Event>::Iterator itEvent = pGlobalEvents->first();
609              RTList<uint>::Iterator end    = pActiveKeys->end();              RTList<Event>::Iterator end     = pGlobalEvents->end();
610              for(; iuiKey != end; ++iuiKey) {              for (; itEvent != end; ++itEvent) {
611                  pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key                  switch (itEvent->Type) {
612                        case Event::type_sysex:
613                            dmsg(5,("Engine: Sysex received\n"));
614                            ProcessSysex(itEvent);
615                            break;
616                    }
617              }              }
618          }          }
619    
620            // reset internal voice counter (just for statistic of active voices)
621            ActiveVoiceCountTemp = 0;
622    
623          // get all events from the input event queue which belong to the current fragment          // handle instrument change commands
624          {          bool instrumentChanged = false;
625              RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          for (int i = 0; i < engineChannels.size(); i++) {
626              Event* pEvent;              EngineChannel* pEngineChannel = engineChannels[i];
627              while (true) {  
628                  // get next event from input event queue              // as we're going to (carefully) write some status to the
629                  if (!(pEvent = eventQueueReader.pop())) break;              // synchronized struct, we cast away the const
630                  // if younger event reached, ignore that and all subsequent ones for now              EngineChannel::instrument_change_command_t& cmd =
631                  if (pEvent->FragmentPos() >= Samples) {                  const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
632                      eventQueueReader--;  
633                      dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));              pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
634                      pEvent->ResetFragmentPos();              pEngineChannel->pDimRegionsInUse->clear();
635                      break;  
636                  }              if (cmd.bChangeInstrument) {
637                  // copy event to internal event list                  // change instrument
638                  if (pEvents->poolIsEmpty()) {                  dmsg(5,("Engine: instrument change command received\n"));
639                      dmsg(1,("Event pool emtpy!\n"));                  cmd.bChangeInstrument = false;
640                      break;                  pEngineChannel->pInstrument = cmd.pInstrument;
641                    instrumentChanged = true;
642    
643                    // Iterate through all active voices and mark them as
644                    // "orphans", which means that the dimension regions
645                    // and samples they use should be released to the
646                    // instrument resource manager when the voices die.
647                    int i = 0;
648                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
649                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
650                    while (iuiKey != end) { // iterate through all active keys
651                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
652                        ++iuiKey;
653    
654                        RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
655                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
656                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
657                            itVoice->Orphan = true;
658                        }
659                  }                  }
                 *pEvents->allocAppend() = *pEvent;  
660              }              }
661              eventQueueReader.free(); // free all copied events from input queue          }
662            if (instrumentChanged) {
663                //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
664                ResetSuspendedRegions();
665            }
666    
667            // handle events on all engine channels
668            for (int i = 0; i < engineChannels.size(); i++) {
669                ProcessEvents(engineChannels[i], Samples);
670            }
671    
672            // render all 'normal', active voices on all engine channels
673            for (int i = 0; i < engineChannels.size(); i++) {
674                RenderActiveVoices(engineChannels[i], Samples);
675            }
676    
677            // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
678            RenderStolenVoices(Samples);
679    
680            // handle audio routing for engine channels with FX sends
681            for (int i = 0; i < engineChannels.size(); i++) {
682                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
683                RouteAudio(engineChannels[i], Samples);
684            }
685    
686            // handle cleanup on all engine channels for the next audio fragment
687            for (int i = 0; i < engineChannels.size(); i++) {
688                PostProcess(engineChannels[i]);
689          }          }
690    
691    
692            // empty the engine's event list for the next audio fragment
693            ClearEventLists();
694    
695            // reset voice stealing for the next audio fragment
696            pVoiceStealingQueue->clear();
697    
698            // just some statistics about this engine instance
699            SetVoiceCount(ActiveVoiceCountTemp);
700            if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
701    
702            // in case regions were previously suspended and we killed voices
703            // with disk streams due to that, check if those streams have finally
704            // been deleted by the disk thread
705            if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
706    
707            for (int i = 0; i < engineChannels.size(); i++) {
708                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
709            }
710            FrameTime += Samples;
711    
712            EngineDisabled.RttDone();
713            return 0;
714        }
715    
716        /**
717         * Dispatch and handle all events in this audio fragment for the given
718         * engine channel.
719         *
720         * @param pEngineChannel - engine channel on which events should be
721         *                         processed
722         * @param Samples        - amount of sample points to be processed in
723         *                         this audio fragment cycle
724         */
725        void Engine::ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
726            // get all events from the engine channels's input event queue which belong to the current fragment
727            // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
728            pEngineChannel->ImportEvents(Samples);
729    
730          // process events          // process events
731          {          {
732              RTList<Event>::Iterator itEvent = pEvents->first();              RTList<Event>::Iterator itEvent = pEngineChannel->pEvents->first();
733              RTList<Event>::Iterator end     = pEvents->end();              RTList<Event>::Iterator end     = pEngineChannel->pEvents->end();
734              for (; itEvent != end; ++itEvent) {              for (; itEvent != end; ++itEvent) {
735                  switch (itEvent->Type) {                  switch (itEvent->Type) {
736                      case Event::type_note_on:                      case Event::type_note_on:
737                          dmsg(5,("Engine: Note on received\n"));                          dmsg(5,("Engine: Note on received\n"));
738                          ProcessNoteOn(itEvent);                          ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
739                          break;                          break;
740                      case Event::type_note_off:                      case Event::type_note_off:
741                          dmsg(5,("Engine: Note off received\n"));                          dmsg(5,("Engine: Note off received\n"));
742                          ProcessNoteOff(itEvent);                          ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
743                          break;                          break;
744                      case Event::type_control_change:                      case Event::type_control_change:
745                          dmsg(5,("Engine: MIDI CC received\n"));                          dmsg(5,("Engine: MIDI CC received\n"));
746                          ProcessControlChange(itEvent);                          ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
747                          break;                          break;
748                      case Event::type_pitchbend:                      case Event::type_pitchbend:
749                          dmsg(5,("Engine: Pitchbend received\n"));                          dmsg(5,("Engine: Pitchbend received\n"));
750                          ProcessPitchbend(itEvent);                          ProcessPitchbend((EngineChannel*)itEvent->pEngineChannel, itEvent);
                         break;  
                     case Event::type_sysex:  
                         dmsg(5,("Engine: Sysex received\n"));  
                         ProcessSysex(itEvent);  
751                          break;                          break;
752                  }                  }
753              }              }
754          }          }
755    
756            // reset voice stealing for the next engine channel (or next audio fragment)
757            itLastStolenVoice         = RTList<Voice>::Iterator();
758            itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
759            iuiLastStolenKey          = RTList<uint>::Iterator();
760            iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
761            pLastStolenChannel        = NULL;
762        }
763    
764          int active_voices = 0;      /**
765         * Render all 'normal' voices (that is voices which were not stolen in
766         * this fragment) on the given engine channel.
767         *
768         * @param pEngineChannel - engine channel on which audio should be
769         *                         rendered
770         * @param Samples        - amount of sample points to be rendered in
771         *                         this audio fragment cycle
772         */
773        void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
774            #if !CONFIG_PROCESS_MUTED_CHANNELS
775            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
776            #endif
777    
778          // render audio from all active voices          uint voiceCount = 0;
779          {          uint streamCount = 0;
780              RTList<uint>::Iterator iuiKey = pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
781              RTList<uint>::Iterator end    = pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
782              while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
783                  midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
784                  ++iuiKey;              ++iuiKey;
785    
786                RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
787                RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
788                for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
789                    // now render current voice
790                    itVoice->Render(Samples);
791                    if (itVoice->IsActive()) { // still active
792                        if (!itVoice->Orphan) {
793                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
794                        }
795                        ActiveVoiceCountTemp++;
796                        voiceCount++;
797    
798                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      if (itVoice->PlaybackState == Voice::playback_state_disk) {
799                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                          if ((itVoice->DiskStreamRef).State != Stream::state_unused) streamCount++;
                 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key  
                     // now render current voice  
                     itVoice->Render(Samples);  
                     if (itVoice->IsActive()) active_voices++; // still active  
                     else { // voice reached end, is now inactive  
                         FreeVoice(itVoice); // remove voice from the list of active voices  
800                      }                      }
801                    }  else { // voice reached end, is now inactive
802                        FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
803                  }                  }
804              }              }
805          }          }
806    
807            pEngineChannel->SetVoiceCount(voiceCount);
808            pEngineChannel->SetDiskStreamCount(streamCount);
809        }
810    
811          // now render all postponed voices from voice stealing      /**
812          {       * Render all stolen voices (only voices which were stolen in this
813              RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();       * fragment) on the given engine channel. Stolen voices are rendered
814              RTList<Event>::Iterator end               = pVoiceStealingQueue->end();       * after all normal voices have been rendered; this is needed to render
815              for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {       * audio of those voices which were selected for voice stealing until
816                  Pool<Voice>::Iterator itNewVoice = LaunchVoice(itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false);       * the point were the stealing (that is the take over of the voice)
817                  if (itNewVoice) {       * actually happened.
818                      for (; itNewVoice; itNewVoice = itNewVoice->itChildVoice) {       *
819                          itNewVoice->Render(Samples);       * @param pEngineChannel - engine channel on which audio should be
820                          if (itNewVoice->IsActive()) active_voices++; // still active       *                         rendered
821                          else { // voice reached end, is now inactive       * @param Samples        - amount of sample points to be rendered in
822                              FreeVoice(itNewVoice); // remove voice from the list of active voices       *                         this audio fragment cycle
823         */
824        void Engine::RenderStolenVoices(uint Samples) {
825            RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
826            RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
827            for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
828                EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
829                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
830                Pool<Voice>::Iterator itNewVoice =
831                    LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
832                if (itNewVoice) {
833                    itNewVoice->Render(Samples);
834                    if (itNewVoice->IsActive()) { // still active
835                        *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
836                        ActiveVoiceCountTemp++;
837                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
838    
839                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
840                            if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
841                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
842                          }                          }
843                      }                      }
844                    } else { // voice reached end, is now inactive
845                        FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
846                  }                  }
                 else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));  
847              }              }
848                else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));
849    
850                // we need to clear the key's event list explicitly here in case key was never active
851                midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
852                pKey->VoiceTheftsQueued--;
853                if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
854          }          }
855          // reset voice stealing for the new fragment      }
         pVoiceStealingQueue->clear();  
         itLastStolenVoice = RTList<Voice>::Iterator();  
         iuiLastStolenKey  = RTList<uint>::Iterator();  
856    
857        /**
858         * Will be called in case the respective engine channel sports FX send
859         * channels. In this particular case, engine channel local buffers are
860         * used to render and mix all voices to. This method is responsible for
861         * copying the audio data from those local buffers to the master audio
862         * output channels as well as to the FX send audio output channels with
863         * their respective FX send levels.
864         *
865         * @param pEngineChannel - engine channel from which audio should be
866         *                         routed
867         * @param Samples        - amount of sample points to be routed in
868         *                         this audio fragment cycle
869         */
870        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
871            // route dry signal
872            {
873                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
874                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
875                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
876                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
877            }
878            // route FX send signal
879            {
880                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
881                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
882                    for (int iChan = 0; iChan < 2; ++iChan) {
883                        AudioChannel* pSource =
884                            (iChan)
885                                ? pEngineChannel->pChannelRight
886                                : pEngineChannel->pChannelLeft;
887                        const int iDstChan = pFxSend->DestinationChannel(iChan);
888                        if (iDstChan < 0) {
889                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
890                            goto channel_cleanup;
891                        }
892                        AudioChannel* pDstChan = NULL;
893                        if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
894                            EffectChain* pEffectChain =
895                                pAudioOutputDevice->MasterEffectChain(
896                                    pFxSend->DestinationMasterEffectChain()
897                                );
898                            if (!pEffectChain) {
899                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
900                                goto channel_cleanup;
901                            }
902                            Effect* pEffect =
903                                pEffectChain->GetEffect(
904                                    pFxSend->DestinationMasterEffect()
905                                );
906                            if (!pEffect) {
907                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
908                                goto channel_cleanup;
909                            }
910                            pDstChan = pEffect->InputChannel(iDstChan);
911                        } else { // FX send routed directly to an audio output channel
912                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
913                        }
914                        if (!pDstChan) {
915                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
916                            goto channel_cleanup;
917                        }
918                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
919                    }
920                }
921            }
922            channel_cleanup:
923            // reset buffers with silence (zero out) for the next audio cycle
924            pEngineChannel->pChannelLeft->Clear();
925            pEngineChannel->pChannelRight->Clear();
926        }
927    
928        /**
929         * Free all keys which have turned inactive in this audio fragment, from
930         * the list of active keys and clear all event lists on that engine
931         * channel.
932         *
933         * @param pEngineChannel - engine channel to cleanup
934         */
935        void Engine::PostProcess(EngineChannel* pEngineChannel) {
936          // free all keys which have no active voices left          // free all keys which have no active voices left
937          {          {
938              RTList<uint>::Iterator iuiKey = pActiveKeys->first();              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
939              RTList<uint>::Iterator end    = pActiveKeys->end();              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
940              while (iuiKey != end) { // iterate through all active keys              while (iuiKey != end) { // iterate through all active keys
941                  midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
942                  ++iuiKey;                  ++iuiKey;
943                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
944                  #if DEVMODE                  #if CONFIG_DEVMODE
945                  else { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)                  else { // just a sanity check for debugging
946                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
947                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
948                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
# Line 561  namespace LinuxSampler { namespace gig { Line 951  namespace LinuxSampler { namespace gig {
951                          }                          }
952                      }                      }
953                  }                  }
954                  #endif // DEVMODE                  #endif // CONFIG_DEVMODE
955              }              }
956          }          }
957    
958            // empty the engine channel's own event lists
959          // write that to the disk thread class so that it can print it          pEngineChannel->ClearEventLists();
         // on the console for debugging purposes  
         ActiveVoiceCount = active_voices;  
         if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;  
   
   
         return 0;  
     }  
   
     /**  
      *  Will be called by the MIDIIn Thread to let the audio thread trigger a new  
      *  voice for the given key.  
      *  
      *  @param Key      - MIDI key number of the triggered key  
      *  @param Velocity - MIDI velocity value of the triggered key  
      */  
     void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {  
         Event event               = pEventGenerator->CreateEvent();  
         event.Type                = Event::type_note_on;  
         event.Param.Note.Key      = Key;  
         event.Param.Note.Velocity = Velocity;  
         if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);  
         else dmsg(1,("Engine: Input event queue full!"));  
     }  
   
     /**  
      *  Will be called by the MIDIIn Thread to signal the audio thread to release  
      *  voice(s) on the given key.  
      *  
      *  @param Key      - MIDI key number of the released key  
      *  @param Velocity - MIDI release velocity value of the released key  
      */  
     void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {  
         Event event               = pEventGenerator->CreateEvent();  
         event.Type                = Event::type_note_off;  
         event.Param.Note.Key      = Key;  
         event.Param.Note.Velocity = Velocity;  
         if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);  
         else dmsg(1,("Engine: Input event queue full!"));  
     }  
   
     /**  
      *  Will be called by the MIDIIn Thread to signal the audio thread to change  
      *  the pitch value for all voices.  
      *  
      *  @param Pitch - MIDI pitch value (-8192 ... +8191)  
      */  
     void Engine::SendPitchbend(int Pitch) {  
         Event event             = pEventGenerator->CreateEvent();  
         event.Type              = Event::type_pitchbend;  
         event.Param.Pitch.Pitch = Pitch;  
         if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);  
         else dmsg(1,("Engine: Input event queue full!"));  
     }  
   
     /**  
      *  Will be called by the MIDIIn Thread to signal the audio thread that a  
      *  continuous controller value has changed.  
      *  
      *  @param Controller - MIDI controller number of the occured control change  
      *  @param Value      - value of the control change  
      */  
     void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {  
         Event event               = pEventGenerator->CreateEvent();  
         event.Type                = Event::type_control_change;  
         event.Param.CC.Controller = Controller;  
         event.Param.CC.Value      = Value;  
         if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);  
         else dmsg(1,("Engine: Input event queue full!"));  
960      }      }
961    
962      /**      /**
# Line 643  namespace LinuxSampler { namespace gig { Line 965  namespace LinuxSampler { namespace gig {
965       *       *
966       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
967       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
968         *  @param pSender - the MIDI input port on which the SysEx message was
969         *                   received
970       */       */
971      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
972          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
973          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
974          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
975            event.pEngineChannel    = NULL; // as Engine global event
976            event.pMidiInputPort    = pSender;
977          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
978              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
979                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 663  namespace LinuxSampler { namespace gig { Line 989  namespace LinuxSampler { namespace gig {
989                  // finally place sysex event into input event queue                  // finally place sysex event into input event queue
990                  pEventQueue->push(&event);                  pEventQueue->push(&event);
991              }              }
992              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));
993          }          }
994          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
995      }      }
# Line 671  namespace LinuxSampler { namespace gig { Line 997  namespace LinuxSampler { namespace gig {
997      /**      /**
998       *  Assigns and triggers a new voice for the respective MIDI key.       *  Assigns and triggers a new voice for the respective MIDI key.
999       *       *
1000         *  @param pEngineChannel - engine channel on which this event occured on
1001       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
1002       */       */
1003      void Engine::ProcessNoteOn(Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1004            #if !CONFIG_PROCESS_MUTED_CHANNELS
1005            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1006            #endif
1007    
1008            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
1009    
1010            //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
1011            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1012    
1013          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
1014            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
1015    
1016          // Change key dimension value if key is in keyswitching area          // move note on event to the key's own event list
1017          if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)          RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
             CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /  
                 (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);  
1018    
1019          midi_key_info_t* pKey = &pMIDIKeyInfo[key];          // if Solo Mode then kill all already active voices
1020            if (pEngineChannel->SoloMode) {
1021                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
1022                if (itYoungestKey) {
1023                    const int iYoungestKey = *itYoungestKey;
1024                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
1025                    if (pOtherKey->Active) {
1026                        // get final portamento position of currently active voice
1027                        if (pEngineChannel->PortamentoMode) {
1028                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
1029                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1030                        }
1031                        // kill all voices on the (other) key
1032                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1033                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1034                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1035                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1036                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1037                        }
1038                    }
1039                }
1040                // set this key as 'currently active solo key'
1041                pEngineChannel->SoloKey = key;
1042            }
1043    
1044            // Change key dimension value if key is in keyswitching area
1045            {
1046                const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1047                if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1048                    pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1049                        (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1050            }
1051    
1052          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
1053            pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1054            pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1055    
1056          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
1057          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
1058              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1059              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
1060                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1061                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1062              }              }
1063              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
1064          }          }
1065    
1066          // move note on event to the key's own event list          // allocate and trigger new voice(s) for the key
1067          RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);          {
1068                // first, get total amount of required voices (dependant on amount of layers)
1069                ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1070                if (pRegion && !RegionSuspended(pRegion)) {
1071                    int voicesRequired = pRegion->Layers;
1072                    // now launch the required amount of voices
1073                    for (int i = 0; i < voicesRequired; i++)
1074                        LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
1075                }
1076            }
1077    
1078          // allocate and trigger a new voice for the key          // if neither a voice was spawned or postponed then remove note on event from key again
1079          LaunchVoice(itNoteOnEventOnKeyList, 0, false, true);          if (!pKey->Active && !pKey->VoiceTheftsQueued)
1080                pKey->pEvents->free(itNoteOnEventOnKeyList);
1081    
1082            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1083            pKey->RoundRobinIndex++;
1084      }      }
1085    
1086      /**      /**
# Line 709  namespace LinuxSampler { namespace gig { Line 1089  namespace LinuxSampler { namespace gig {
1089       *  sustain pedal will be released or voice turned inactive by itself (e.g.       *  sustain pedal will be released or voice turned inactive by itself (e.g.
1090       *  due to completion of sample playback).       *  due to completion of sample playback).
1091       *       *
1092         *  @param pEngineChannel - engine channel on which this event occured on
1093       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
1094       */       */
1095      void Engine::ProcessNoteOff(Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1096          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
1097            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1098            #endif
1099    
1100          pKey->KeyPressed = false; // the MIDI key was now released          //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
1101            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1102    
1103          // release voices on this key if needed          const int iKey = itNoteOffEvent->Param.Note.Key;
1104          if (pKey->Active && !SustainPedal) {          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1105              itNoteOffEvent->Type = Event::type_release; // transform event type          pKey->KeyPressed = false; // the MIDI key was now released
         }  
1106    
1107          // move event to the key's own event list          // move event to the key's own event list
1108          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1109    
1110          // spawn release triggered voice(s) if needed          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1111          if (pKey->ReleaseTrigger) {  
1112              LaunchVoice(itNoteOffEventOnKeyList, 0, true, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples          // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1113              pKey->ReleaseTrigger = false;          if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1114                bool bOtherKeysPressed = false;
1115                if (iKey == pEngineChannel->SoloKey) {
1116                    pEngineChannel->SoloKey = -1;
1117                    // if there's still a key pressed down, respawn a voice (group) on the highest key
1118                    for (int i = 127; i > 0; i--) {
1119                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1120                        if (pOtherKey->KeyPressed) {
1121                            bOtherKeysPressed = true;
1122                            // make the other key the new 'currently active solo key'
1123                            pEngineChannel->SoloKey = i;
1124                            // get final portamento position of currently active voice
1125                            if (pEngineChannel->PortamentoMode) {
1126                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1127                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1128                            }
1129                            // create a pseudo note on event
1130                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1131                            if (itPseudoNoteOnEvent) {
1132                                // copy event
1133                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1134                                // transform event to a note on event
1135                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
1136                                itPseudoNoteOnEvent->Param.Note.Key      = i;
1137                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1138                                // allocate and trigger new voice(s) for the other key
1139                                {
1140                                    // first, get total amount of required voices (dependant on amount of layers)
1141                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1142                                    if (pRegion) {
1143                                        int voicesRequired = pRegion->Layers;
1144                                        // now launch the required amount of voices
1145                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1146                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1147                                    }
1148                                }
1149                                // if neither a voice was spawned or postponed then remove note on event from key again
1150                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1151                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1152    
1153                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
1154                            break; // done
1155                        }
1156                    }
1157                }
1158                if (bOtherKeysPressed) {
1159                    if (pKey->Active) { // kill all voices on this key
1160                        bShouldRelease = false; // no need to release, as we kill it here
1161                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1162                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
1163                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1164                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1165                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1166                        }
1167                    }
1168                } else pEngineChannel->PortamentoPos = -1.0f;
1169            }
1170    
1171            // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1172            if (bShouldRelease) {
1173                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1174    
1175                // spawn release triggered voice(s) if needed
1176                if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1177                    // first, get total amount of required voices (dependant on amount of layers)
1178                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1179                    if (pRegion) {
1180                        int voicesRequired = pRegion->Layers;
1181    
1182                        // MIDI note-on velocity is used instead of note-off velocity
1183                        itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
1184    
1185                        // now launch the required amount of voices
1186                        for (int i = 0; i < voicesRequired; i++)
1187                            LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
1188                    }
1189                    pKey->ReleaseTrigger = false;
1190                }
1191          }          }
1192    
1193            // if neither a voice was spawned or postponed on this key then remove note off event from key again
1194            if (!pKey->Active && !pKey->VoiceTheftsQueued)
1195                pKey->pEvents->free(itNoteOffEventOnKeyList);
1196      }      }
1197    
1198      /**      /**
1199       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
1200       *  event list.       *  channel's event list. It will actually processed later by the
1201         *  respective voice.
1202       *       *
1203         *  @param pEngineChannel - engine channel on which this event occured on
1204       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
1205       */       */
1206      void Engine::ProcessPitchbend(Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
1207          this->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value          pEngineChannel->Pitch = itPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
         itPitchbendEvent.moveToEndOf(pSynthesisEvents[Event::destination_vco]);  
1208      }      }
1209    
1210      /**      /**
# Line 747  namespace LinuxSampler { namespace gig { Line 1212  namespace LinuxSampler { namespace gig {
1212       *  called by the ProcessNoteOn() method and by the voices itself       *  called by the ProcessNoteOn() method and by the voices itself
1213       *  (e.g. to spawn further voices on the same key for layered sounds).       *  (e.g. to spawn further voices on the same key for layered sounds).
1214       *       *
1215         *  @param pEngineChannel      - engine channel on which this event occured on
1216       *  @param itNoteOnEvent       - key, velocity and time stamp of the event       *  @param itNoteOnEvent       - key, velocity and time stamp of the event
1217       *  @param iLayer              - layer index for the new voice (optional - only       *  @param iLayer              - layer index for the new voice (optional - only
1218       *                               in case of layered sounds of course)       *                               in case of layered sounds of course)
# Line 755  namespace LinuxSampler { namespace gig { Line 1221  namespace LinuxSampler { namespace gig {
1221       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
1222       *                               when there is no free voice       *                               when there is no free voice
1223       *                               (optional, default = true)       *                               (optional, default = true)
1224         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
1225         *                                   key group conflict
1226       *  @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
1227       *           if the voice wasn't triggered (for example when no region is       *           if the voice wasn't triggered (for example when no region is
1228       *           defined for the given key).       *           defined for the given key).
1229       */       */
1230      Pool<Voice>::Iterator Engine::LaunchVoice(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) {
1231          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
1232            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
1233            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
1234    
1235            // if nothing defined for this key
1236            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
1237    
1238            // only mark the first voice of a layered voice (group) to be in a
1239            // key group, so the layered voices won't kill each other
1240            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
1241    
1242            // handle key group (a.k.a. exclusive group) conflicts
1243            if (HandleKeyGroupConflicts) {
1244                if (iKeyGroup) { // if this voice / key belongs to a key group
1245                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
1246                    if (*ppKeyGroup) { // if there's already an active key in that key group
1247                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
1248                        // kill all voices on the (other) key
1249                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1250                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1251                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1252                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
1253                                itVoiceToBeKilled->Kill(itNoteOnEvent);
1254                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
1255                            }
1256                        }
1257                    }
1258                }
1259            }
1260    
1261            Voice::type_t VoiceType = Voice::type_normal;
1262    
1263            // get current dimension values to select the right dimension region
1264            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
1265            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
1266            uint DimValues[8] = { 0 };
1267            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
1268                switch (pRegion->pDimensionDefinitions[i].dimension) {
1269                    case ::gig::dimension_samplechannel:
1270                        DimValues[i] = 0; //TODO: we currently ignore this dimension
1271                        break;
1272                    case ::gig::dimension_layer:
1273                        DimValues[i] = iLayer;
1274                        break;
1275                    case ::gig::dimension_velocity:
1276                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1277                        break;
1278                    case ::gig::dimension_channelaftertouch:
1279                        DimValues[i] = pEngineChannel->ControllerTable[128];
1280                        break;
1281                    case ::gig::dimension_releasetrigger:
1282                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1283                        DimValues[i] = (uint) ReleaseTriggerVoice;
1284                        break;
1285                    case ::gig::dimension_keyboard:
1286                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1287                        break;
1288                    case ::gig::dimension_roundrobin:
1289                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
1290                        break;
1291                    case ::gig::dimension_random:
1292                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
1293                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1294                        break;
1295                    case ::gig::dimension_modwheel:
1296                        DimValues[i] = pEngineChannel->ControllerTable[1];
1297                        break;
1298                    case ::gig::dimension_breath:
1299                        DimValues[i] = pEngineChannel->ControllerTable[2];
1300                        break;
1301                    case ::gig::dimension_foot:
1302                        DimValues[i] = pEngineChannel->ControllerTable[4];
1303                        break;
1304                    case ::gig::dimension_portamentotime:
1305                        DimValues[i] = pEngineChannel->ControllerTable[5];
1306                        break;
1307                    case ::gig::dimension_effect1:
1308                        DimValues[i] = pEngineChannel->ControllerTable[12];
1309                        break;
1310                    case ::gig::dimension_effect2:
1311                        DimValues[i] = pEngineChannel->ControllerTable[13];
1312                        break;
1313                    case ::gig::dimension_genpurpose1:
1314                        DimValues[i] = pEngineChannel->ControllerTable[16];
1315                        break;
1316                    case ::gig::dimension_genpurpose2:
1317                        DimValues[i] = pEngineChannel->ControllerTable[17];
1318                        break;
1319                    case ::gig::dimension_genpurpose3:
1320                        DimValues[i] = pEngineChannel->ControllerTable[18];
1321                        break;
1322                    case ::gig::dimension_genpurpose4:
1323                        DimValues[i] = pEngineChannel->ControllerTable[19];
1324                        break;
1325                    case ::gig::dimension_sustainpedal:
1326                        DimValues[i] = pEngineChannel->ControllerTable[64];
1327                        break;
1328                    case ::gig::dimension_portamento:
1329                        DimValues[i] = pEngineChannel->ControllerTable[65];
1330                        break;
1331                    case ::gig::dimension_sostenutopedal:
1332                        DimValues[i] = pEngineChannel->ControllerTable[66];
1333                        break;
1334                    case ::gig::dimension_softpedal:
1335                        DimValues[i] = pEngineChannel->ControllerTable[67];
1336                        break;
1337                    case ::gig::dimension_genpurpose5:
1338                        DimValues[i] = pEngineChannel->ControllerTable[80];
1339                        break;
1340                    case ::gig::dimension_genpurpose6:
1341                        DimValues[i] = pEngineChannel->ControllerTable[81];
1342                        break;
1343                    case ::gig::dimension_genpurpose7:
1344                        DimValues[i] = pEngineChannel->ControllerTable[82];
1345                        break;
1346                    case ::gig::dimension_genpurpose8:
1347                        DimValues[i] = pEngineChannel->ControllerTable[83];
1348                        break;
1349                    case ::gig::dimension_effect1depth:
1350                        DimValues[i] = pEngineChannel->ControllerTable[91];
1351                        break;
1352                    case ::gig::dimension_effect2depth:
1353                        DimValues[i] = pEngineChannel->ControllerTable[92];
1354                        break;
1355                    case ::gig::dimension_effect3depth:
1356                        DimValues[i] = pEngineChannel->ControllerTable[93];
1357                        break;
1358                    case ::gig::dimension_effect4depth:
1359                        DimValues[i] = pEngineChannel->ControllerTable[94];
1360                        break;
1361                    case ::gig::dimension_effect5depth:
1362                        DimValues[i] = pEngineChannel->ControllerTable[95];
1363                        break;
1364                    case ::gig::dimension_none:
1365                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1366                        break;
1367                    default:
1368                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1369                }
1370            }
1371    
1372            // return if this is a release triggered voice and there is no
1373            // releasetrigger dimension (could happen if an instrument
1374            // change has occured between note on and off)
1375            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1376    
1377            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1378    
1379            // no need to continue if sample is silent
1380            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1381    
1382          // allocate a new voice for the key          // allocate a new voice for the key
1383          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1384          if (itNewVoice) {          if (itNewVoice) {
1385              // launch the new voice              // launch the new voice
1386              if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1387                  dmsg(4,("Voice not triggered\n"));                  dmsg(4,("Voice not triggered\n"));
1388                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1389              }              }
1390              else { // on success              else { // on success
1391                  uint** ppKeyGroup = NULL;                  --VoiceSpawnsLeft;
                 if (itNewVoice->KeyGroup) { // if this voice / key belongs to a key group  
                     ppKeyGroup = &ActiveKeyGroups[itNewVoice->KeyGroup];  
                     if (*ppKeyGroup) { // if there's already an active key in that key group  
                         midi_key_info_t* pOtherKey = &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);  
                         }  
                     }  
                 }  
1392                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1393                      pKey->Active = true;                      pKey->Active = true;
1394                      pKey->itSelf = pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1395                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1396                  }                  }
1397                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1398                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1399                      *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
1400                  }                  }
1401                  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 797  namespace LinuxSampler { namespace gig { Line 1403  namespace LinuxSampler { namespace gig {
1403              }              }
1404          }          }
1405          else if (VoiceStealing) {          else if (VoiceStealing) {
1406              // first, get total amount of required voices (dependant on amount of layers)              // try to steal one voice
1407              ::gig::Region* pRegion = pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);              int result = StealVoice(pEngineChannel, itNoteOnEvent);
1408              if (!pRegion) return Pool<Voice>::Iterator(); // nothing defined for this MIDI key, so no voice needed              if (!result) { // voice stolen successfully
1409              int voicesRequired = pRegion->Layers;                  // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1410                    RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1411              // now steal the (remaining) amount of voices                  if (itStealEvent) {
1412              for (int i = iLayer; i < voicesRequired; i++)                      *itStealEvent = *itNoteOnEvent; // copy event
1413                  StealVoice(itNoteOnEvent);                      itStealEvent->Param.Note.Layer = iLayer;
1414                        itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1415              // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died                      pKey->VoiceTheftsQueued++;
1416              RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();                  }
1417              if (itStealEvent) {                  else dmsg(1,("Voice stealing queue full!\n"));
                 *itStealEvent = *itNoteOnEvent; // copy event  
                 itStealEvent->Param.Note.Layer = iLayer;  
                 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;  
1418              }              }
             else dmsg(1,("Voice stealing queue full!\n"));  
1419          }          }
1420    
1421          return Pool<Voice>::Iterator(); // no free voice or error          return Pool<Voice>::Iterator(); // no free voice or error
# Line 825  namespace LinuxSampler { namespace gig { Line 1427  namespace LinuxSampler { namespace gig {
1427       *  voice stealing and postpone the note-on event until the selected       *  voice stealing and postpone the note-on event until the selected
1428       *  voice actually died.       *  voice actually died.
1429       *       *
1430         *  @param pEngineChannel - engine channel on which this event occured on
1431       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
1432         *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1433       */       */
1434      void Engine::StealVoice(Pool<Event>::Iterator& itNoteOnEvent) {      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1435            if (VoiceSpawnsLeft <= 0) {
1436                dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1437                return -1;
1438            }
1439          if (!pEventPool->poolIsEmpty()) {          if (!pEventPool->poolIsEmpty()) {
1440    
1441              RTList<uint>::Iterator  iuiOldestKey;              RTList<Voice>::Iterator itSelectedVoice;
             RTList<Voice>::Iterator itOldestVoice;  
1442    
1443              // Select one voice for voice stealing              // Select one voice for voice stealing
1444              switch (VOICE_STEAL_ALGORITHM) {              switch (CONFIG_VOICE_STEAL_ALGO) {
1445    
1446                  // try to pick the oldest voice on the key where the new                  // try to pick the oldest voice on the key where the new
1447                  // voice should be spawned, if there is no voice on that                  // voice should be spawned, if there is no voice on that
1448                  // key, or no voice left to kill there, then procceed with                  // key, or no voice left to kill, then procceed with
1449                  // 'oldestkey' algorithm                  // 'oldestkey' algorithm
1450                  case voice_steal_algo_keymask: {                  case voice_steal_algo_oldestvoiceonkey: {
1451                      midi_key_info_t* pOldestKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1452                      if (itLastStolenVoice) {                      itSelectedVoice = pSelectedKey->pActiveVoices->first();
1453                          itOldestVoice = itLastStolenVoice;                      // proceed iterating if voice was created in this fragment cycle
1454                          ++itOldestVoice;                      while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1455                      }                      // if we haven't found a voice then proceed with algorithm 'oldestkey'
1456                      else { // no voice stolen in this audio fragment cycle yet                      if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
                         itOldestVoice = pOldestKey->pActiveVoices->first();  
                     }  
                     if (itOldestVoice) {  
                         iuiOldestKey = pOldestKey->itSelf;  
                         break; // selection succeeded  
                     }  
1457                  } // no break - intentional !                  } // no break - intentional !
1458    
1459                  // try to pick the oldest voice on the oldest active key                  // try to pick the oldest voice on the oldest active key
1460                  // (caution: must stay after 'keymask' algorithm !)                  // from the same engine channel
1461                    // (caution: must stay after 'oldestvoiceonkey' algorithm !)
1462                  case voice_steal_algo_oldestkey: {                  case voice_steal_algo_oldestkey: {
1463                      if (itLastStolenVoice) {                      // if we already stole in this fragment, try to proceed on same key
1464                          midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiLastStolenKey];                      if (this->itLastStolenVoice) {
1465                          itOldestVoice = itLastStolenVoice;                          itSelectedVoice = this->itLastStolenVoice;
1466                          ++itOldestVoice;                          do {
1467                          if (!itOldestVoice) {                              ++itSelectedVoice;
1468                              iuiOldestKey = iuiLastStolenKey;                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1469                              ++iuiOldestKey;                          // found a "stealable" voice ?
1470                              if (iuiOldestKey) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1471                                  midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];                              // remember which voice we stole, so we can simply proceed on next voice stealing
1472                                  itOldestVoice = pOldestKey->pActiveVoices->first();                              this->itLastStolenVoice = itSelectedVoice;
1473                              }                              break; // selection succeeded
                             else {  
                                 dmsg(1,("gig::Engine: Warning, too less voices, even for voice stealing! - Better recompile with higher MAX_AUDIO_VOICES.\n"));  
                                 return;  
                             }  
1474                          }                          }
                         else iuiOldestKey = iuiLastStolenKey;  
1475                      }                      }
1476                      else { // no voice stolen in this audio fragment cycle yet                      // get (next) oldest key
1477                          iuiOldestKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
1478                          midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];                      while (iuiSelectedKey) {
1479                          itOldestVoice = pOldestKey->pActiveVoices->first();                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1480                            itSelectedVoice = pSelectedKey->pActiveVoices->first();
1481                            // proceed iterating if voice was created in this fragment cycle
1482                            while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1483                            // found a "stealable" voice ?
1484                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1485                                // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1486                                this->iuiLastStolenKey  = iuiSelectedKey;
1487                                this->itLastStolenVoice = itSelectedVoice;
1488                                break; // selection succeeded
1489                            }
1490                            ++iuiSelectedKey; // get next oldest key
1491                      }                      }
1492                      break;                      break;
1493                  }                  }
# Line 888  namespace LinuxSampler { namespace gig { Line 1496  namespace LinuxSampler { namespace gig {
1496                  case voice_steal_algo_none:                  case voice_steal_algo_none:
1497                  default: {                  default: {
1498                      dmsg(1,("No free voice (voice stealing disabled)!\n"));                      dmsg(1,("No free voice (voice stealing disabled)!\n"));
1499                      return;                      return -1;
1500                  }                  }
1501              }              }
1502    
1503              //FIXME: can be removed, just a sanity check for debugging              // if we couldn't steal a voice from the same engine channel then
1504              if (!itOldestVoice->IsActive()) dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));              // steal oldest voice on the oldest key from any other engine channel
1505                // (the smaller engine channel number, the higher priority)
1506                if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1507                    EngineChannel* pSelectedChannel;
1508                    int            iChannelIndex;
1509                    // select engine channel
1510                    if (pLastStolenChannel) {
1511                        pSelectedChannel = pLastStolenChannel;
1512                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1513                    } else { // pick the engine channel followed by this engine channel
1514                        iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1515                        pSelectedChannel = engineChannels[iChannelIndex];
1516                    }
1517    
1518                    // if we already stole in this fragment, try to proceed on same key
1519                    if (this->itLastStolenVoiceGlobally) {
1520                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1521                        do {
1522                            ++itSelectedVoice;
1523                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1524                    }
1525    
1526                    #if CONFIG_DEVMODE
1527                    EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1528                    #endif // CONFIG_DEVMODE
1529    
1530                    // did we find a 'stealable' voice?
1531                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1532                        // remember which voice we stole, so we can simply proceed on next voice stealing
1533                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1534                    } else while (true) { // iterate through engine channels
1535                        // get (next) oldest key
1536                        RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1537                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1538                        while (iuiSelectedKey) {
1539                            midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1540                            itSelectedVoice = pSelectedKey->pActiveVoices->first();
1541                            // proceed iterating if voice was created in this fragment cycle
1542                            while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1543                            // found a "stealable" voice ?
1544                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1545                                // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1546                                this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1547                                this->itLastStolenVoiceGlobally = itSelectedVoice;
1548                                this->pLastStolenChannel        = pSelectedChannel;
1549                                goto stealable_voice_found; // selection succeeded
1550                            }
1551                            ++iuiSelectedKey; // get next key on current engine channel
1552                        }
1553                        // get next engine channel
1554                        iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1555                        pSelectedChannel = engineChannels[iChannelIndex];
1556    
1557                        #if CONFIG_DEVMODE
1558                        if (pSelectedChannel == pBegin) {
1559                            dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1560                            dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1561                            dmsg(1,("Exiting.\n"));
1562                            exit(-1);
1563                        }
1564                        #endif // CONFIG_DEVMODE
1565                    }
1566                }
1567    
1568                // jump point if a 'stealable' voice was found
1569                stealable_voice_found:
1570    
1571                #if CONFIG_DEVMODE
1572                if (!itSelectedVoice->IsActive()) {
1573                    dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
1574                    return -1;
1575                }
1576                #endif // CONFIG_DEVMODE
1577    
1578              // now kill the selected voice              // now kill the selected voice
1579              itOldestVoice->Kill(itNoteOnEvent);              itSelectedVoice->Kill(itNoteOnEvent);
1580              // remember which voice on which key we stole, so we can simply proceed for the next voice stealing  
1581              this->itLastStolenVoice = itOldestVoice;              --VoiceSpawnsLeft;
1582              this->iuiLastStolenKey = iuiOldestKey;  
1583                return 0; // success
1584            }
1585            else {
1586                dmsg(1,("Event pool emtpy!\n"));
1587                return -1;
1588          }          }
         else dmsg(1,("Event pool emtpy!\n"));  
1589      }      }
1590    
1591      /**      /**
# Line 910  namespace LinuxSampler { namespace gig { Line 1594  namespace LinuxSampler { namespace gig {
1594       *  it finished to playback its sample, finished its release stage or       *  it finished to playback its sample, finished its release stage or
1595       *  just was killed.       *  just was killed.
1596       *       *
1597         *  @param pEngineChannel - engine channel on which this event occured on
1598       *  @param itVoice - points to the voice to be freed       *  @param itVoice - points to the voice to be freed
1599       */       */
1600      void Engine::FreeVoice(Pool<Voice>::Iterator& itVoice) {      void Engine::FreeVoice(EngineChannel* pEngineChannel, Pool<Voice>::Iterator& itVoice) {
1601          if (itVoice) {          if (itVoice) {
1602              midi_key_info_t* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoice->MIDIKey];
1603    
1604              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1605    
1606                // if the sample and dimension region belong to an
1607                // instrument that is unloaded, tell the disk thread to
1608                // release them
1609                if (itVoice->Orphan) {
1610                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1611                }
1612    
1613              // free the voice object              // free the voice object
1614              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1615    
1616              // if no other voices left and member of a key group, remove from key group              // if no other voices left and member of a key group, remove from key group
1617              if (pKey->pActiveVoices->isEmpty() && keygroup) {              if (pKey->pActiveVoices->isEmpty() && keygroup) {
1618                  uint** ppKeyGroup = &ActiveKeyGroups[keygroup];                  uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[keygroup];
1619                  if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group                  if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
1620              }              }
1621          }          }
# Line 934  namespace LinuxSampler { namespace gig { Line 1626  namespace LinuxSampler { namespace gig {
1626       *  Called when there's no more voice left on a key, this call will       *  Called when there's no more voice left on a key, this call will
1627       *  update the key info respectively.       *  update the key info respectively.
1628       *       *
1629         *  @param pEngineChannel - engine channel on which this event occured on
1630       *  @param pKey - key which is now inactive       *  @param pKey - key which is now inactive
1631       */       */
1632      void Engine::FreeKey(midi_key_info_t* pKey) {      void Engine::FreeKey(EngineChannel* pEngineChannel, midi_key_info_t* pKey) {
1633          if (pKey->pActiveVoices->isEmpty()) {          if (pKey->pActiveVoices->isEmpty()) {
1634              pKey->Active = false;              pKey->Active = false;
1635              pActiveKeys->free(pKey->itSelf); // remove key from list of active keys              pEngineChannel->pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
1636              pKey->itSelf = RTList<uint>::Iterator();              pKey->itSelf = RTList<uint>::Iterator();
1637              pKey->ReleaseTrigger = false;              pKey->ReleaseTrigger = false;
1638              pKey->pEvents->clear();              pKey->pEvents->clear();
# Line 952  namespace LinuxSampler { namespace gig { Line 1645  namespace LinuxSampler { namespace gig {
1645       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
1646       *  modulation wheel, aftertouch).       *  modulation wheel, aftertouch).
1647       *       *
1648         *  @param pEngineChannel - engine channel on which this event occured on
1649       *  @param itControlChangeEvent - controller, value and time stamp of the event       *  @param itControlChangeEvent - controller, value and time stamp of the event
1650       */       */
1651      void Engine::ProcessControlChange(Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1652          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1653    
1654            // handle the "control triggered" MIDI rule: a control change
1655            // event can trigger a new note on or note off event
1656            if (pEngineChannel->pInstrument) {
1657    
1658                ::gig::MidiRule* rule;
1659                for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1660    
1661                    if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1662                        dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1663                        if (itControlChangeEvent->Param.CC.Controller ==
1664                            ctrlTrigger->ControllerNumber) {
1665    
1666                            uint8_t oldCCValue = pEngineChannel->ControllerTable[
1667                                itControlChangeEvent->Param.CC.Controller];
1668                            uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1669    
1670                            for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1671                                ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1672                                      &ctrlTrigger->pTriggers[i];
1673    
1674                                // check if the controller has passed the
1675                                // trigger point in the right direction
1676                                if ((pTrigger->Descending &&
1677                                     oldCCValue > pTrigger->TriggerPoint &&
1678                                     newCCValue <= pTrigger->TriggerPoint) ||
1679                                    (!pTrigger->Descending &&
1680                                     oldCCValue < pTrigger->TriggerPoint &&
1681                                     newCCValue >= pTrigger->TriggerPoint)) {
1682    
1683                                    RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1684                                    if (itNewEvent) {
1685                                        *itNewEvent = *itControlChangeEvent;
1686                                        itNewEvent->Param.Note.Key = pTrigger->Key;
1687    
1688                                        if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1689                                            itNewEvent->Type = Event::type_note_off;
1690                                            itNewEvent->Param.Note.Velocity = 100;
1691    
1692                                            ProcessNoteOff(pEngineChannel, itNewEvent);
1693                                        } else {
1694                                            itNewEvent->Type = Event::type_note_on;
1695                                            //TODO: if Velocity is 255, the triggered velocity should
1696                                            // depend on how fast the controller is moving
1697                                            itNewEvent->Param.Note.Velocity =
1698                                                pTrigger->Velocity == 255 ? 100 :
1699                                                pTrigger->Velocity;
1700    
1701                                            ProcessNoteOn(pEngineChannel, itNewEvent);
1702                                        }
1703                                    }
1704                                    else dmsg(1,("Event pool emtpy!\n"));
1705                                }
1706                            }
1707                        }
1708                    }
1709                }
1710            }
1711    
1712            // update controller value in the engine channel's controller table
1713            pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1714    
1715            // handle hard coded MIDI controllers
1716          switch (itControlChangeEvent->Param.CC.Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
1717              case 64: {              case 5: { // portamento time
1718                  if (itControlChangeEvent->Param.CC.Value >= 64 && !SustainPedal) {                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1719                      dmsg(4,("PEDAL DOWN\n"));                  break;
1720                      SustainPedal = true;              }
1721                case 6: { // data entry (currently only used for RPN controllers)
1722                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1723                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1724                        // limit to +- two octaves for now
1725                        transpose = RTMath::Min(transpose,  24);
1726                        transpose = RTMath::Max(transpose, -24);
1727                        pEngineChannel->GlobalTranspose = transpose;
1728                        // workaround, so we won't have hanging notes
1729                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1730                    }
1731                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1732                    pEngineChannel->ResetMidiRpnController();
1733                    break;
1734                }
1735                case 7: { // volume
1736                    //TODO: not sample accurate yet
1737                    pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1738                    pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1739                    break;
1740                }
1741                case 10: { // panpot
1742                    //TODO: not sample accurate yet
1743                    pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1744                    pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1745                    pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1746                    break;
1747                }
1748                case 64: { // sustain
1749                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1750                        dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1751                        pEngineChannel->SustainPedal = true;
1752    
1753                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1754                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1755                        #endif
1756    
1757                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1758                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1759                      if (iuiKey) {                      for (; iuiKey; ++iuiKey) {
1760                          itControlChangeEvent->Type = Event::type_cancel_release; // transform event type                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1761                          while (iuiKey) {                          if (!pKey->KeyPressed) {
1762                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1763                              ++iuiKey;                              if (itNewEvent) {
1764                              if (!pKey->KeyPressed) {                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1765                                  RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                                  itNewEvent->Type = Event::type_cancel_release; // transform event type
                                 if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list  
                                 else dmsg(1,("Event pool emtpy!\n"));  
1766                              }                              }
1767                                else dmsg(1,("Event pool emtpy!\n"));
1768                          }                          }
1769                      }                      }
1770                  }                  }
1771                  if (itControlChangeEvent->Param.CC.Value < 64 && SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1772                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1773                      SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1774    
1775                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1776                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1777                        #endif
1778    
1779                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1780                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1781                      if (iuiKey) {                      for (; iuiKey; ++iuiKey) {
1782                          itControlChangeEvent->Type = Event::type_release; // transform event type                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1783                          while (iuiKey) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1784                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1785                              ++iuiKey;                              if (itNewEvent) {
1786                              if (!pKey->KeyPressed) {                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1787                                  RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                                  itNewEvent->Type = Event::type_release; // transform event type
                                 if (itNewEvent) *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list  
                                 else dmsg(1,("Event pool emtpy!\n"));  
1788                              }                              }
1789                                else dmsg(1,("Event pool emtpy!\n"));
1790                          }                          }
1791                      }                      }
1792                  }                  }
1793                  break;                  break;
1794              }              }
1795          }              case 65: { // portamento on / off
1796                    const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1797                    if (bPortamento != pEngineChannel->PortamentoMode)
1798                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1799                    pEngineChannel->PortamentoMode = bPortamento;
1800                    break;
1801                }
1802                case 66: { // sostenuto
1803                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1804                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1805                        pEngineChannel->SostenutoPedal = true;
1806    
1807                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1808                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1809                        #endif
1810    
1811                        SostenutoKeyCount = 0;
1812                        // Remeber the pressed keys
1813                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1814                        for (; iuiKey; ++iuiKey) {
1815                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1816                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1817                        }
1818                    }
1819                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1820                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1821                        pEngineChannel->SostenutoPedal = false;
1822    
1823                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1824                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1825                        #endif
1826    
1827                        // release voices if the damper pedal is up and their respective key is not pressed
1828                        for (int i = 0; i < SostenutoKeyCount; i++) {
1829                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1830                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1831                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1832                                if (itNewEvent) {
1833                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1834                                    itNewEvent->Type = Event::type_release; // transform event type
1835                                }
1836                                else dmsg(1,("Event pool emtpy!\n"));
1837                            }
1838                        }
1839                    }
1840                    break;
1841                }
1842                case 100: { // RPN controller LSB
1843                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1844                    break;
1845                }
1846                case 101: { // RPN controller MSB
1847                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1848                    break;
1849                }
1850    
1851    
1852                // Channel Mode Messages
1853    
1854          // update controller value in the engine's controller table              case 120: { // all sound off
1855          ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1856                    break;
1857                }
1858                case 121: { // reset all controllers
1859                    pEngineChannel->ResetControllers();
1860                    break;
1861                }
1862                case 123: { // all notes off
1863                    #if CONFIG_PROCESS_ALL_NOTES_OFF
1864                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1865                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1866                    break;
1867                }
1868                case 126: { // mono mode on
1869                    if (!pEngineChannel->SoloMode)
1870                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1871                    pEngineChannel->SoloMode = true;
1872                    break;
1873                }
1874                case 127: { // poly mode on
1875                    if (pEngineChannel->SoloMode)
1876                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1877                    pEngineChannel->SoloMode = false;
1878                    break;
1879                }
1880            }
1881    
1882          // move event from the unsorted event list to the control change event list          // handle FX send controllers
1883          itControlChangeEvent.moveToEndOf(pCCEvents);          if (!pEngineChannel->fxSends.empty()) {
1884                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1885                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1886                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1887                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1888                        pFxSend->SetInfoChanged(true);
1889                    }
1890                }
1891            }
1892      }      }
1893    
1894      /**      /**
# Line 1014  namespace LinuxSampler { namespace gig { Line 1897  namespace LinuxSampler { namespace gig {
1897       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1898       */       */
1899      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1900          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1901    
1902          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1903          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1022  namespace LinuxSampler { namespace gig { Line 1905  namespace LinuxSampler { namespace gig {
1905          if (exclusive_status != 0xF0)       goto free_sysex_data;          if (exclusive_status != 0xF0)       goto free_sysex_data;
1906    
1907          switch (id) {          switch (id) {
1908                case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1909                    uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1910                    if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1911                    if (!reader.pop(&sub_id1)) goto free_sysex_data;
1912                    if (!reader.pop(&sub_id2)) goto free_sysex_data;
1913                    if (!reader.pop(&val_lsb)) goto free_sysex_data;
1914                    if (!reader.pop(&val_msb)) goto free_sysex_data;
1915                    //TODO: for now we simply ignore the sysex channel, seldom used anyway
1916                    switch (sub_id1) {
1917                        case 0x04: // Device Control
1918                            switch (sub_id2) {
1919                                case 0x01: { // Master Volume
1920                                    const double volume =
1921                                        double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1922                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1923                                    // apply volume to all sampler channels that
1924                                    // are connected to the same MIDI input port
1925                                    // this sysex message arrived on
1926                                    for (int i = 0; i < engineChannels.size(); ++i) {
1927                                        EngineChannel* pEngineChannel = engineChannels[i];
1928                                        if (pEngineChannel->GetMidiInputPort() ==
1929                                            itSysexEvent->pMidiInputPort)
1930                                        {
1931                                            pEngineChannel->Volume(volume);
1932                                        }
1933                                    }
1934                                    #else
1935                                    // apply volume globally to the whole sampler
1936                                    GLOBAL_VOLUME = volume;
1937                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1938                                    break;
1939                                }
1940                            }
1941                            break;
1942                    }
1943                    break;
1944                }
1945              case 0x41: { // Roland              case 0x41: { // Roland
1946                    dmsg(3,("Roland Sysex\n"));
1947                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
1948                  if (!reader.pop(&device_id)) goto free_sysex_data;                  if (!reader.pop(&device_id)) goto free_sysex_data;
1949                  if (!reader.pop(&model_id))  goto free_sysex_data;                  if (!reader.pop(&model_id))  goto free_sysex_data;
# Line 1032  namespace LinuxSampler { namespace gig { Line 1953  namespace LinuxSampler { namespace gig {
1953    
1954                  // command address                  // command address
1955                  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)
1956                  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
1957                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1958                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1959                        dmsg(3,("\tSystem Parameter\n"));
1960                  }                  }
1961                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1962                        dmsg(3,("\tCommon Parameter\n"));
1963                  }                  }
1964                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
1965                      switch (addr[3]) {                      dmsg(3,("\tPart Parameter\n"));
1966                        switch (addr[2]) {
1967                          case 0x40: { // scale tuning                          case 0x40: { // scale tuning
1968                                dmsg(3,("\t\tScale Tuning\n"));
1969                              uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave                              uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
1970                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1971                              uint8_t checksum;                              uint8_t checksum;
1972                              if (!reader.pop(&checksum))                      goto free_sysex_data;                              if (!reader.pop(&checksum)) goto free_sysex_data;
1973                              if (GSCheckSum(checksum_reader, 12) != checksum) goto free_sysex_data;                              #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1974                                if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1975                                #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1976                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1977                              AdjustScale((int8_t*) scale_tunes);                              AdjustScale((int8_t*) scale_tunes);
1978                                dmsg(3,("\t\t\tNew scale applied.\n"));
1979                                break;
1980                            }
1981                            case 0x15: { // chromatic / drumkit mode
1982                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1983                                uint8_t part = addr[1] & 0x0f;
1984                                uint8_t map;
1985                                if (!reader.pop(&map)) goto free_sysex_data;
1986                                for (int i = 0; i < engineChannels.size(); ++i) {
1987                                    EngineChannel* pEngineChannel = engineChannels[i];
1988                                    if (
1989                                        (pEngineChannel->midiChannel == part ||
1990                                         pEngineChannel->midiChannel == midi_chan_all) &&
1991                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
1992                                    ) {
1993                                        try {
1994                                            pEngineChannel->SetMidiInstrumentMap(map);
1995                                        } catch (Exception e) {
1996                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
1997                                            goto free_sysex_data;
1998                                        } catch (...) {
1999                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
2000                                            goto free_sysex_data;
2001                                        }
2002                                    }
2003                                }
2004                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
2005                              break;                              break;
2006                          }                          }
2007                      }                      }
# Line 1072  namespace LinuxSampler { namespace gig { Line 2026  namespace LinuxSampler { namespace gig {
2026       *                     question       *                     question
2027       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
2028       */       */
2029      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) {
2030          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
2031          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
2032          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
2033          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1092  namespace LinuxSampler { namespace gig { Line 2046  namespace LinuxSampler { namespace gig {
2046      }      }
2047    
2048      /**      /**
2049       * Initialize the parameter sequence for the modulation destination given by       * Releases all voices on an engine channel. All voices will go into
2050       * by 'dst' with the constant value given by val.       * the release stage and thus it might take some time (e.g. dependant to
2051         * their envelope release time) until they actually die.
2052         *
2053         * @param pEngineChannel - engine channel on which all voices should be released
2054         * @param itReleaseEvent - event which caused this releasing of all voices
2055       */       */
2056      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) {
2057          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
2058          float* m = &pSynthesisParameters[dst][0];          while (iuiKey) {
2059          for (int i = 0; i < maxsamples; i += 4) {              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
2060             m[i]   = val;              ++iuiKey;
2061             m[i+1] = val;              // append a 'release' event to the key's own event list
2062             m[i+2] = val;              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
2063             m[i+3] = val;              if (itNewEvent) {
2064                    *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
2065                    itNewEvent->Type = Event::type_release; // transform event type
2066                }
2067                else dmsg(1,("Event pool emtpy!\n"));
2068          }          }
2069      }      }
2070    
2071      float Engine::Volume() {      /**
2072          return GlobalVolume;       * Kills all voices on an engine channel as soon as possible. Voices
2073         * won't get into release state, their volume level will be ramped down
2074         * as fast as possible.
2075         *
2076         * @param pEngineChannel - engine channel on which all voices should be killed
2077         * @param itKillEvent    - event which caused this killing of all voices
2078         */
2079        void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
2080            RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
2081            RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
2082            while (iuiKey != end) { // iterate through all active keys
2083                midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
2084                ++iuiKey;
2085                RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
2086                RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
2087                for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
2088                    itVoice->Kill(itKillEvent);
2089                    --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
2090                }
2091            }
2092      }      }
2093    
2094      void Engine::Volume(float f) {      /**
2095          GlobalVolume = f;       * Determines whether the specified voice should be released.
2096         *
2097         * @param pEngineChannel - The engine channel on which the voice should be checked
2098         * @param Key - The key number
2099         * @returns true if the specified should be released, false otherwise.
2100         */
2101        bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
2102            if (pEngineChannel->SustainPedal) return false;
2103    
2104            if (pEngineChannel->SostenutoPedal) {
2105                for (int i = 0; i < SostenutoKeyCount; i++)
2106                    if (Key == SostenutoKeys[i]) return false;
2107            }
2108    
2109            return true;
2110      }      }
2111    
2112      uint Engine::Channels() {      uint Engine::VoiceCount() {
2113          return 2;          return atomic_read(&ActiveVoiceCount);
2114      }      }
2115    
2116      void Engine::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void Engine::SetVoiceCount(uint Count) {
2117          AudioChannel* pChannel = pAudioOutputDevice->Channel(AudioDeviceChannel);          atomic_set(&ActiveVoiceCount, Count);
         if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));  
         switch (EngineAudioChannel) {  
             case 0: // left output channel  
                 pOutputLeft = pChannel->Buffer();  
                 AudioDeviceChannelLeft = AudioDeviceChannel;  
                 break;  
             case 1: // right output channel  
                 pOutputRight = pChannel->Buffer();  
                 AudioDeviceChannelRight = AudioDeviceChannel;  
                 break;  
             default:  
                 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));  
         }  
2118      }      }
2119    
2120      int Engine::OutputChannel(uint EngineAudioChannel) {      uint Engine::VoiceCountMax() {
2121          switch (EngineAudioChannel) {          return ActiveVoiceCountMax;
             case 0: // left channel  
                 return AudioDeviceChannelLeft;  
             case 1: // right channel  
                 return AudioDeviceChannelRight;  
             default:  
                 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));  
         }  
2122      }      }
2123    
2124      uint Engine::VoiceCount() {      int Engine::MaxVoices() {
2125          return ActiveVoiceCount;          return pVoicePool->poolSize();
2126      }      }
2127    
2128      uint Engine::VoiceCountMax() {      void Engine::SetMaxVoices(int iVoices) throw (Exception) {
2129          return ActiveVoiceCountMax;          if (iVoices < 1)
2130                throw Exception("Maximum voices for an engine cannot be set lower than 1");
2131    
2132            SuspendAll();
2133    
2134            if (pDimRegionPool[0]) delete pDimRegionPool[0];
2135            if (pDimRegionPool[1]) delete pDimRegionPool[1];
2136    
2137            pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices);
2138            pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices);
2139    
2140            try {
2141                pVoicePool->resizePool(iVoices);
2142            } catch (...) {
2143                throw Exception("FATAL: Could not resize voice pool!");
2144            }
2145    
2146            for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2147                iterVoice->SetEngine(this);
2148                iterVoice->pDiskThread = this->pDiskThread;
2149            }
2150            pVoicePool->clear();
2151    
2152            ResumeAll();
2153      }      }
2154    
2155      bool Engine::DiskStreamSupported() {      bool Engine::DiskStreamSupported() {
# Line 1159  namespace LinuxSampler { namespace gig { Line 2157  namespace LinuxSampler { namespace gig {
2157      }      }
2158    
2159      uint Engine::DiskStreamCount() {      uint Engine::DiskStreamCount() {
2160          return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;          return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0;
2161      }      }
2162    
2163      uint Engine::DiskStreamCountMax() {      uint Engine::DiskStreamCountMax() {
2164          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2165      }      }
2166    
2167      String Engine::DiskStreamBufferFillBytes() {      int Engine::MaxDiskStreams() {
2168          return pDiskThread->GetBufferFillBytes();          return iMaxDiskStreams;
2169      }      }
2170    
2171      String Engine::DiskStreamBufferFillPercentage() {      void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) {
2172          return pDiskThread->GetBufferFillPercentage();          if (iStreams < 0)
2173      }              throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
2174    
2175      String Engine::EngineName() {          SuspendAll();
2176          return "GigEngine";  
2177      }          iMaxDiskStreams = iStreams;
2178    
2179      String Engine::InstrumentFileName() {          // reconnect to audio output device, because that will automatically
2180          return InstrumentFile;          // recreate the disk thread with the required amount of streams
2181            if (pAudioOutputDevice) Connect(pAudioOutputDevice);
2182    
2183            ResumeAll();
2184      }      }
2185    
2186      String Engine::InstrumentName() {      String Engine::DiskStreamBufferFillBytes() {
2187          return InstrumentIdxName;          return pDiskThread->GetBufferFillBytes();
2188      }      }
2189    
2190      int Engine::InstrumentIndex() {      String Engine::DiskStreamBufferFillPercentage() {
2191          return InstrumentIdx;          return pDiskThread->GetBufferFillPercentage();
2192      }      }
2193    
2194      int Engine::InstrumentStatus() {      String Engine::EngineName() {
2195          return InstrumentStat;          return LS_GIG_ENGINE_NAME;
2196      }      }
2197    
2198      String Engine::Description() {      String Engine::Description() {
2199          return "Gigasampler Engine";          return "Gigasampler Format Engine";
2200      }      }
2201    
2202      String Engine::Version() {      String Engine::Version() {
2203          String s = "$Revision: 1.24 $";          String s = "$Revision: 1.99 $";
2204          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
2205      }      }
2206    
2207        InstrumentManager* Engine::GetInstrumentManager() {
2208            return &instruments;
2209        }
2210    
2211        // static constant initializers
2212        const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2213        const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2214        const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2215    
2216        float* Engine::InitVolumeCurve() {
2217            // line-segment approximation
2218            const float segments[] = {
2219                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2220                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2221            };
2222            return InitCurve(segments);
2223        }
2224    
2225        float* Engine::InitPanCurve() {
2226            // line-segment approximation
2227            const float segments[] = {
2228                0, 0, 1, 0,
2229                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2230                127, 1.41, 128, 1.41
2231            };
2232            return InitCurve(segments, 129);
2233        }
2234    
2235        float* Engine::InitCrossfadeCurve() {
2236            // line-segment approximation
2237            const float segments[] = {
2238                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2239            };
2240            return InitCurve(segments);
2241        }
2242    
2243        float* Engine::InitCurve(const float* segments, int size) {
2244            float* y = new float[size];
2245            for (int x = 0 ; x < size ; x++) {
2246                if (x > segments[2]) segments += 2;
2247                y[x] = segments[1] + (x - segments[0]) *
2248                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
2249            }
2250            return y;
2251        }
2252    
2253  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.376  
changed lines
  Added in v.1800

  ViewVC Help
Powered by ViewVC