/[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 351 by schoenebeck, Tue Jan 25 22:11:43 2005 UTC revision 1248 by persson, Fri Jun 22 10:10:06 2007 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005-2007 Christian Schoenebeck                        *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 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"
 #include <malloc.h>  
31    
32  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
33    
34      InstrumentResourceManager Engine::Instruments;      InstrumentResourceManager Engine::instruments;
35    
36        std::map<AudioOutputDevice*,Engine*> Engine::engines;
37    
38        /**
39         * Get a gig::Engine object for the given gig::EngineChannel and the
40         * given AudioOutputDevice. All engine channels which are connected to
41         * the same audio output device will use the same engine instance. This
42         * method will be called by a gig::EngineChannel whenever it's
43         * connecting to a audio output device.
44         *
45         * @param pChannel - engine channel which acquires an engine object
46         * @param pDevice  - the audio output device \a pChannel is connected to
47         */
48        Engine* Engine::AcquireEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
49            Engine* pEngine = NULL;
50            // check if there's already an engine for the given audio output device
51            if (engines.count(pDevice)) {
52                dmsg(4,("Using existing gig::Engine.\n"));
53                pEngine = engines[pDevice];
54    
55                // Disable the engine while the new engine channel is
56                // added and initialized. The engine will be enabled again
57                // in EngineChannel::Connect.
58                pEngine->DisableAndLock();
59            } else { // create a new engine (and disk thread) instance for the given audio output device
60                dmsg(4,("Creating new gig::Engine.\n"));
61                pEngine = (Engine*) EngineFactory::Create("gig");
62                pEngine->Connect(pDevice);
63                engines[pDevice] = pEngine;
64            }
65            // register engine channel to the engine instance
66            pEngine->engineChannels.add(pChannel);
67            // remember index in the ArrayList
68            pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
69            dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
70            return pEngine;
71        }
72    
73        /**
74         * Once an engine channel is disconnected from an audio output device,
75         * it wil immediately call this method to unregister itself from the
76         * engine instance and if that engine instance is not used by any other
77         * engine channel anymore, then that engine instance will be destroyed.
78         *
79         * @param pChannel - engine channel which wants to disconnect from it's
80         *                   engine instance
81         * @param pDevice  - audio output device \a pChannel was connected to
82         */
83        void Engine::FreeEngine(LinuxSampler::gig::EngineChannel* pChannel, AudioOutputDevice* pDevice) {
84            dmsg(4,("Disconnecting EngineChannel from gig::Engine.\n"));
85            Engine* pEngine = engines[pDevice];
86            // unregister EngineChannel from the Engine instance
87            pEngine->engineChannels.remove(pChannel);
88            // if the used Engine instance is not used anymore, then destroy it
89            if (pEngine->engineChannels.empty()) {
90                pDevice->Disconnect(pEngine);
91                engines.erase(pDevice);
92                delete pEngine;
93                dmsg(4,("Destroying gig::Engine.\n"));
94            }
95            else dmsg(4,("This gig::Engine has now %d EngineChannels.\n",pEngine->engineChannels.size()));
96        }
97    
98        /**
99         * Constructor
100         */
101      Engine::Engine() {      Engine::Engine() {
         pRIFF              = NULL;  
         pGig               = NULL;  
         pInstrument        = NULL;  
102          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
103          pDiskThread        = NULL;          pDiskThread        = NULL;
104          pEventGenerator    = NULL;          pEventGenerator    = NULL;
105          pSysexBuffer       = new RingBuffer<uint8_t>(SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
106          pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
107          pEventPool         = new Pool<Event>(MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
108          pVoicePool         = new Pool<Voice>(MAX_AUDIO_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
109          pActiveKeys        = new Pool<uint>(128);          pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];
110          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
111          pEvents            = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
112          pCCEvents          = new RTList<Event>(pEventPool);          InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);
113          for (uint i = 0; i < Event::destination_count; i++) {          InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);
114              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);  
         }  
115          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
116              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
117          }          }
118          pVoicePool->clear();          pVoicePool->clear();
119    
         pSynthesisParameters[0] = NULL; // we allocate when an audio device is connected  
         pBasicFilterParameters  = NULL;  
         pMainFilterParameters   = NULL;  
   
         InstrumentIdx = -1;  
         InstrumentStat = -1;  
   
         AudioDeviceChannelLeft  = -1;  
         AudioDeviceChannelRight = -1;  
   
