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

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

  ViewVC Help
Powered by ViewVC