120          ResetInternal();          ResetInternal();
121            ResetScaleTuning();
122      }      }
123    
124        /**
125         * Destructor
126         */
127      Engine::~Engine() {      Engine::~Engine() {
128            MidiInputPort::RemoveSysexListener(this);
129          if (pDiskThread) {          if (pDiskThread) {
130              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
131              pDiskThread->StopThread();              pDiskThread->StopThread();
132              delete pDiskThread;              delete pDiskThread;
133              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
134          }          }
   
         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;  
135          if (pEventQueue) delete pEventQueue;          if (pEventQueue) delete pEventQueue;
136          if (pEventPool)  delete pEventPool;          if (pEventPool)  delete pEventPool;
137          if (pVoicePool) {          if (pVoicePool) {
138                  pVoicePool->clear();              pVoicePool->clear();
139                  delete pVoicePool;              delete pVoicePool;
140          }          }
         if (pActiveKeys) delete pActiveKeys;  
         if (pSysexBuffer) delete pSysexBuffer;  
141          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
         if (pMainFilterParameters) delete[] pMainFilterParameters;  
         if (pBasicFilterParameters) delete[] pBasicFilterParameters;  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
142          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
143            if (pSysexBuffer) delete pSysexBuffer;
144            if (pGlobalEvents) delete pGlobalEvents;
145            if (InstrumentChangeQueue) delete InstrumentChangeQueue;
146            if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;
147            if (pDimRegionsInUse) delete[] pDimRegionsInUse;
148            Unregister();
149      }      }
150    
151      void Engine::Enable() {      void Engine::Enable() {
# Line 135  namespace LinuxSampler { namespace gig { Line 172  namespace LinuxSampler { namespace gig {
172       */       */
173      void Engine::Reset() {      void Engine::Reset() {
174          DisableAndLock();          DisableAndLock();
   
         //if (pAudioOutputDevice->IsPlaying()) { // if already running  
             /*  
             // signal audio thread not to enter render part anymore  
             SuspensionRequested = true;  
             // sleep until wakened by audio thread  
             pthread_mutex_lock(&__render_state_mutex);  
             pthread_cond_wait(&__render_exit_condition, &__render_state_mutex);  
             pthread_mutex_unlock(&__render_state_mutex);  
             */  
         //}  
   
         //if (wasplaying) pAudioOutputDevice->Stop();  
   
175          ResetInternal();          ResetInternal();
176            ResetScaleTuning();
         // signal audio thread to continue with rendering  
         //SuspensionRequested = false;  
177          Enable();          Enable();
178      }      }
179    
180      /**      /**
181       *  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
182       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
183       */       */
184      void Engine::ResetInternal() {      void Engine::ResetInternal() {
185          Pitch               = 0;          ResetInternalMutex.Lock();
186          SustainPedal        = false;  
187            // make sure that the engine does not get any sysex messages
188            // while it's reseting
189            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
190          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
191          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
         GlobalVolume        = 1.0;  
192    
193          // reset voice stealing parameters          // reset voice stealing parameters
         itLastStolenVoice = RTList<Voice>::Iterator();  
         iuiLastStolenKey  = RTList<uint>::Iterator();  
194          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
195            itLastStolenVoice          = RTList<Voice>::Iterator();
196          // reset to normal chromatic scale (means equal temper)          itLastStolenVoiceGlobally  = RTList<Voice>::Iterator();
197          memset(&ScaleTuning[0], 0x00, 12);          iuiLastStolenKey           = RTList<uint>::Iterator();
198            iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
199          // 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;  
200    
201          // reset all voices          // reset all voices
202          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 198  namespace LinuxSampler { namespace gig { Line 204  namespace LinuxSampler { namespace gig {
204          }          }
205          pVoicePool->clear();          pVoicePool->clear();
206    
         // free all active keys  
         pActiveKeys->clear();  
   
207          // reset disk thread          // reset disk thread
208          if (pDiskThread) pDiskThread->Reset();          if (pDiskThread) pDiskThread->Reset();
209    
210          // delete all input events          // delete all input events
211          pEventQueue->init();          pEventQueue->init();
212            pSysexBuffer->init();
213            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
214            ResetInternalMutex.Unlock();
215      }      }
216    
217      /**      /**
218       *  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  
219       */       */
220      void Engine::LoadInstrument(const char* FileName, uint Instrument) {      void Engine::ResetScaleTuning() {
221            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;  
   
         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();  
     }  
   
     /**  
      * Will be called by the InstrumentResourceManager when the instrument  
      * we are currently using in this engine is going to be updated, so we  
      * can stop playback before that happens.  
      */  
     void Engine::ResourceToBeUpdated(::gig::Instrument* pResource, void*& pUpdateArg) {  
         dmsg(3,("gig::Engine: Received instrument update message.\n"));  
         DisableAndLock();  
         ResetInternal();  
         this->pInstrument = NULL;  
222      }      }
223    
224      /**      /**
225       * Will be called by the InstrumentResourceManager when the instrument       * Connect this engine instance with the given audio output device.
226       * update process was completed, so we can continue with playback.       * This method will be called when an Engine instance is created.
227         * All of the engine's data structures which are dependant to the used
228         * audio output device / driver will be (re)allocated and / or
229         * adjusted appropriately.
230         *
231         * @param pAudioOut - audio output device to connect to
232       */       */
     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();  
     }  
   
233      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
234          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
235    
# Line 312  namespace LinuxSampler { namespace gig { Line 241  namespace LinuxSampler { namespace gig {
241          }          }
242          catch (AudioOutputException e) {          catch (AudioOutputException e) {
243              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();
244              throw LinuxSamplerException(msg);              throw Exception(msg);
245          }          }
246    
247          this->AudioDeviceChannelLeft  = 0;          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
248          this->AudioDeviceChannelRight = 1;          this->SampleRate         = pAudioOutputDevice->SampleRate();
         this->pOutputLeft             = pAudioOutputDevice->Channel(0)->Buffer();  
         this->pOutputRight            = pAudioOutputDevice->Channel(1)->Buffer();  
         this->MaxSamplesPerCycle      = pAudioOutputDevice->MaxSamplesPerCycle();  
         this->SampleRate              = pAudioOutputDevice->SampleRate();  
249    
250          // FIXME: audio drivers with varying fragment sizes might be a problem here          // FIXME: audio drivers with varying fragment sizes might be a problem here
251          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * EG_MIN_RELEASE_TIME) - 1;          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
252          if (MaxFadeOutPos < 0)          if (MaxFadeOutPos < 0) {
253              throw LinuxSamplerException("EG_MIN_RELEASE_TIME in EGADSR.h to big for current audio fragment size / sampling rate!");              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
254                          << "too big for current audio fragment size & sampling rate! "
255                          << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
256                // force volume ramp downs at the beginning of each fragment
257                MaxFadeOutPos = 0;
258                // lower minimum release time
259                const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
260                for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
261                    iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);
262                }
263                pVoicePool->clear();
264            }
265    
266          // (re)create disk thread          // (re)create disk thread
267          if (this->pDiskThread) {          if (this->pDiskThread) {
# Line 334  namespace LinuxSampler { namespace gig { Line 270  namespace LinuxSampler { namespace gig {
270              delete this->pDiskThread;              delete this->pDiskThread;
271              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
272          }          }
273          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
274                                               &instruments);
275          if (!pDiskThread) {          if (!pDiskThread) {
276              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
277              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 350  namespace LinuxSampler { namespace gig { Line 287  namespace LinuxSampler { namespace gig {
287          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
288          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());          pEventGenerator = new EventGenerator(pAudioOut->SampleRate());
289    
         // (re)allocate synthesis parameter matrix  
         if (pSynthesisParameters[0]) free(pSynthesisParameters[0]);  
         pSynthesisParameters[0] = (float *) memalign(16,(Event::destination_count * sizeof(float) * pAudioOut->MaxSamplesPerCycle()));  
         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()];  
   
290          dmsg(1,("Starting disk thread..."));          dmsg(1,("Starting disk thread..."));
291          pDiskThread->StartThread();          pDiskThread->StartThread();
292          dmsg(1,("OK\n"));          dmsg(1,("OK\n"));
# Line 374  namespace LinuxSampler { namespace gig { Line 299  namespace LinuxSampler { namespace gig {
299          }          }
300      }      }
301    
302      void Engine::DisconnectAudioOutputDevice() {      /**
303          if (pAudioOutputDevice) { // if clause to prevent disconnect loops       * Clear all engine global event lists.
304              AudioOutputDevice* olddevice = pAudioOutputDevice;       */
305              pAudioOutputDevice = NULL;      void Engine::ClearEventLists() {
306              olddevice->Disconnect(this);          pGlobalEvents->clear();
307              AudioDeviceChannelLeft  = -1;      }
308              AudioDeviceChannelRight = -1;  
309        /**
310         * Copy all events from the engine's global input queue buffer to the
311         * engine's internal event list. This will be done at the beginning of
312         * each audio cycle (that is each RenderAudio() call) to distinguish
313         * all global events which have to be processed in the current audio
314         * cycle. These events are usually just SysEx messages. Every
315         * EngineChannel has it's own input event queue buffer and event list
316         * to handle common events like NoteOn, NoteOff and ControlChange
317         * events.
318         *
319         * @param Samples - number of sample points to be processed in the
320         *                  current audio cycle
321         */
322        void Engine::ImportEvents(uint Samples) {
323            RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
324            Event* pEvent;
325            while (true) {
326                // get next event from input event queue
327                if (!(pEvent = eventQueueReader.pop())) break;
328                // if younger event reached, ignore that and all subsequent ones for now
329                if (pEvent->FragmentPos() >= Samples) {
330                    eventQueueReader--;
331                    dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));
332                    pEvent->ResetFragmentPos();
333                    break;
334                }
335                // copy event to internal event list
336                if (pGlobalEvents->poolIsEmpty()) {
337                    dmsg(1,("Event pool emtpy!\n"));
338                    break;
339                }
340                *pGlobalEvents->allocAppend() = *pEvent;
341          }          }
342            eventQueueReader.free(); // free all copied events from input queue
343      }      }
344    
345      /**      /**
346       *  Let this engine proceed to render the given amount of sample points. The       * Let this engine proceed to render the given amount of sample points.
347       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
348       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
349       *  converted to the appropriate value range by the audio output class (e.g.       * all voices of each engine channel will be placed into the audio sum
350       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
351         * respective engine channel.
352       *       *
353       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
354       *  @returns       0 on success       *  @returns       0 on success
355       */       */
356      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
357          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));
358    
359          // return if no instrument loaded or engine disabled          // return if engine disabled
360          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
361              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
362              return 0;              return 0;
363          }          }
         if (!pInstrument) {  
             dmsg(5,("gig::Engine: no instrument loaded\n"));  
             return 0;  
         }  
   
364    
365          // 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)
366          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
367    
368            // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned
369            // in each audio fragment. All subsequent request for spawning new
370            // voices in the same audio fragment will be ignored.
371            VoiceSpawnsLeft = CONFIG_MAX_VOICES;
372    
373            // get all events from the engine's global input event queue which belong to the current fragment
374            // (these are usually just SysEx messages)
375            ImportEvents(Samples);
376    
377          // 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();  
         }  
378          {          {
379              RTList<uint>::Iterator iuiKey = pActiveKeys->first();              RTList<Event>::Iterator itEvent = pGlobalEvents->first();
380              RTList<uint>::Iterator end    = pActiveKeys->end();              RTList<Event>::Iterator end     = pGlobalEvents->end();
381              for(; iuiKey != end; ++iuiKey) {              for (; itEvent != end; ++itEvent) {
382                  pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key                  switch (itEvent->Type) {
383                        case Event::type_sysex:
384                            dmsg(5,("Engine: Sysex received\n"));
385                            ProcessSysex(itEvent);
386                            break;
387                    }
388              }              }
389          }          }
390    
391            // reset internal voice counter (just for statistic of active voices)
392            ActiveVoiceCountTemp = 0;
393    
394          // get all events from the input event queue which belong to the current fragment          // handle instrument change commands
395          {          instrument_change_command_t command;
396              RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          if (InstrumentChangeQueue->pop(&command) > 0) {
397              Event* pEvent;              EngineChannel* pEngineChannel = command.pEngineChannel;
398              while (true) {              pEngineChannel->pInstrument = command.pInstrument;
399                  // get next event from input event queue  
400                  if (!(pEvent = eventQueueReader.pop())) break;              // iterate through all active voices and mark their
401                  // if younger event reached, ignore that and all subsequent ones for now              // dimension regions as "in use". The instrument resource
402                  if (pEvent->FragmentPos() >= Samples) {              // manager may delete all of the instrument except the
403                      eventQueueReader--;              // dimension regions and samples that are in use.
404                      dmsg(2,("Younger Event, pos=%d ,Samples=%d!\n",pEvent->FragmentPos(),Samples));              int i = 0;
405                      pEvent->ResetFragmentPos();              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
406                      break;              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
407                  }              while (iuiKey != end) { // iterate through all active keys
408                  // copy event to internal event list                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
409                  if (pEvents->poolIsEmpty()) {                  ++iuiKey;
410                      dmsg(1,("Event pool emtpy!\n"));  
411                      break;                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
412                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
413                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
414                        if (!itVoice->Orphan) {
415                            itVoice->Orphan = true;
416                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
417                        }
418                  }                  }
                 *pEvents->allocAppend() = *pEvent;  
419              }              }
420              eventQueueReader.free(); // free all copied events from input queue              pDimRegionsInUse[i] = 0; // end of list
421    
422                // send a reply to the calling thread, which is waiting
423                instrument_change_reply_t reply;
424                InstrumentChangeReplyQueue->push(&reply);
425            }
426    
427            // handle events on all engine channels
428            for (int i = 0; i < engineChannels.size(); i++) {
429                ProcessEvents(engineChannels[i], Samples);
430            }
431    
432            // render all 'normal', active voices on all engine channels
433            for (int i = 0; i < engineChannels.size(); i++) {
434                RenderActiveVoices(engineChannels[i], Samples);
435            }
436    
437            // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
438            RenderStolenVoices(Samples);
439    
440            // handle audio routing for engine channels with FX sends
441            for (int i = 0; i < engineChannels.size(); i++) {
442                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
443                RouteAudio(engineChannels[i], Samples);
444            }
445    
446            // handle cleanup on all engine channels for the next audio fragment
447            for (int i = 0; i < engineChannels.size(); i++) {
448                PostProcess(engineChannels[i]);
449          }          }
450    
451    
452            // empty the engine's event list for the next audio fragment
453            ClearEventLists();
454    
455            // reset voice stealing for the next audio fragment
456            pVoiceStealingQueue->clear();
457    
458            // just some statistics about this engine instance
459            ActiveVoiceCount = ActiveVoiceCountTemp;
460            if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
461    
462            FrameTime += Samples;
463    
464            return 0;
465        }
466    
467        /**
468         * Dispatch and handle all events in this audio fragment for the given
469         * engine channel.
470         *
471         * @param pEngineChannel - engine channel on which events should be
472         *                         processed
473         * @param Samples        - amount of sample points to be processed in
474         *                         this audio fragment cycle
475         */
476        void Engine::ProcessEvents(EngineChannel* pEngineChannel, uint Samples) {
477            // get all events from the engine channels's input event queue which belong to the current fragment
478            // (these are the common events like NoteOn, NoteOff, ControlChange, etc.)
479            pEngineChannel->ImportEvents(Samples);
480    
481          // process events          // process events
482          {          {
483              RTList<Event>::Iterator itEvent = pEvents->first();              RTList<Event>::Iterator itEvent = pEngineChannel->pEvents->first();
484              RTList<Event>::Iterator end     = pEvents->end();              RTList<Event>::Iterator end     = pEngineChannel->pEvents->end();
485              for (; itEvent != end; ++itEvent) {              for (; itEvent != end; ++itEvent) {
486                  switch (itEvent->Type) {                  switch (itEvent->Type) {
487                      case Event::type_note_on:                      case Event::type_note_on:
488                          dmsg(5,("Engine: Note on received\n"));                          dmsg(5,("Engine: Note on received\n"));
489                          ProcessNoteOn(itEvent);                          ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
490                          break;                          break;
491                      case Event::type_note_off:                      case Event::type_note_off:
492                          dmsg(5,("Engine: Note off received\n"));                          dmsg(5,("Engine: Note off received\n"));
493                          ProcessNoteOff(itEvent);                          ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
494                          break;                          break;
495                      case Event::type_control_change:                      case Event::type_control_change:
496                          dmsg(5,("Engine: MIDI CC received\n"));                          dmsg(5,("Engine: MIDI CC received\n"));
497                          ProcessControlChange(itEvent);                          ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
498                          break;                          break;
499                      case Event::type_pitchbend:                      case Event::type_pitchbend:
500                          dmsg(5,("Engine: Pitchbend received\n"));                          dmsg(5,("Engine: Pitchbend received\n"));
501                          ProcessPitchbend(itEvent);                          ProcessPitchbend((EngineChannel*)itEvent->pEngineChannel, itEvent);
                         break;  
                     case Event::type_sysex:  
                         dmsg(5,("Engine: Sysex received\n"));  
                         ProcessSysex(itEvent);  
502                          break;                          break;
503                  }                  }
504              }              }
505          }          }
506    
507            // reset voice stealing for the next engine channel (or next audio fragment)
508            itLastStolenVoice         = RTList<Voice>::Iterator();
509            itLastStolenVoiceGlobally = RTList<Voice>::Iterator();
510            iuiLastStolenKey          = RTList<uint>::Iterator();
511            iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
512            pLastStolenChannel        = NULL;
513        }
514    
515          int active_voices = 0;      /**
516         * Render all 'normal' voices (that is voices which were not stolen in
517          // render audio from all active voices       * this fragment) on the given engine channel.
518          {       *
519              RTList<uint>::Iterator iuiKey = pActiveKeys->first();       * @param pEngineChannel - engine channel on which audio should be
520              RTList<uint>::Iterator end    = pActiveKeys->end();       *                         rendered
521              while (iuiKey != end) { // iterate through all active keys       * @param Samples        - amount of sample points to be rendered in
522                  midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];       *                         this audio fragment cycle
523                  ++iuiKey;       */
524        void Engine::RenderActiveVoices(EngineChannel* pEngineChannel, uint Samples) {
525                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();          #if !CONFIG_PROCESS_MUTED_CHANNELS
526                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
527                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key          #endif
528                      // now render current voice  
529                      itVoice->Render(Samples);          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
530                      if (itVoice->IsActive()) active_voices++; // still active          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
531                      else { // voice reached end, is now inactive          while (iuiKey != end) { // iterate through all active keys
532                          FreeVoice(itVoice); // remove voice from the list of active voices              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
533                      }              ++iuiKey;
534    
535                RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
536                RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
537                for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
538                    // now render current voice
539                    itVoice->Render(Samples);
540                    if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active
541                    else { // voice reached end, is now inactive
542                        FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
543                  }                  }
544              }              }
545          }          }
546        }
547    
548        /**
549         * Render all stolen voices (only voices which were stolen in this
550         * fragment) on the given engine channel. Stolen voices are rendered
551         * after all normal voices have been rendered; this is needed to render
552         * audio of those voices which were selected for voice stealing until
553         * the point were the stealing (that is the take over of the voice)
554         * actually happened.
555         *
556         * @param pEngineChannel - engine channel on which audio should be
557         *                         rendered
558         * @param Samples        - amount of sample points to be rendered in
559         *                         this audio fragment cycle
560         */
561        void Engine::RenderStolenVoices(uint Samples) {
562            RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();
563            RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
564            for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
565                EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
566                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
567                Pool<Voice>::Iterator itNewVoice =
568                    LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
569                if (itNewVoice) {
570                    itNewVoice->Render(Samples);
571                    if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active
572                    else { // voice reached end, is now inactive
573                        FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
574                    }
575                }
576                else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));
577    
578                // we need to clear the key's event list explicitly here in case key was never active
579                midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoiceStealEvent->Param.Note.Key];
580                pKey->VoiceTheftsQueued--;
581                if (!pKey->Active && !pKey->VoiceTheftsQueued) pKey->pEvents->clear();
582            }
583        }
584    
585          // now render all postponed voices from voice stealing      /**
586         * Will be called in case the respective engine channel sports FX send
587         * channels. In this particular case, engine channel local buffers are
588         * used to render and mix all voices to. This method is responsible for
589         * copying the audio data from those local buffers to the master audio
590         * output channels as well as to the FX send audio output channels with
591         * their respective FX send levels.
592         *
593         * @param pEngineChannel - engine channel from which audio should be
594         *                         routed
595         * @param Samples        - amount of sample points to be routed in
596         *                         this audio fragment cycle
597         */
598        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
599            // route master signal
600          {          {
601              RTList<Event>::Iterator itVoiceStealEvent = pVoiceStealingQueue->first();              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
602              RTList<Event>::Iterator end               = pVoiceStealingQueue->end();              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
603              for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {              pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
604                  Pool<Voice>::Iterator itNewVoice = LaunchVoice(itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false);              pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
605                  if (itNewVoice) {          }
606                      for (; itNewVoice; itNewVoice = itNewVoice->itChildVoice) {          // route FX send signal
607                          itNewVoice->Render(Samples);          {
608                          if (itNewVoice->IsActive()) active_voices++; // still active              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
609                          else { // voice reached end, is now inactive                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
610                              FreeVoice(itNewVoice); // remove voice from the list of active voices                  // left channel
611                          }                  const int iDstL = pFxSend->DestinationChannel(0);
612                      }                  if (iDstL < 0) {
613                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
614                    } else {
615                        AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
616                        if (!pDstL) {
617                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
618                        } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
619                    }
620                    // right channel
621                    const int iDstR = pFxSend->DestinationChannel(1);
622                    if (iDstR < 0) {
623                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
624                    } else {
625                        AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
626                        if (!pDstR) {
627                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
628                        } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
629                  }                  }
                 else dmsg(1,("gig::Engine: ERROR, voice stealing didn't work out!\n"));  
630              }              }
631          }          }
632          // reset voice stealing for the new fragment          // reset buffers with silence (zero out) for the next audio cycle
633          pVoiceStealingQueue->clear();          pEngineChannel->pChannelLeft->Clear();
634          itLastStolenVoice = RTList<Voice>::Iterator();          pEngineChannel->pChannelRight->Clear();
635          iuiLastStolenKey  = RTList<uint>::Iterator();      }
   
636    
637        /**
638         * Free all keys which have turned inactive in this audio fragment, from
639         * the list of active keys and clear all event lists on that engine
640         * channel.
641         *
642         * @param pEngineChannel - engine channel to cleanup
643         */
644        void Engine::PostProcess(EngineChannel* pEngineChannel) {
645          // free all keys which have no active voices left          // free all keys which have no active voices left
646          {          {
647              RTList<uint>::Iterator iuiKey = pActiveKeys->first();              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
648              RTList<uint>::Iterator end    = pActiveKeys->end();              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
649              while (iuiKey != end) { // iterate through all active keys              while (iuiKey != end) { // iterate through all active keys
650                  midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
651                  ++iuiKey;                  ++iuiKey;
652                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);                  if (pKey->pActiveVoices->isEmpty()) FreeKey(pEngineChannel, pKey);
653                  #if DEVMODE                  #if CONFIG_DEVMODE
654                  else { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging)                  else { // just a sanity check for debugging
655                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
656                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
657                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
# Line 549  namespace LinuxSampler { namespace gig { Line 660  namespace LinuxSampler { namespace gig {
660                          }                          }
661                      }                      }
662                  }                  }
663                  #endif // DEVMODE                  #endif // CONFIG_DEVMODE
664              }              }
665          }          }
666    
667            // empty the engine channel's own event lists
668          // 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!"));  
669      }      }
670    
671      /**      /**
# Line 636  namespace LinuxSampler { namespace gig { Line 679  namespace LinuxSampler { namespace gig {
679          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
680          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
681          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
682            event.pEngineChannel    = NULL; // as Engine global event
683          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
684              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
685                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 651  namespace LinuxSampler { namespace gig { Line 695  namespace LinuxSampler { namespace gig {
695                  // finally place sysex event into input event queue                  // finally place sysex event into input event queue
696                  pEventQueue->push(&event);                  pEventQueue->push(&event);
697              }              }
698              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));
699          }          }
700          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
701      }      }
# Line 659  namespace LinuxSampler { namespace gig { Line 703  namespace LinuxSampler { namespace gig {
703      /**      /**
704       *  Assigns and triggers a new voice for the respective MIDI key.       *  Assigns and triggers a new voice for the respective MIDI key.
705       *       *
706         *  @param pEngineChannel - engine channel on which this event occured on
707       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
708       */       */
709      void Engine::ProcessNoteOn(Pool<Event>::Iterator& itNoteOnEvent) {      void Engine::ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
710          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
711            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
712            #endif
713    
714            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
715    
716            //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
717            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
718    
719            const int key = itNoteOnEvent->Param.Note.Key;
720            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
721    
722            // move note on event to the key's own event list
723            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
724    
725            // if Solo Mode then kill all already active voices
726            if (pEngineChannel->SoloMode) {
727                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
728                if (itYoungestKey) {
729                    const int iYoungestKey = *itYoungestKey;
730                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
731                    if (pOtherKey->Active) {
732                        // get final portamento position of currently active voice
733                        if (pEngineChannel->PortamentoMode) {
734                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
735                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
736                        }
737                        // kill all voices on the (other) key
738                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
739                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
740                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
741                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
742                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
743                        }
744                    }
745                }
746                // set this key as 'currently active solo key'
747                pEngineChannel->SoloKey = key;
748            }
749    
750            // Change key dimension value if key is in keyswitching area
751            {
752                const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
753                if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
754                    pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
755                        (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
756            }
757    
758          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
759            pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
760            pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
761    
762          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
763          if (pKey->Active && !SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
764              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
765              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
766                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
767                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
768              }              }
769              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
770          }          }
771    
772          // move note on event to the key's own event list          // allocate and trigger new voice(s) for the key
773          RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);          {
774                // first, get total amount of required voices (dependant on amount of layers)
775                ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
776                if (pRegion) {
777                    int voicesRequired = pRegion->Layers;
778                    // now launch the required amount of voices
779                    for (int i = 0; i < voicesRequired; i++)
780                        LaunchVoice(pEngineChannel, itNoteOnEventOnKeyList, i, false, true, true);
781                }
782            }
783    
784            // if neither a voice was spawned or postponed then remove note on event from key again
785            if (!pKey->Active && !pKey->VoiceTheftsQueued)
786                pKey->pEvents->free(itNoteOnEventOnKeyList);
787    
788          // allocate and trigger a new voice for the key          if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
789          LaunchVoice(itNoteOnEventOnKeyList, 0, false, true);          pKey->RoundRobinIndex++;
790      }      }
791    
792      /**      /**
# Line 689  namespace LinuxSampler { namespace gig { Line 795  namespace LinuxSampler { namespace gig {
795       *  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.
796       *  due to completion of sample playback).       *  due to completion of sample playback).
797       *       *
798         *  @param pEngineChannel - engine channel on which this event occured on
799       *  @param itNoteOffEvent - key, velocity and time stamp of the event       *  @param itNoteOffEvent - key, velocity and time stamp of the event
800       */       */
801      void Engine::ProcessNoteOff(Pool<Event>::Iterator& itNoteOffEvent) {      void Engine::ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
802          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          #if !CONFIG_PROCESS_MUTED_CHANNELS
803            if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
804            #endif
805    
806          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
807            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
808    
809          // release voices on this key if needed          const int iKey = itNoteOffEvent->Param.Note.Key;
810          if (pKey->Active && !SustainPedal) {          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
811              itNoteOffEvent->Type = Event::type_release; // transform event type          pKey->KeyPressed = false; // the MIDI key was now released
         }  
812    
813          // move event to the key's own event list          // move event to the key's own event list
814          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
815    
816          // spawn release triggered voice(s) if needed          bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
817          if (pKey->ReleaseTrigger) {  
818              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)
819              pKey->ReleaseTrigger = false;          if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
820                bool bOtherKeysPressed = false;
821                if (iKey == pEngineChannel->SoloKey) {
822                    pEngineChannel->SoloKey = -1;
823                    // if there's still a key pressed down, respawn a voice (group) on the highest key
824                    for (int i = 127; i > 0; i--) {
825                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
826                        if (pOtherKey->KeyPressed) {
827                            bOtherKeysPressed = true;
828                            // make the other key the new 'currently active solo key'
829                            pEngineChannel->SoloKey = i;
830                            // get final portamento position of currently active voice
831                            if (pEngineChannel->PortamentoMode) {
832                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
833                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
834                            }
835                            // create a pseudo note on event
836                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
837                            if (itPseudoNoteOnEvent) {
838                                // copy event
839                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
840                                // transform event to a note on event
841                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
842                                itPseudoNoteOnEvent->Param.Note.Key      = i;
843                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
844                                // allocate and trigger new voice(s) for the other key
845                                {
846                                    // first, get total amount of required voices (dependant on amount of layers)
847                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
848                                    if (pRegion) {
849                                        int voicesRequired = pRegion->Layers;
850                                        // now launch the required amount of voices
851                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
852                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
853                                    }
854                                }
855                                // if neither a voice was spawned or postponed then remove note on event from key again
856                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
857                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
858    
859                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
860                            break; // done
861                        }
862                    }
863                }
864                if (bOtherKeysPressed) {
865                    if (pKey->Active) { // kill all voices on this key
866                        bShouldRelease = false; // no need to release, as we kill it here
867                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
868                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
869                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
870                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
871                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
872                        }
873                    }
874                } else pEngineChannel->PortamentoPos = -1.0f;
875          }          }
876    
877            // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
878            if (bShouldRelease) {
879                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
880    
881                // spawn release triggered voice(s) if needed
882                if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
883                    // first, get total amount of required voices (dependant on amount of layers)
884                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
885                    if (pRegion) {
886                        int voicesRequired = pRegion->Layers;
887    
888                        // MIDI note-on velocity is used instead of note-off velocity
889                        itNoteOffEventOnKeyList->Param.Note.Velocity = pKey->Velocity;
890    
891                        // now launch the required amount of voices
892                        for (int i = 0; i < voicesRequired; i++)
893                            LaunchVoice(pEngineChannel, itNoteOffEventOnKeyList, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
894                    }
895                    pKey->ReleaseTrigger = false;
896                }
897            }
898    
899            // if neither a voice was spawned or postponed on this key then remove note off event from key again
900            if (!pKey->Active && !pKey->VoiceTheftsQueued)
901                pKey->pEvents->free(itNoteOffEventOnKeyList);
902      }      }
903    
904      /**      /**
905       *  Moves pitchbend event from the general (input) event list to the pitch       *  Moves pitchbend event from the general (input) event list to the engine
906       *  event list.       *  channel's event list. It will actually processed later by the
907         *  respective voice.
908       *       *
909         *  @param pEngineChannel - engine channel on which this event occured on
910       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event       *  @param itPitchbendEvent - absolute pitch value and time stamp of the event
911       */       */
912      void Engine::ProcessPitchbend(Pool<Event>::Iterator& itPitchbendEvent) {      void Engine::ProcessPitchbend(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itPitchbendEvent) {
913          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]);  
914      }      }
915    
916      /**      /**
# Line 727  namespace LinuxSampler { namespace gig { Line 918  namespace LinuxSampler { namespace gig {
918       *  called by the ProcessNoteOn() method and by the voices itself       *  called by the ProcessNoteOn() method and by the voices itself
919       *  (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).
920       *       *
921         *  @param pEngineChannel      - engine channel on which this event occured on
922       *  @param itNoteOnEvent       - key, velocity and time stamp of the event       *  @param itNoteOnEvent       - key, velocity and time stamp of the event
923       *  @param iLayer              - layer index for the new voice (optional - only       *  @param iLayer              - layer index for the new voice (optional - only
924       *                               in case of layered sounds of course)       *                               in case of layered sounds of course)
# Line 735  namespace LinuxSampler { namespace gig { Line 927  namespace LinuxSampler { namespace gig {
927       *  @param VoiceStealing       - if voice stealing should be performed       *  @param VoiceStealing       - if voice stealing should be performed
928       *                               when there is no free voice       *                               when there is no free voice
929       *                               (optional, default = true)       *                               (optional, default = true)
930         *  @param HandleKeyGroupConflicts - if voices should be killed due to a
931         *                                   key group conflict
932       *  @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
933       *           if an error occured while trying to trigger the new voice       *           if the voice wasn't triggered (for example when no region is
934         *           defined for the given key).
935       */       */
936      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) {
937          midi_key_info_t* pKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];          int MIDIKey            = itNoteOnEvent->Param.Note.Key;
938            midi_key_info_t* pKey  = &pEngineChannel->pMIDIKeyInfo[MIDIKey];
939            ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(MIDIKey);
940    
941            // if nothing defined for this key
942            if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
943    
944            // only mark the first voice of a layered voice (group) to be in a
945            // key group, so the layered voices won't kill each other
946            int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
947    
948            // handle key group (a.k.a. exclusive group) conflicts
949            if (HandleKeyGroupConflicts) {
950                if (iKeyGroup) { // if this voice / key belongs to a key group
951                    uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[iKeyGroup];
952                    if (*ppKeyGroup) { // if there's already an active key in that key group
953                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[**ppKeyGroup];
954                        // kill all voices on the (other) key
955                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
956                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
957                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
958                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
959                                itVoiceToBeKilled->Kill(itNoteOnEvent);
960                                --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
961                            }
962                        }
963                    }
964                }
965            }
966    
967            Voice::type_t VoiceType = Voice::type_normal;
968    
969            // get current dimension values to select the right dimension region
970            //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
971            //FIXME: controller values for selecting the dimension region here are currently not sample accurate
972            uint DimValues[8] = { 0 };
973            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
974                switch (pRegion->pDimensionDefinitions[i].dimension) {
975                    case ::gig::dimension_samplechannel:
976                        DimValues[i] = 0; //TODO: we currently ignore this dimension
977                        break;
978                    case ::gig::dimension_layer:
979                        DimValues[i] = iLayer;
980                        break;
981                    case ::gig::dimension_velocity:
982                        DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
983                        break;
984                    case ::gig::dimension_channelaftertouch:
985                        DimValues[i] = pEngineChannel->ControllerTable[128];
986                        break;
987                    case ::gig::dimension_releasetrigger:
988                        VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
989                        DimValues[i] = (uint) ReleaseTriggerVoice;
990                        break;
991                    case ::gig::dimension_keyboard:
992                        DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
993                        break;
994                    case ::gig::dimension_roundrobin:
995                        DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
996                        break;
997                    case ::gig::dimension_random:
998                        RandomSeed   = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
999                        DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
1000                        break;
1001                    case ::gig::dimension_modwheel:
1002                        DimValues[i] = pEngineChannel->ControllerTable[1];
1003                        break;
1004                    case ::gig::dimension_breath:
1005                        DimValues[i] = pEngineChannel->ControllerTable[2];
1006                        break;
1007                    case ::gig::dimension_foot:
1008                        DimValues[i] = pEngineChannel->ControllerTable[4];
1009                        break;
1010                    case ::gig::dimension_portamentotime:
1011                        DimValues[i] = pEngineChannel->ControllerTable[5];
1012                        break;
1013                    case ::gig::dimension_effect1:
1014                        DimValues[i] = pEngineChannel->ControllerTable[12];
1015                        break;
1016                    case ::gig::dimension_effect2:
1017                        DimValues[i] = pEngineChannel->ControllerTable[13];
1018                        break;
1019                    case ::gig::dimension_genpurpose1:
1020                        DimValues[i] = pEngineChannel->ControllerTable[16];
1021                        break;
1022                    case ::gig::dimension_genpurpose2:
1023                        DimValues[i] = pEngineChannel->ControllerTable[17];
1024                        break;
1025                    case ::gig::dimension_genpurpose3:
1026                        DimValues[i] = pEngineChannel->ControllerTable[18];
1027                        break;
1028                    case ::gig::dimension_genpurpose4:
1029                        DimValues[i] = pEngineChannel->ControllerTable[19];
1030                        break;
1031                    case ::gig::dimension_sustainpedal:
1032                        DimValues[i] = pEngineChannel->ControllerTable[64];
1033                        break;
1034                    case ::gig::dimension_portamento:
1035                        DimValues[i] = pEngineChannel->ControllerTable[65];
1036                        break;
1037                    case ::gig::dimension_sostenutopedal:
1038                        DimValues[i] = pEngineChannel->ControllerTable[66];
1039                        break;
1040                    case ::gig::dimension_softpedal:
1041                        DimValues[i] = pEngineChannel->ControllerTable[67];
1042                        break;
1043                    case ::gig::dimension_genpurpose5:
1044                        DimValues[i] = pEngineChannel->ControllerTable[80];
1045                        break;
1046                    case ::gig::dimension_genpurpose6:
1047                        DimValues[i] = pEngineChannel->ControllerTable[81];
1048                        break;
1049                    case ::gig::dimension_genpurpose7:
1050                        DimValues[i] = pEngineChannel->ControllerTable[82];
1051                        break;
1052                    case ::gig::dimension_genpurpose8:
1053                        DimValues[i] = pEngineChannel->ControllerTable[83];
1054                        break;
1055                    case ::gig::dimension_effect1depth:
1056                        DimValues[i] = pEngineChannel->ControllerTable[91];
1057                        break;
1058                    case ::gig::dimension_effect2depth:
1059                        DimValues[i] = pEngineChannel->ControllerTable[92];
1060                        break;
1061                    case ::gig::dimension_effect3depth:
1062                        DimValues[i] = pEngineChannel->ControllerTable[93];
1063                        break;
1064                    case ::gig::dimension_effect4depth:
1065                        DimValues[i] = pEngineChannel->ControllerTable[94];
1066                        break;
1067                    case ::gig::dimension_effect5depth:
1068                        DimValues[i] = pEngineChannel->ControllerTable[95];
1069                        break;
1070                    case ::gig::dimension_none:
1071                        std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
1072                        break;
1073                    default:
1074                        std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1075                }
1076            }
1077    
1078            // return if this is a release triggered voice and there is no
1079            // releasetrigger dimension (could happen if an instrument
1080            // change has occured between note on and off)
1081            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1082    
1083            ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1084    
1085            // no need to continue if sample is silent
1086            if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
1087    
1088          // allocate a new voice for the key          // allocate a new voice for the key
1089          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();          Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
1090          if (itNewVoice) {          if (itNewVoice) {
1091              // launch the new voice              // launch the new voice
1092              if (itNewVoice->Trigger(itNoteOnEvent, this->Pitch, this->pInstrument, iLayer, ReleaseTriggerVoice, VoiceStealing) < 0) {              if (itNewVoice->Trigger(pEngineChannel, itNoteOnEvent, pEngineChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
1093                  dmsg(1,("Triggering new voice failed!\n"));                  dmsg(4,("Voice not triggered\n"));
1094                  pKey->pActiveVoices->free(itNewVoice);                  pKey->pActiveVoices->free(itNewVoice);
1095              }              }
1096              else { // on success              else { // on success
1097                  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);  
                         }  
                     }  
                 }  
1098                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
1099                      pKey->Active = true;                      pKey->Active = true;
1100                      pKey->itSelf = pActiveKeys->allocAppend();                      pKey->itSelf = pEngineChannel->pActiveKeys->allocAppend();
1101                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                      *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
1102                  }                  }
1103                  if (itNewVoice->KeyGroup) {                  if (itNewVoice->KeyGroup) {
1104                        uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
1105                      *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
1106                  }                  }
1107                  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 776  namespace LinuxSampler { namespace gig { Line 1109  namespace LinuxSampler { namespace gig {
1109              }              }
1110          }          }
1111          else if (VoiceStealing) {          else if (VoiceStealing) {
1112              // first, get total amount of required voices (dependant on amount of layers)              // try to steal one voice
1113              ::gig::Region* pRegion = pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);              int result = StealVoice(pEngineChannel, itNoteOnEvent);
1114              if (!pRegion) return Pool<Voice>::Iterator(); // nothing defined for this MIDI key, so no voice needed              if (!result) { // voice stolen successfully
1115              int voicesRequired = pRegion->Layers;                  // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
1116                    RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
1117              // now steal the (remaining) amount of voices                  if (itStealEvent) {
1118              for (int i = iLayer; i < voicesRequired; i++)                      *itStealEvent = *itNoteOnEvent; // copy event
1119                  StealVoice(itNoteOnEvent);                      itStealEvent->Param.Note.Layer = iLayer;
1120                        itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
1121              // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died                      pKey->VoiceTheftsQueued++;
1122              RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();                  }
1123              if (itStealEvent) {                  else dmsg(1,("Voice stealing queue full!\n"));
                 *itStealEvent = *itNoteOnEvent; // copy event  
                 itStealEvent->Param.Note.Layer = iLayer;  
                 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;  
1124              }              }
             else dmsg(1,("Voice stealing queue full!\n"));  
1125          }          }
1126    
1127          return Pool<Voice>::Iterator(); // no free voice or error          return Pool<Voice>::Iterator(); // no free voice or error
# Line 804  namespace LinuxSampler { namespace gig { Line 1133  namespace LinuxSampler { namespace gig {
1133       *  voice stealing and postpone the note-on event until the selected       *  voice stealing and postpone the note-on event until the selected
1134       *  voice actually died.       *  voice actually died.
1135       *       *
1136         *  @param pEngineChannel - engine channel on which this event occured on
1137       *  @param itNoteOnEvent - key, velocity and time stamp of the event       *  @param itNoteOnEvent - key, velocity and time stamp of the event
1138         *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1139       */       */
1140      void Engine::StealVoice(Pool<Event>::Iterator& itNoteOnEvent) {      int Engine::StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1141            if (VoiceSpawnsLeft <= 0) {
1142                dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1143                return -1;
1144            }
1145          if (!pEventPool->poolIsEmpty()) {          if (!pEventPool->poolIsEmpty()) {
1146    
1147              RTList<uint>::Iterator  iuiOldestKey;              RTList<Voice>::Iterator itSelectedVoice;
             RTList<Voice>::Iterator itOldestVoice;  
1148    
1149              // Select one voice for voice stealing              // Select one voice for voice stealing
1150              switch (VOICE_STEAL_ALGORITHM) {              switch (CONFIG_VOICE_STEAL_ALGO) {
1151    
1152                  // try to pick the oldest voice on the key where the new                  // try to pick the oldest voice on the key where the new
1153                  // voice should be spawned, if there is no voice on that                  // voice should be spawned, if there is no voice on that
1154                  // key, or no voice left to kill there, then procceed with                  // key, or no voice left to kill, then procceed with
1155                  // 'oldestkey' algorithm                  // 'oldestkey' algorithm
1156                  case voice_steal_algo_keymask: {                  case voice_steal_algo_oldestvoiceonkey: {
1157                      midi_key_info_t* pOldestKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                      midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
1158                      if (itLastStolenVoice) {                      itSelectedVoice = pSelectedKey->pActiveVoices->first();
1159                          itOldestVoice = itLastStolenVoice;                      // proceed iterating if voice was created in this fragment cycle
1160                          ++itOldestVoice;                      while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1161                      }                      // if we haven't found a voice then proceed with algorithm 'oldestkey'
1162                      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  
                     }  
1163                  } // no break - intentional !                  } // no break - intentional !
1164    
1165                  // try to pick the oldest voice on the oldest active key                  // try to pick the oldest voice on the oldest active key
1166                  // (caution: must stay after 'keymask' algorithm !)                  // from the same engine channel
1167                    // (caution: must stay after 'oldestvoiceonkey' algorithm !)
1168                  case voice_steal_algo_oldestkey: {                  case voice_steal_algo_oldestkey: {
1169                      if (itLastStolenVoice) {                      // if we already stole in this fragment, try to proceed on same key
1170                          midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiLastStolenKey];                      if (this->itLastStolenVoice) {
1171                          itOldestVoice = itLastStolenVoice;                          itSelectedVoice = this->itLastStolenVoice;
1172                          ++itOldestVoice;                          do {
1173                          if (!itOldestVoice) {                              ++itSelectedVoice;
1174                              iuiOldestKey = iuiLastStolenKey;                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1175                              ++iuiOldestKey;                          // found a "stealable" voice ?
1176                              if (iuiOldestKey) {                          if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1177                                  midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];                              // remember which voice we stole, so we can simply proceed on next voice stealing
1178                                  itOldestVoice = pOldestKey->pActiveVoices->first();                              this->itLastStolenVoice = itSelectedVoice;
1179                              }                              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;  
                             }  
1180                          }                          }
                         else iuiOldestKey = iuiLastStolenKey;  
1181                      }                      }
1182                      else { // no voice stolen in this audio fragment cycle yet                      // get (next) oldest key
1183                          iuiOldestKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKey) ? ++this->iuiLastStolenKey : pEngineChannel->pActiveKeys->first();
1184                          midi_key_info_t* pOldestKey = &pMIDIKeyInfo[*iuiOldestKey];                      while (iuiSelectedKey) {
1185                          itOldestVoice = pOldestKey->pActiveVoices->first();                          midi_key_info_t* pSelectedKey = &pEngineChannel->pMIDIKeyInfo[*iuiSelectedKey];
1186                            itSelectedVoice = pSelectedKey->pActiveVoices->first();
1187                            // proceed iterating if voice was created in this fragment cycle
1188                            while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1189                            // found a "stealable" voice ?
1190                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1191                                // remember which voice on which key we stole, so we can simply proceed on next voice stealing
1192                                this->iuiLastStolenKey  = iuiSelectedKey;
1193                                this->itLastStolenVoice = itSelectedVoice;
1194                                break; // selection succeeded
1195                            }
1196                            ++iuiSelectedKey; // get next oldest key
1197                      }                      }
1198                      break;                      break;
1199                  }                  }
# Line 867  namespace LinuxSampler { namespace gig { Line 1202  namespace LinuxSampler { namespace gig {
1202                  case voice_steal_algo_none:                  case voice_steal_algo_none:
1203                  default: {                  default: {
1204                      dmsg(1,("No free voice (voice stealing disabled)!\n"));                      dmsg(1,("No free voice (voice stealing disabled)!\n"));
1205                      return;                      return -1;
1206                    }
1207                }
1208    
1209                // if we couldn't steal a voice from the same engine channel then
1210                // steal oldest voice on the oldest key from any other engine channel
1211                // (the smaller engine channel number, the higher priority)
1212                if (!itSelectedVoice || !itSelectedVoice->IsStealable()) {
1213                    EngineChannel* pSelectedChannel;
1214                    int            iChannelIndex;
1215                    // select engine channel
1216                    if (pLastStolenChannel) {
1217                        pSelectedChannel = pLastStolenChannel;
1218                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1219                    } else { // pick the engine channel followed by this engine channel
1220                        iChannelIndex    = (pEngineChannel->iEngineIndexSelf + 1) % engineChannels.size();
1221                        pSelectedChannel = engineChannels[iChannelIndex];
1222                    }
1223    
1224                    // if we already stole in this fragment, try to proceed on same key
1225                    if (this->itLastStolenVoiceGlobally) {
1226                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1227                        do {
1228                            ++itSelectedVoice;
1229                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1230                    }
1231    
1232                    #if CONFIG_DEVMODE
1233                    EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1234                    #endif // CONFIG_DEVMODE
1235    
1236                    // did we find a 'stealable' voice?
1237                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1238                        // remember which voice we stole, so we can simply proceed on next voice stealing
1239                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1240                    } else while (true) { // iterate through engine channels
1241                        // get (next) oldest key
1242                        RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1243                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1244                        while (iuiSelectedKey) {
1245                            midi_key_info_t* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1246                            itSelectedVoice = pSelectedKey->pActiveVoices->first();
1247                            // proceed iterating if voice was created in this fragment cycle
1248                            while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1249                            // found a "stealable" voice ?
1250                            if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1251                                // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1252                                this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1253                                this->itLastStolenVoiceGlobally = itSelectedVoice;
1254                                this->pLastStolenChannel        = pSelectedChannel;
1255                                goto stealable_voice_found; // selection succeeded
1256                            }
1257                            ++iuiSelectedKey; // get next key on current engine channel
1258                        }
1259                        // get next engine channel
1260                        iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1261                        pSelectedChannel = engineChannels[iChannelIndex];
1262    
1263                        #if CONFIG_DEVMODE
1264                        if (pSelectedChannel == pBegin) {
1265                            dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1266                            dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1267                            dmsg(1,("Exiting.\n"));
1268                            exit(-1);
1269                        }
1270                        #endif // CONFIG_DEVMODE
1271                  }                  }
1272              }              }
1273    
1274              //FIXME: can be removed, just a sanity check for debugging              // jump point if a 'stealable' voice was found
1275              if (!itOldestVoice->IsActive()) dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));              stealable_voice_found:
1276    
1277                #if CONFIG_DEVMODE
1278                if (!itSelectedVoice->IsActive()) {
1279                    dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
1280                    return -1;
1281                }
1282                #endif // CONFIG_DEVMODE
1283    
1284              // now kill the selected voice              // now kill the selected voice
1285              itOldestVoice->Kill(itNoteOnEvent);              itSelectedVoice->Kill(itNoteOnEvent);
1286              // remember which voice on which key we stole, so we can simply proceed for the next voice stealing  
1287              this->itLastStolenVoice = itOldestVoice;              --VoiceSpawnsLeft;
1288              this->iuiLastStolenKey = iuiOldestKey;  
1289                return 0; // success
1290            }
1291            else {
1292                dmsg(1,("Event pool emtpy!\n"));
1293                return -1;
1294          }          }
         else dmsg(1,("Event pool emtpy!\n"));  
1295      }      }
1296    
1297      /**      /**
# Line 889  namespace LinuxSampler { namespace gig { Line 1300  namespace LinuxSampler { namespace gig {
1300       *  it finished to playback its sample, finished its release stage or       *  it finished to playback its sample, finished its release stage or
1301       *  just was killed.       *  just was killed.
1302       *       *
1303         *  @param pEngineChannel - engine channel on which this event occured on
1304       *  @param itVoice - points to the voice to be freed       *  @param itVoice - points to the voice to be freed
1305       */       */
1306      void Engine::FreeVoice(Pool<Voice>::Iterator& itVoice) {      void Engine::FreeVoice(EngineChannel* pEngineChannel, Pool<Voice>::Iterator& itVoice) {
1307          if (itVoice) {          if (itVoice) {
1308              midi_key_info_t* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itVoice->MIDIKey];
1309    
1310              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1311    
1312                // if the sample and dimension region belong to an
1313                // instrument that is unloaded, tell the disk thread to
1314                // release them
1315                if (itVoice->Orphan) {
1316                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1317                }
1318    
1319              // free the voice object              // free the voice object
1320              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1321    
1322              // 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
1323              if (pKey->pActiveVoices->isEmpty() && keygroup) {              if (pKey->pActiveVoices->isEmpty() && keygroup) {
1324                  uint** ppKeyGroup = &ActiveKeyGroups[keygroup];                  uint** ppKeyGroup = &pEngineChannel->ActiveKeyGroups[keygroup];
1325                  if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group                  if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
1326              }              }
1327          }          }
# Line 913  namespace LinuxSampler { namespace gig { Line 1332  namespace LinuxSampler { namespace gig {
1332       *  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
1333       *  update the key info respectively.       *  update the key info respectively.
1334       *       *
1335         *  @param pEngineChannel - engine channel on which this event occured on
1336       *  @param pKey - key which is now inactive       *  @param pKey - key which is now inactive
1337       */       */
1338      void Engine::FreeKey(midi_key_info_t* pKey) {      void Engine::FreeKey(EngineChannel* pEngineChannel, midi_key_info_t* pKey) {
1339          if (pKey->pActiveVoices->isEmpty()) {          if (pKey->pActiveVoices->isEmpty()) {
1340              pKey->Active = false;              pKey->Active = false;
1341              pActiveKeys->free(pKey->itSelf); // remove key from list of active keys              pEngineChannel->pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
1342              pKey->itSelf = RTList<uint>::Iterator();              pKey->itSelf = RTList<uint>::Iterator();
1343              pKey->ReleaseTrigger = false;              pKey->ReleaseTrigger = false;
1344              pKey->pEvents->clear();              pKey->pEvents->clear();
# Line 931  namespace LinuxSampler { namespace gig { Line 1351  namespace LinuxSampler { namespace gig {
1351       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
1352       *  modulation wheel, aftertouch).       *  modulation wheel, aftertouch).
1353       *       *
1354         *  @param pEngineChannel - engine channel on which this event occured on
1355       *  @param itControlChangeEvent - controller, value and time stamp of the event       *  @param itControlChangeEvent - controller, value and time stamp of the event
1356       */       */
1357      void Engine::ProcessControlChange(Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1358          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));
1359    
1360            // update controller value in the engine channel's controller table
1361            pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1362    
1363            // handle hard coded MIDI controllers
1364          switch (itControlChangeEvent->Param.CC.Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
1365              case 64: {              case 5: { // portamento time
1366                  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;
1367                      dmsg(4,("PEDAL DOWN\n"));                  break;
1368                      SustainPedal = true;              }
1369                case 6: { // data entry (currently only used for RPN controllers)
1370                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1371                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1372                        // limit to +- two octaves for now
1373                        transpose = RTMath::Min(transpose,  24);
1374                        transpose = RTMath::Max(transpose, -24);
1375                        pEngineChannel->GlobalTranspose = transpose;
1376                        // workaround, so we won't have hanging notes
1377                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1378                    }
1379                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1380                    pEngineChannel->ResetMidiRpnController();
1381                    break;
1382                }
1383                case 7: { // volume
1384                    //TODO: not sample accurate yet
1385                    pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1386                    pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1387                    break;
1388                }
1389                case 10: { // panpot
1390                    //TODO: not sample accurate yet
1391                    pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1392                    pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1393                    break;
1394                }
1395                case 64: { // sustain
1396                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1397                        dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1398                        pEngineChannel->SustainPedal = true;
1399    
1400                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1401                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1402                        #endif
1403    
1404                      // cancel release process of voices if necessary                      // cancel release process of voices if necessary
1405                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1406                      if (iuiKey) {                      for (; iuiKey; ++iuiKey) {
1407                          itControlChangeEvent->Type = Event::type_cancel_release; // transform event type                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1408                          while (iuiKey) {                          if (!pKey->KeyPressed) {
1409                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1410                              ++iuiKey;                              if (itNewEvent) {
1411                              if (!pKey->KeyPressed) {                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1412                                  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"));  
1413                              }                              }
1414                                else dmsg(1,("Event pool emtpy!\n"));
1415                          }                          }
1416                      }                      }
1417                  }                  }
1418                  if (itControlChangeEvent->Param.CC.Value < 64 && SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1419                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1420                      SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1421    
1422                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1423                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1424                        #endif
1425    
1426                      // release voices if their respective key is not pressed                      // release voices if their respective key is not pressed
1427                      RTList<uint>::Iterator iuiKey = pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1428                      if (iuiKey) {                      for (; iuiKey; ++iuiKey) {
1429                          itControlChangeEvent->Type = Event::type_release; // transform event type                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1430                          while (iuiKey) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1431                              midi_key_info_t* pKey = &pMIDIKeyInfo[*iuiKey];                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1432                              ++iuiKey;                              if (itNewEvent) {
1433                              if (!pKey->KeyPressed) {                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1434                                  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"));  
1435                              }                              }
1436                                else dmsg(1,("Event pool emtpy!\n"));
1437                          }                          }
1438                      }                      }
1439                  }                  }
1440                  break;                  break;
1441              }              }
1442          }              case 65: { // portamento on / off
1443                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1444                    pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64;
1445                    break;
1446                }
1447                case 66: { // sostenuto
1448                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1449                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1450                        pEngineChannel->SostenutoPedal = true;
1451    
1452                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1453                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1454                        #endif
1455    
1456                        SostenutoKeyCount = 0;
1457                        // Remeber the pressed keys
1458                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1459                        for (; iuiKey; ++iuiKey) {
1460                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1461                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1462                        }
1463                    }
1464                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1465                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1466                        pEngineChannel->SostenutoPedal = false;
1467    
1468                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1469                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1470                        #endif
1471    
1472                        // release voices if the damper pedal is up and their respective key is not pressed
1473                        for (int i = 0; i < SostenutoKeyCount; i++) {
1474                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1475                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1476                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1477                                if (itNewEvent) {
1478                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1479                                    itNewEvent->Type = Event::type_release; // transform event type
1480                                }
1481                                else dmsg(1,("Event pool emtpy!\n"));
1482                            }
1483                        }
1484                    }
1485                    break;
1486                }
1487                case 100: { // RPN controller LSB
1488                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1489                    break;
1490                }
1491                case 101: { // RPN controller MSB
1492                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1493                    break;
1494                }
1495    
1496    
1497                // Channel Mode Messages
1498    
1499          // update controller value in the engine's controller table              case 120: { // all sound off
1500          ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;                  KillAllVoices(pEngineChannel, itControlChangeEvent);
1501                    break;
1502                }
1503                case 121: { // reset all controllers
1504                    pEngineChannel->ResetControllers();
1505                    break;
1506                }
1507                case 123: { // all notes off
1508                    #if CONFIG_PROCESS_ALL_NOTES_OFF
1509                    ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1510                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1511                    break;
1512                }
1513                case 126: { // mono mode on
1514                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1515                    pEngineChannel->SoloMode = true;
1516                    break;
1517                }
1518                case 127: { // poly mode on
1519                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1520                    pEngineChannel->SoloMode = false;
1521                    break;
1522                }
1523            }
1524    
1525          // move event from the unsorted event list to the control change event list          // handle FX send controllers
1526          itControlChangeEvent.moveToEndOf(pCCEvents);          if (!pEngineChannel->fxSends.empty()) {
1527                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1528                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1529                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1530                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1531                        pFxSend->SetInfoChanged(true);
1532                }
1533            }
1534      }      }
1535    
1536      /**      /**
# Line 993  namespace LinuxSampler { namespace gig { Line 1539  namespace LinuxSampler { namespace gig {
1539       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1540       */       */
1541      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1542          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1543    
1544          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1545          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1002  namespace LinuxSampler { namespace gig { Line 1548  namespace LinuxSampler { namespace gig {
1548    
1549          switch (id) {          switch (id) {
1550              case 0x41: { // Roland              case 0x41: { // Roland
1551                    dmsg(3,("Roland Sysex\n"));
1552                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
1553                  if (!reader.pop(&device_id)) goto free_sysex_data;                  if (!reader.pop(&device_id)) goto free_sysex_data;
1554                  if (!reader.pop(&model_id))  goto free_sysex_data;                  if (!reader.pop(&model_id))  goto free_sysex_data;
# Line 1011  namespace LinuxSampler { namespace gig { Line 1558  namespace LinuxSampler { namespace gig {
1558    
1559                  // command address                  // command address
1560                  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)
1561                  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
1562                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1563                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1564                        dmsg(3,("\tSystem Parameter\n"));
1565                  }                  }
1566                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1567                        dmsg(3,("\tCommon Parameter\n"));
1568                  }                  }
1569                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
1570                      switch (addr[3]) {                      dmsg(3,("\tPart Parameter\n"));
1571                        switch (addr[2]) {
1572                          case 0x40: { // scale tuning                          case 0x40: { // scale tuning
1573                                dmsg(3,("\t\tScale Tuning\n"));
1574                              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
1575                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;                              if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
1576                              uint8_t checksum;                              uint8_t checksum;
1577                              if (!reader.pop(&checksum))                      goto free_sysex_data;                              if (!reader.pop(&checksum)) goto free_sysex_data;
1578                              if (GSCheckSum(checksum_reader, 12) != checksum) goto free_sysex_data;                              #if CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1579                                if (GSCheckSum(checksum_reader, 12)) goto free_sysex_data;
1580                                #endif // CONFIG_ASSERT_GS_SYSEX_CHECKSUM
1581                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;                              for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
1582                              AdjustScale((int8_t*) scale_tunes);                              AdjustScale((int8_t*) scale_tunes);
1583                                dmsg(3,("\t\t\tNew scale applied.\n"));
1584                              break;                              break;
1585                          }                          }
1586                      }                      }
# Line 1051  namespace LinuxSampler { namespace gig { Line 1605  namespace LinuxSampler { namespace gig {
1605       *                     question       *                     question
1606       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1607       */       */
1608      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) {
1609          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1610          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1611          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1612          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1071  namespace LinuxSampler { namespace gig { Line 1625  namespace LinuxSampler { namespace gig {
1625      }      }
1626    
1627      /**      /**
1628       * Initialize the parameter sequence for the modulation destination given by       * Releases all voices on an engine channel. All voices will go into
1629       * by 'dst' with the constant value given by val.       * the release stage and thus it might take some time (e.g. dependant to
1630         * their envelope release time) until they actually die.
1631         *
1632         * @param pEngineChannel - engine channel on which all voices should be released
1633         * @param itReleaseEvent - event which caused this releasing of all voices
1634       */       */
1635      void Engine::ResetSynthesisParameters(Event::destination_t dst, float val) {      void Engine::ReleaseAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itReleaseEvent) {
1636          int maxsamples = pAudioOutputDevice->MaxSamplesPerCycle();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1637          float* m = &pSynthesisParameters[dst][0];          while (iuiKey) {
1638          for (int i = 0; i < maxsamples; i += 4) {              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1639             m[i]   = val;              ++iuiKey;
1640             m[i+1] = val;              // append a 'release' event to the key's own event list
1641             m[i+2] = val;              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1642             m[i+3] = val;              if (itNewEvent) {
1643                    *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
1644                    itNewEvent->Type = Event::type_release; // transform event type
1645                }
1646                else dmsg(1,("Event pool emtpy!\n"));
1647          }          }
1648      }      }
1649    
1650      float Engine::Volume() {      /**
1651          return GlobalVolume;       * Kills all voices on an engine channel as soon as possible. Voices
1652      }       * won't get into release state, their volume level will be ramped down
1653         * as fast as possible.
1654      void Engine::Volume(float f) {       *
1655          GlobalVolume = f;       * @param pEngineChannel - engine channel on which all voices should be killed
1656      }       * @param itKillEvent    - event which caused this killing of all voices
1657         */
1658      uint Engine::Channels() {      void Engine::KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {
1659          return 2;          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1660      }          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
1661            while (iuiKey != end) { // iterate through all active keys
1662      void Engine::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {              midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1663          AudioChannel* pChannel = pAudioOutputDevice->Channel(AudioDeviceChannel);              ++iuiKey;
1664          if (!pChannel) throw AudioOutputException("Invalid audio output device channel " + ToString(AudioDeviceChannel));              RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
1665          switch (EngineAudioChannel) {              RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
1666              case 0: // left output channel              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
1667                  pOutputLeft = pChannel->Buffer();                  itVoice->Kill(itKillEvent);
1668                  AudioDeviceChannelLeft = AudioDeviceChannel;                  --VoiceSpawnsLeft; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
1669                  break;              }
             case 1: // right output channel  
                 pOutputRight = pChannel->Buffer();  
                 AudioDeviceChannelRight = AudioDeviceChannel;  
                 break;  
             default:  
                 throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));  
1670          }          }
1671      }      }
1672    
1673      int Engine::OutputChannel(uint EngineAudioChannel) {      /**
1674          switch (EngineAudioChannel) {       * Determines whether the specified voice should be released.
1675              case 0: // left channel       *
1676                  return AudioDeviceChannelLeft;       * @param pEngineChannel - The engine channel on which the voice should be checked
1677              case 1: // right channel       * @param Key - The key number
1678                  return AudioDeviceChannelRight;       * @returns true if the specified should be released, false otherwise.
1679              default:       */
1680                  throw AudioOutputException("Invalid engine audio channel " + ToString(EngineAudioChannel));      bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
1681            if (pEngineChannel->SustainPedal) return false;
1682    
1683            if (pEngineChannel->SostenutoPedal) {
1684                for (int i = 0; i < SostenutoKeyCount; i++)
1685                    if (Key == SostenutoKeys[i]) return false;
1686          }          }
1687    
1688            return true;
1689      }      }
1690    
1691      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
# Line 1154  namespace LinuxSampler { namespace gig { Line 1717  namespace LinuxSampler { namespace gig {
1717      }      }
1718    
1719      String Engine::EngineName() {      String Engine::EngineName() {
1720          return "GigEngine";          return LS_GIG_ENGINE_NAME;
1721      }      }
1722    
1723      String Engine::InstrumentFileName() {      String Engine::Description() {
1724          return InstrumentFile;          return "Gigasampler Engine";
1725      }      }
1726    
1727      int Engine::InstrumentIndex() {      String Engine::Version() {
1728          return InstrumentIdx;          String s = "$Revision: 1.77 $";
1729            return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
1730      }      }
1731    
1732      int Engine::InstrumentStatus() {      InstrumentManager* Engine::GetInstrumentManager() {
1733          return InstrumentStat;          return &instruments;
1734      }      }
1735    
1736      String Engine::Description() {      // static constant initializers
1737          return "Gigasampler Engine";      const float* Engine::VolumeCurve(InitVolumeCurve());
1738        const float* Engine::PanCurve(InitPanCurve());
1739        const float* Engine::CrossfadeCurve(InitCrossfadeCurve());
1740    
1741        float* Engine::InitVolumeCurve() {
1742            // line-segment approximation
1743            const float segments[] = {
1744                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
1745                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
1746            };
1747            return InitCurve(segments);
1748      }      }
1749    
1750      String Engine::Version() {      float* Engine::InitPanCurve() {
1751          String s = "$Revision: 1.21 $";          // line-segment approximation
1752          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          const float segments[] = {
1753                0, 0, 1, 0,
1754                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
1755                127, 1.41, 128, 1.41
1756            };
1757            return InitCurve(segments, 129);
1758        }
1759    
1760        float* Engine::InitCrossfadeCurve() {
1761            // line-segment approximation
1762            const float segments[] = {
1763                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
1764            };
1765            return InitCurve(segments);
1766        }
1767    
1768        float* Engine::InitCurve(const float* segments, int size) {
1769            float* y = new float[size];
1770            for (int x = 0 ; x < size ; x++) {
1771                if (x > segments[2]) segments += 2;
1772                y[x] = segments[1] + (x - segments[0]) *
1773                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
1774            }
1775            return y;
1776        }
1777    
1778        /**
1779         * Changes the instrument for an engine channel.
1780         *
1781         * @param pEngineChannel - engine channel on which the instrument
1782         *                         should be changed
1783         * @param pInstrument - new instrument
1784         * @returns a list of dimension regions from the old instrument
1785         *          that are still in use
1786         */
1787        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
1788            instrument_change_command_t command;
1789            command.pEngineChannel = pEngineChannel;
1790            command.pInstrument = pInstrument;
1791            InstrumentChangeQueue->push(&command);
1792    
1793            // wait for the audio thread to confirm that the instrument
1794            // change has been done
1795            instrument_change_reply_t reply;
1796            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
1797                usleep(10000);
1798            }
1799            return pDimRegionsInUse;
1800      }      }
1801    
1802  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.351  
changed lines
  Added in v.1248

  ViewVC Help
Powered by ViewVC