/[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 775 by schoenebeck, Wed Sep 21 14:30:43 2005 UTC revision 1893 by schoenebeck, Sat May 2 18:57:49 2009 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 29  Line 29 
29    
30  #include "Engine.h"  #include "Engine.h"
31    
32    #include "../../common/global_private.h"
33    
34  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
35    
36      InstrumentResourceManager Engine::instruments;      InstrumentResourceManager Engine::instruments;
# Line 51  namespace LinuxSampler { namespace gig { Line 53  namespace LinuxSampler { namespace gig {
53          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
54              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
55              pEngine = engines[pDevice];              pEngine = engines[pDevice];
56    
57                // Disable the engine while the new engine channel is
58                // added and initialized. The engine will be enabled again
59                // in EngineChannel::Connect.
60                pEngine->DisableAndLock();
61          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
62              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
63              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 67  namespace LinuxSampler { namespace gig { Line 74  namespace LinuxSampler { namespace gig {
74    
75      /**      /**
76       * Once an engine channel is disconnected from an audio output device,       * Once an engine channel is disconnected from an audio output device,
77       * it wil immediately call this method to unregister itself from the       * it will immediately call this method to unregister itself from the
78       * engine instance and if that engine instance is not used by any other       * engine instance and if that engine instance is not used by any other
79       * engine channel anymore, then that engine instance will be destroyed.       * engine channel anymore, then that engine instance will be destroyed.
80       *       *
# Line 93  namespace LinuxSampler { namespace gig { Line 100  namespace LinuxSampler { namespace gig {
100      /**      /**
101       * Constructor       * Constructor
102       */       */
103      Engine::Engine() {      Engine::Engine() : SuspendedRegions(128) {
104          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
105          pDiskThread        = NULL;          pDiskThread        = NULL;
106          pEventGenerator    = NULL;          pEventGenerator    = NULL;
107          pSysexBuffer       = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
108          pEventQueue        = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(GLOBAL_MAX_VOICES);
111            pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
112            pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
115            iMaxDiskStreams    = GLOBAL_MAX_STREAMS;
116    
117          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
118              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
119          }          }
# Line 110  namespace LinuxSampler { namespace gig { Line 121  namespace LinuxSampler { namespace gig {
121    
122          ResetInternal();          ResetInternal();
123          ResetScaleTuning();          ResetScaleTuning();
124            ResetSuspendedRegions();
125      }      }
126    
127      /**      /**
128       * Destructor       * Destructor
129       */       */
130      Engine::~Engine() {      Engine::~Engine() {
131            MidiInputPort::RemoveSysexListener(this);
132          if (pDiskThread) {          if (pDiskThread) {
133              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
134              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 131  namespace LinuxSampler { namespace gig { Line 144  namespace LinuxSampler { namespace gig {
144          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
145          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
146          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
147          EngineFactory::Destroy(this);          if (pGlobalEvents) delete pGlobalEvents;
148            if (pDimRegionPool[0]) delete pDimRegionPool[0];
149            if (pDimRegionPool[1]) delete pDimRegionPool[1];
150            ResetSuspendedRegions();
151            Unregister();
152      }      }
153    
154      void Engine::Enable() {      void Engine::Enable() {
# Line 140  namespace LinuxSampler { namespace gig { Line 157  namespace LinuxSampler { namespace gig {
157          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
158      }      }
159    
160        /**
161         * Temporarily stop the engine to not do anything. The engine will just be
162         * frozen during that time, that means after enabling it again it will
163         * continue where it was, with all its voices and playback state it had at
164         * the point of disabling. Notice that the engine's (audio) thread will
165         * continue to run, it just remains in an inactive loop during that time.
166         *
167         * If you need to be sure that all voices and disk streams are killed as
168         * well, use @c SuspendAll() instead.
169         *
170         * @see Enable(), SuspendAll()
171         */
172      void Engine::Disable() {      void Engine::Disable() {
173          dmsg(3,("gig::Engine: disabling\n"));          dmsg(3,("gig::Engine: disabling\n"));
174          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
# Line 153  namespace LinuxSampler { namespace gig { Line 182  namespace LinuxSampler { namespace gig {
182      }      }
183    
184      /**      /**
185         * Similar to @c Disable() but this method additionally kills all voices
186         * and disk streams and blocks until all voices and disk streams are actually
187         * killed / deleted.
188         *
189         * @e Note: only the original calling thread is able to re-enable the
190         * engine afterwards by calling @c ResumeAll() later on!
191         */
192        void Engine::SuspendAll() {
193            dmsg(2,("gig::Engine: Suspending all ...\n"));
194            // stop the engine, so we can safely modify the engine's
195            // data structures from this foreign thread
196            DisableAndLock();
197            // we could also use the respective class member variable here,
198            // but this is probably safer and cleaner
199            int iPendingStreamDeletions = 0;
200            // kill all voices on all engine channels the *die hard* way
201            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
202                EngineChannel* pEngineChannel = engineChannels[iChannel];
203                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
204                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
205                for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
206                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
207                    RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
208                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
209                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
210                        // request a notification from disk thread side for stream deletion
211                        const Stream::Handle hStream = itVoice->KillImmediately(true);
212                        if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
213                            iPendingStreamDeletions++;
214                        }
215                        // free the voice to the voice pool and update key info
216                        FreeVoice(pEngineChannel, itVoice);
217                    }
218                }
219            }
220            // wait until all streams were actually deleted by the disk thread
221            while (iPendingStreamDeletions) {
222                while (
223                    iPendingStreamDeletions &&
224                    pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
225                ) iPendingStreamDeletions--;
226                if (!iPendingStreamDeletions) break;
227                usleep(10000); // sleep for 10ms
228            }
229            dmsg(2,("gig::Engine: Everything suspended.\n"));
230        }
231    
232        /**
233         * At the moment same as calling @c Enable() directly, but this might
234         * change in future, so better call this method as counterpart to
235         * @c SuspendAll() instead of @c Enable() !
236         */
237        void Engine::ResumeAll() {
238            Enable();
239        }
240    
241        /**
242         * Order the engine to stop rendering audio for the given region.
243         * Additionally this method will block until all voices and their disk
244         * streams associated with that region are actually killed / deleted, so
245         * one can i.e. safely modify the region with an instrument editor after
246         * returning from this method.
247         *
248         * @param pRegion - region the engine shall stop using
249         */
250        void Engine::Suspend(::gig::Region* pRegion) {
251            dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
252            SuspendedRegionsMutex.Lock();
253            SuspensionChangeOngoing.Set(true);
254            pPendingRegionSuspension = pRegion;
255            SuspensionChangeOngoing.WaitAndUnlockIf(true);
256            SuspendedRegionsMutex.Unlock();
257            dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
258        }
259    
260        /**
261         * Orders the engine to resume playing back the given region, previously
262         * suspended with @c Suspend() .
263         *
264         * @param pRegion - region the engine shall be allowed to use again
265         */
266        void Engine::Resume(::gig::Region* pRegion) {
267            dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
268            SuspendedRegionsMutex.Lock();
269            SuspensionChangeOngoing.Set(true);
270            pPendingRegionResumption = pRegion;
271            SuspensionChangeOngoing.WaitAndUnlockIf(true);
272            SuspendedRegionsMutex.Unlock();
273            dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
274        }
275    
276        /**
277       *  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
278       *  control and status variables.       *  control and status variables.
279       */       */
# Line 165  namespace LinuxSampler { namespace gig { Line 286  namespace LinuxSampler { namespace gig {
286    
287      /**      /**
288       *  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
289       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
290       */       */
291      void Engine::ResetInternal() {      void Engine::ResetInternal() {
292          ActiveVoiceCount    = 0;          ResetInternalMutex.Lock();
293    
294            // make sure that the engine does not get any sysex messages
295            // while it's reseting
296            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
297            SetVoiceCount(0);
298          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
299    
300          // reset voice stealing parameters          // reset voice stealing parameters
# Line 191  namespace LinuxSampler { namespace gig { Line 317  namespace LinuxSampler { namespace gig {
317          // delete all input events          // delete all input events
318          pEventQueue->init();          pEventQueue->init();
319          pSysexBuffer->init();          pSysexBuffer->init();
320            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
321            ResetInternalMutex.Unlock();
322      }      }
323    
324      /**      /**
# Line 200  namespace LinuxSampler { namespace gig { Line 328  namespace LinuxSampler { namespace gig {
328          memset(&ScaleTuning[0], 0x00, 12);          memset(&ScaleTuning[0], 0x00, 12);
329      }      }
330    
331        void Engine::ResetSuspendedRegions() {
332            SuspendedRegions.clear();
333            iPendingStreamDeletions = 0;
334            pPendingRegionSuspension = pPendingRegionResumption = NULL;
335            SuspensionChangeOngoing.Set(false);
336        }
337    
338      /**      /**
339       * Connect this engine instance with the given audio output device.       * Connect this engine instance with the given audio output device.
340       * This method will be called when an Engine instance is created.       * This method will be called when an Engine instance is created.
# Line 210  namespace LinuxSampler { namespace gig { Line 345  namespace LinuxSampler { namespace gig {
345       * @param pAudioOut - audio output device to connect to       * @param pAudioOut - audio output device to connect to
346       */       */
347      void Engine::Connect(AudioOutputDevice* pAudioOut) {      void Engine::Connect(AudioOutputDevice* pAudioOut) {
348            // caution: don't ignore if connecting to the same device here,
349            // because otherwise SetMaxDiskStreams() implementation won't work anymore!
350    
351          pAudioOutputDevice = pAudioOut;          pAudioOutputDevice = pAudioOut;
352    
353          ResetInternal();          ResetInternal();
# Line 220  namespace LinuxSampler { namespace gig { Line 358  namespace LinuxSampler { namespace gig {
358          }          }
359          catch (AudioOutputException e) {          catch (AudioOutputException e) {
360              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();
361              throw LinuxSamplerException(msg);              throw Exception(msg);
362          }          }
363    
364          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
365          this->SampleRate         = pAudioOutputDevice->SampleRate();          this->SampleRate         = pAudioOutputDevice->SampleRate();
366    
367          // FIXME: audio drivers with varying fragment sizes might be a problem here          MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
368          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;          if (MaxSamplesPerCycle < MinFadeOutSamples) {
         if (MaxFadeOutPos < 0) {  
369              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
370                        << "too big for current audio fragment size & sampling rate! "                        << "too big for current audio fragment size & sampling rate! "
371                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
372              // force volume ramp downs at the beginning of each fragment              // force volume ramp downs at the beginning of each fragment
373              MaxFadeOutPos = 0;              MinFadeOutSamples = MaxSamplesPerCycle;
374              // lower minimum release time              // lower minimum release time
375              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
376              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 249  namespace LinuxSampler { namespace gig { Line 386  namespace LinuxSampler { namespace gig {
386              delete this->pDiskThread;              delete this->pDiskThread;
387              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
388          }          }
389          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread =
390                new DiskThread(
391                    iMaxDiskStreams,
392                    ((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
393                    &instruments
394                );
395    
396          if (!pDiskThread) {          if (!pDiskThread) {
397              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
398              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 275  namespace LinuxSampler { namespace gig { Line 418  namespace LinuxSampler { namespace gig {
418                  exit(EXIT_FAILURE);                  exit(EXIT_FAILURE);
419              }              }
420          }          }
421            pVoicePool->clear();
422        }
423    
424        /**
425         * Called by the engine's (audio) thread once per cycle to process requests
426         * from the outer world to suspend or resume a given @c gig::Region .
427         */
428        void Engine::ProcessSuspensionsChanges() {
429            // process request for suspending one region
430            if (pPendingRegionSuspension) {
431                // kill all voices on all engine channels that use this region
432                for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
433                    EngineChannel* pEngineChannel = engineChannels[iChannel];
434                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
435                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
436                    for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
437                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
438                        RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
439                        // if current key is not associated with this region, skip this key
440                        if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
441                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
442                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
443                            // request a notification from disk thread side for stream deletion
444                            const Stream::Handle hStream = itVoice->KillImmediately(true);
445                            if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
446                                iPendingStreamDeletions++;
447                            }
448                            //NOTE: maybe we should call FreeVoice() here, shouldn't cause a harm though I think, since the voices should be freed by RenderActiveVoices() in the render loop, they are probably just freed a bit later than they could/should be
449                        }
450                    }
451                }
452                // make sure the region is not yet on the list
453                bool bAlreadySuspended = false;
454                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
455                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
456                for (; iter != end; ++iter) { // iterate through all suspended regions
457                    if (*iter == pPendingRegionSuspension) { // found
458                        bAlreadySuspended = true;
459                        dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
460                        break;
461                    }
462                }
463                if (!bAlreadySuspended) {
464                    // put the region on the list of suspended regions
465                    RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
466                    if (iter) {
467                        *iter = pPendingRegionSuspension;
468                    } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
469                }
470                // free request slot for next caller (and to make sure that
471                // we're not going to process the same request in the next cycle)
472                pPendingRegionSuspension = NULL;
473                // if no disk stream deletions are pending, awaken other side, as
474                // we're done in this case
475                if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
476            }
477    
478            // process request for resuming one region
479            if (pPendingRegionResumption) {
480                // remove region from the list of suspended regions
481                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
482                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
483                for (; iter != end; ++iter) { // iterate through all suspended regions
484                    if (*iter == pPendingRegionResumption) { // found
485                        SuspendedRegions.free(iter);
486                        break; // done
487                    }
488                }
489                // free request slot for next caller
490                pPendingRegionResumption = NULL;
491                // awake other side as we're done
492                SuspensionChangeOngoing.Set(false);
493            }
494        }
495    
496        /**
497         * Called by the engine's (audio) thread once per cycle to check if
498         * streams of voices that were killed due to suspension request have
499         * finally really been deleted by the disk thread.
500         */
501        void Engine::ProcessPendingStreamDeletions() {
502            if (!iPendingStreamDeletions) return;
503            //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
504            while (
505                iPendingStreamDeletions &&
506                pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
507            ) iPendingStreamDeletions--;
508            // just for safety ...
509            while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
510            // now that all disk streams are deleted, awake other side as
511            // we're finally done with suspending the requested region
512            if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
513        }
514    
515        /**
516         * Returns @c true if the given region is currently set to be suspended
517         * from being used, @c false otherwise.
518         */
519        bool Engine::RegionSuspended(::gig::Region* pRegion) {
520            if (SuspendedRegions.isEmpty()) return false;
521            //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
522            RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
523            RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
524            for (; iter != end; ++iter)  // iterate through all suspended regions
525                if (*iter == pRegion) return true;
526            return false;
527      }      }
528    
529      /**      /**
# Line 298  namespace LinuxSampler { namespace gig { Line 547  namespace LinuxSampler { namespace gig {
547       *                  current audio cycle       *                  current audio cycle
548       */       */
549      void Engine::ImportEvents(uint Samples) {      void Engine::ImportEvents(uint Samples) {
550          RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
551          Event* pEvent;          Event* pEvent;
552          while (true) {          while (true) {
553              // get next event from input event queue              // get next event from input event queue
# Line 321  namespace LinuxSampler { namespace gig { Line 570  namespace LinuxSampler { namespace gig {
570      }      }
571    
572      /**      /**
573       *  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.
574       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
575       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
576       *  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
577       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
578         * respective engine channel.
579       *       *
580       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
581       *  @returns       0 on success       *  @returns       0 on success
582       */       */
583      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
584          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
585    
586          // return if engine disabled          // return if engine disabled
587          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
588              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
589                EngineDisabled.RttDone();
590              return 0;              return 0;
591          }          }
592    
593            // process requests for suspending / resuming regions (i.e. to avoid
594            // crashes while these regions are modified by an instrument editor)
595            ProcessSuspensionsChanges();
596    
597          // 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)
598          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
599    
600          // We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned          // We only allow the given maximum number of voices to be spawned
601          // in each audio fragment. All subsequent request for spawning new          // in each audio fragment. All subsequent request for spawning new
602          // voices in the same audio fragment will be ignored.          // voices in the same audio fragment will be ignored.
603          VoiceSpawnsLeft = CONFIG_MAX_VOICES;          VoiceSpawnsLeft = MaxVoices();
604    
605          // get all events from the engine's global input event queue which belong to the current fragment          // get all events from the engine's global input event queue which belong to the current fragment
606          // (these are usually just SysEx messages)          // (these are usually just SysEx messages)
# Line 368  namespace LinuxSampler { namespace gig { Line 623  namespace LinuxSampler { namespace gig {
623          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
624          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
625    
626            // handle instrument change commands
627            bool instrumentChanged = false;
628            for (int i = 0; i < engineChannels.size(); i++) {
629                EngineChannel* pEngineChannel = engineChannels[i];
630    
631                // as we're going to (carefully) write some status to the
632                // synchronized struct, we cast away the const
633                EngineChannel::instrument_change_command_t& cmd =
634                    const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
635    
636                pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
637                pEngineChannel->pDimRegionsInUse->clear();
638    
639                if (cmd.bChangeInstrument) {
640                    // change instrument
641                    dmsg(5,("Engine: instrument change command received\n"));
642                    cmd.bChangeInstrument = false;
643                    pEngineChannel->pInstrument = cmd.pInstrument;
644                    instrumentChanged = true;
645    
646                    // Iterate through all active voices and mark them as
647                    // "orphans", which means that the dimension regions
648                    // and samples they use should be released to the
649                    // instrument resource manager when the voices die.
650                    int i = 0;
651                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
652                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
653                    while (iuiKey != end) { // iterate through all active keys
654                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
655                        ++iuiKey;
656    
657                        RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
658                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
659                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
660                            itVoice->Orphan = true;
661                        }
662                    }
663                }
664            }
665            if (instrumentChanged) {
666                //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
667                ResetSuspendedRegions();
668            }
669    
670          // handle events on all engine channels          // handle events on all engine channels
671          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
672              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
673          }          }
674    
675          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
676          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
677              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
678          }          }
679    
680          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices          // now that all ordinary voices on ALL engine channels are rendered, render new stolen voices
681          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
682    
683            // handle audio routing for engine channels with FX sends
684            for (int i = 0; i < engineChannels.size(); i++) {
685                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
686                RouteAudio(engineChannels[i], Samples);
687            }
688    
689          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
690          for (int i = 0; i < engineChannels.size(); i++) {          for (int i = 0; i < engineChannels.size(); i++) {
             if (!engineChannels[i]->pInstrument) continue; // ignore if no instrument loaded  
691              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
692          }          }
693    
# Line 397  namespace LinuxSampler { namespace gig { Line 699  namespace LinuxSampler { namespace gig {
699          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
700    
701          // just some statistics about this engine instance          // just some statistics about this engine instance
702          ActiveVoiceCount = ActiveVoiceCountTemp;          SetVoiceCount(ActiveVoiceCountTemp);
703          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
704    
705            // in case regions were previously suspended and we killed voices
706            // with disk streams due to that, check if those streams have finally
707            // been deleted by the disk thread
708            if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
709    
710            for (int i = 0; i < engineChannels.size(); i++) {
711                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
712            }
713          FrameTime += Samples;          FrameTime += Samples;
714    
715            EngineDisabled.RttDone();
716          return 0;          return 0;
717      }      }
718    
# Line 467  namespace LinuxSampler { namespace gig { Line 778  namespace LinuxSampler { namespace gig {
778          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
779          #endif          #endif
780    
781            uint voiceCount = 0;
782            uint streamCount = 0;
783          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
784          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
785          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 478  namespace LinuxSampler { namespace gig { Line 791  namespace LinuxSampler { namespace gig {
791              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
792                  // now render current voice                  // now render current voice
793                  itVoice->Render(Samples);                  itVoice->Render(Samples);
794                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
795                  else { // voice reached end, is now inactive                      if (!itVoice->Orphan) {
796                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
797                        }
798                        ActiveVoiceCountTemp++;
799                        voiceCount++;
800    
801                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
802                            if ((itVoice->DiskStreamRef).State != Stream::state_unused) streamCount++;
803                        }
804                    }  else { // voice reached end, is now inactive
805                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
806                  }                  }
807              }              }
808          }          }
809    
810            pEngineChannel->SetVoiceCount(voiceCount);
811            pEngineChannel->SetDiskStreamCount(streamCount);
812      }      }
813    
814      /**      /**
# Line 504  namespace LinuxSampler { namespace gig { Line 829  namespace LinuxSampler { namespace gig {
829          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
830          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
831              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
832                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
833              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
834                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
835              if (itNewVoice) {              if (itNewVoice) {
836                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
837                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
838                  else { // voice reached end, is now inactive                      *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
839                        ActiveVoiceCountTemp++;
840                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
841    
842                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
843                            if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
844                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
845                            }
846                        }
847                    } else { // voice reached end, is now inactive
848                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
849                  }                  }
850              }              }
# Line 523  namespace LinuxSampler { namespace gig { Line 858  namespace LinuxSampler { namespace gig {
858      }      }
859    
860      /**      /**
861         * Will be called in case the respective engine channel sports FX send
862         * channels. In this particular case, engine channel local buffers are
863         * used to render and mix all voices to. This method is responsible for
864         * copying the audio data from those local buffers to the master audio
865         * output channels as well as to the FX send audio output channels with
866         * their respective FX send levels.
867         *
868         * @param pEngineChannel - engine channel from which audio should be
869         *                         routed
870         * @param Samples        - amount of sample points to be routed in
871         *                         this audio fragment cycle
872         */
873        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
874            // route dry signal
875            {
876                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
877                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
878                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
879                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
880            }
881            // route FX send signal
882            {
883                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
884                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
885                    for (int iChan = 0; iChan < 2; ++iChan) {
886                        AudioChannel* pSource =
887                            (iChan)
888                                ? pEngineChannel->pChannelRight
889                                : pEngineChannel->pChannelLeft;
890                        const int iDstChan = pFxSend->DestinationChannel(iChan);
891                        if (iDstChan < 0) {
892                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
893                            goto channel_cleanup;
894                        }
895                        AudioChannel* pDstChan = NULL;
896                        if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
897                            EffectChain* pEffectChain =
898                                pAudioOutputDevice->MasterEffectChain(
899                                    pFxSend->DestinationMasterEffectChain()
900                                );
901                            if (!pEffectChain) {
902                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
903                                goto channel_cleanup;
904                            }
905                            Effect* pEffect =
906                                pEffectChain->GetEffect(
907                                    pFxSend->DestinationMasterEffect()
908                                );
909                            if (!pEffect) {
910                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
911                                goto channel_cleanup;
912                            }
913                            pDstChan = pEffect->InputChannel(iDstChan);
914                        } else { // FX send routed directly to an audio output channel
915                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
916                        }
917                        if (!pDstChan) {
918                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
919                            goto channel_cleanup;
920                        }
921                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
922                    }
923                }
924            }
925            channel_cleanup:
926            // reset buffers with silence (zero out) for the next audio cycle
927            pEngineChannel->pChannelLeft->Clear();
928            pEngineChannel->pChannelRight->Clear();
929        }
930    
931        /**
932       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
933       * the list of active keys and clear all event lists on that engine       * the list of active keys and clear all event lists on that engine
934       * channel.       * channel.
# Line 562  namespace LinuxSampler { namespace gig { Line 968  namespace LinuxSampler { namespace gig {
968       *       *
969       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
970       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
971         *  @param pSender - the MIDI input port on which the SysEx message was
972         *                   received
973       */       */
974      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
975          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
976          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
977          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
978          event.pEngineChannel    = NULL; // as Engine global event          event.pEngineChannel    = NULL; // as Engine global event
979            event.pMidiInputPort    = pSender;
980          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
981              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
982                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 599  namespace LinuxSampler { namespace gig { Line 1008  namespace LinuxSampler { namespace gig {
1008          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1009          #endif          #endif
1010    
1011            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
1012    
1013            //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
1014            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1015    
1016          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
1017            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
1018    
1019            // move note on event to the key's own event list
1020            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1021    
1022            // if Solo Mode then kill all already active voices
1023            if (pEngineChannel->SoloMode) {
1024                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
1025                if (itYoungestKey) {
1026                    const int iYoungestKey = *itYoungestKey;
1027                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
1028                    if (pOtherKey->Active) {
1029                        // get final portamento position of currently active voice
1030                        if (pEngineChannel->PortamentoMode) {
1031                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
1032                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1033                        }
1034                        // kill all voices on the (other) key
1035                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
1036                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
1037                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1038                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1039                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1040                        }
1041                    }
1042                }
1043                // set this key as 'currently active solo key'
1044                pEngineChannel->SoloKey = key;
1045            }
1046    
1047          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
1048          {          {
1049              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
1050              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
1051                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
1052                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
1053          }          }
1054    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
1055          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
1056          pKey->Velocity   = itNoteOnEvent->Param.Note.Velocity;          pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1057          pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length          pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1058    
1059          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
1060          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
1061              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1062              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
1063                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1064                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
1065              }              }
1066              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
1067          }          }
1068    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
1069          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
1070          {          {
1071              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
1072              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1073              if (pRegion) {              if (pRegion && !RegionSuspended(pRegion)) {
1074                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
1075                  // now launch the required amount of voices                  // now launch the required amount of voices
1076                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
# Line 644  namespace LinuxSampler { namespace gig { Line 1082  namespace LinuxSampler { namespace gig {
1082          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
1083              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
1084    
1085            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
1086          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
1087      }      }
1088    
# Line 661  namespace LinuxSampler { namespace gig { Line 1100  namespace LinuxSampler { namespace gig {
1100          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1101          #endif          #endif
1102    
1103          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];          //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
1104            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1105    
1106            const int iKey = itNoteOffEvent->Param.Note.Key;
1107            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1108          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
1109    
1110          // release voices on this key if needed          // move event to the key's own event list
1111          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1112              itNoteOffEvent->Type = Event::type_release; // transform event type  
1113            bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
1114    
1115            // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1116            if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1117                bool bOtherKeysPressed = false;
1118                if (iKey == pEngineChannel->SoloKey) {
1119                    pEngineChannel->SoloKey = -1;
1120                    // if there's still a key pressed down, respawn a voice (group) on the highest key
1121                    for (int i = 127; i > 0; i--) {
1122                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
1123                        if (pOtherKey->KeyPressed) {
1124                            bOtherKeysPressed = true;
1125                            // make the other key the new 'currently active solo key'
1126                            pEngineChannel->SoloKey = i;
1127                            // get final portamento position of currently active voice
1128                            if (pEngineChannel->PortamentoMode) {
1129                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
1130                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1131                            }
1132                            // create a pseudo note on event
1133                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1134                            if (itPseudoNoteOnEvent) {
1135                                // copy event
1136                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1137                                // transform event to a note on event
1138                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
1139                                itPseudoNoteOnEvent->Param.Note.Key      = i;
1140                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1141                                // allocate and trigger new voice(s) for the other key
1142                                {
1143                                    // first, get total amount of required voices (dependant on amount of layers)
1144                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
1145                                    if (pRegion) {
1146                                        int voicesRequired = pRegion->Layers;
1147                                        // now launch the required amount of voices
1148                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
1149                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
1150                                    }
1151                                }
1152                                // if neither a voice was spawned or postponed then remove note on event from key again
1153                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1154                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1155    
1156                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
1157                            break; // done
1158                        }
1159                    }
1160                }
1161                if (bOtherKeysPressed) {
1162                    if (pKey->Active) { // kill all voices on this key
1163                        bShouldRelease = false; // no need to release, as we kill it here
1164                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
1165                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
1166                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1167                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
1168                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1169                        }
1170                    }
1171                } else pEngineChannel->PortamentoPos = -1.0f;
1172            }
1173    
1174              // move event to the key's own event list          // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1175              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          if (bShouldRelease) {
1176                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
1177    
1178              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
1179              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
1180                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
1181                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
1182                  if (pRegion) {                  if (pRegion) {
# Line 687  namespace LinuxSampler { namespace gig { Line 1191  namespace LinuxSampler { namespace gig {
1191                  }                  }
1192                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
1193              }              }
   
             // if neither a voice was spawned or postponed then remove note off event from key again  
             if (!pKey->Active && !pKey->VoiceTheftsQueued)  
                 pKey->pEvents->free(itNoteOffEventOnKeyList);  
1194          }          }
1195    
1196            // if neither a voice was spawned or postponed on this key then remove note off event from key again
1197            if (!pKey->Active && !pKey->VoiceTheftsQueued)
1198                pKey->pEvents->free(itNoteOffEventOnKeyList);
1199      }      }
1200    
1201      /**      /**
# Line 775  namespace LinuxSampler { namespace gig { Line 1279  namespace LinuxSampler { namespace gig {
1279                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
1280                      break;                      break;
1281                  case ::gig::dimension_channelaftertouch:                  case ::gig::dimension_channelaftertouch:
1282                      DimValues[i] = 0; //TODO: we currently ignore this dimension                      DimValues[i] = pEngineChannel->ControllerTable[128];
1283                      break;                      break;
1284                  case ::gig::dimension_releasetrigger:                  case ::gig::dimension_releasetrigger:
1285                      VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;                      VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
1286                      DimValues[i] = (uint) ReleaseTriggerVoice;                      DimValues[i] = (uint) ReleaseTriggerVoice;
1287                      break;                      break;
1288                  case ::gig::dimension_keyboard:                  case ::gig::dimension_keyboard:
1289                      DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;                      DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
1290                      break;                      break;
1291                  case ::gig::dimension_roundrobin:                  case ::gig::dimension_roundrobin:
1292                      DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on                      DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
# Line 867  namespace LinuxSampler { namespace gig { Line 1371  namespace LinuxSampler { namespace gig {
1371                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1372              }              }
1373          }          }
1374    
1375            // return if this is a release triggered voice and there is no
1376            // releasetrigger dimension (could happen if an instrument
1377            // change has occured between note on and off)
1378            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1379    
1380          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1381    
1382          // no need to continue if sample is silent          // no need to continue if sample is silent
# Line 1096  namespace LinuxSampler { namespace gig { Line 1606  namespace LinuxSampler { namespace gig {
1606    
1607              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1608    
1609                // if the sample and dimension region belong to an
1610                // instrument that is unloaded, tell the disk thread to
1611                // release them
1612                if (itVoice->Orphan) {
1613                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1614                }
1615    
1616              // free the voice object              // free the voice object
1617              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1618    
# Line 1137  namespace LinuxSampler { namespace gig { Line 1654  namespace LinuxSampler { namespace gig {
1654      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1655          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));
1656    
1657            // handle the "control triggered" MIDI rule: a control change
1658            // event can trigger a new note on or note off event
1659            if (pEngineChannel->pInstrument) {
1660    
1661                ::gig::MidiRule* rule;
1662                for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1663    
1664                    if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1665                        dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1666                        if (itControlChangeEvent->Param.CC.Controller ==
1667                            ctrlTrigger->ControllerNumber) {
1668    
1669                            uint8_t oldCCValue = pEngineChannel->ControllerTable[
1670                                itControlChangeEvent->Param.CC.Controller];
1671                            uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1672    
1673                            for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1674                                ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1675                                      &ctrlTrigger->pTriggers[i];
1676    
1677                                // check if the controller has passed the
1678                                // trigger point in the right direction
1679                                if ((pTrigger->Descending &&
1680                                     oldCCValue > pTrigger->TriggerPoint &&
1681                                     newCCValue <= pTrigger->TriggerPoint) ||
1682                                    (!pTrigger->Descending &&
1683                                     oldCCValue < pTrigger->TriggerPoint &&
1684                                     newCCValue >= pTrigger->TriggerPoint)) {
1685    
1686                                    RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1687                                    if (itNewEvent) {
1688                                        *itNewEvent = *itControlChangeEvent;
1689                                        itNewEvent->Param.Note.Key = pTrigger->Key;
1690    
1691                                        if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1692                                            itNewEvent->Type = Event::type_note_off;
1693                                            itNewEvent->Param.Note.Velocity = 100;
1694    
1695                                            ProcessNoteOff(pEngineChannel, itNewEvent);
1696                                        } else {
1697                                            itNewEvent->Type = Event::type_note_on;
1698                                            //TODO: if Velocity is 255, the triggered velocity should
1699                                            // depend on how fast the controller is moving
1700                                            itNewEvent->Param.Note.Velocity =
1701                                                pTrigger->Velocity == 255 ? 100 :
1702                                                pTrigger->Velocity;
1703    
1704                                            ProcessNoteOn(pEngineChannel, itNewEvent);
1705                                        }
1706                                    }
1707                                    else dmsg(1,("Event pool emtpy!\n"));
1708                                }
1709                            }
1710                        }
1711                    }
1712                }
1713            }
1714    
1715          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1716          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1717    
1718            // handle hard coded MIDI controllers
1719          switch (itControlChangeEvent->Param.CC.Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
1720                case 5: { // portamento time
1721                    pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1722                    break;
1723                }
1724                case 6: { // data entry (currently only used for RPN controllers)
1725                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1726                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1727                        // limit to +- two octaves for now
1728                        transpose = RTMath::Min(transpose,  24);
1729                        transpose = RTMath::Max(transpose, -24);
1730                        pEngineChannel->GlobalTranspose = transpose;
1731                        // workaround, so we won't have hanging notes
1732                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1733                    }
1734                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1735                    pEngineChannel->ResetMidiRpnController();
1736                    break;
1737                }
1738              case 7: { // volume              case 7: { // volume
1739                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1740                  pEngineChannel->GlobalVolume = (float) itControlChangeEvent->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1741                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1742                  break;                  break;
1743              }              }
1744              case 10: { // panpot              case 10: { // panpot
1745                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1746                  const int pan = (int) itControlChangeEvent->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1747                  pEngineChannel->GlobalPanLeft  = 1.0f - float(RTMath::Max(pan, 0)) /  63.0f;                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1748                  pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f;                  pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1749                  break;                  break;
1750              }              }
1751              case 64: { // sustain              case 64: { // sustain
1752                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1753                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1754                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1755    
1756                      #if !CONFIG_PROCESS_MUTED_CHANNELS                      #if !CONFIG_PROCESS_MUTED_CHANNELS
# Line 1178  namespace LinuxSampler { namespace gig { Line 1772  namespace LinuxSampler { namespace gig {
1772                      }                      }
1773                  }                  }
1774                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1775                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1776                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1777    
1778                      #if !CONFIG_PROCESS_MUTED_CHANNELS                      #if !CONFIG_PROCESS_MUTED_CHANNELS
# Line 1189  namespace LinuxSampler { namespace gig { Line 1783  namespace LinuxSampler { namespace gig {
1783                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1784                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1785                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1786                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1787                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1788                                if (itNewEvent) {
1789                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1790                                    itNewEvent->Type = Event::type_release; // transform event type
1791                                }
1792                                else dmsg(1,("Event pool emtpy!\n"));
1793                            }
1794                        }
1795                    }
1796                    break;
1797                }
1798                case 65: { // portamento on / off
1799                    const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1800                    if (bPortamento != pEngineChannel->PortamentoMode)
1801                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1802                    pEngineChannel->PortamentoMode = bPortamento;
1803                    break;
1804                }
1805                case 66: { // sostenuto
1806                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1807                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1808                        pEngineChannel->SostenutoPedal = true;
1809    
1810                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1811                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1812                        #endif
1813    
1814                        SostenutoKeyCount = 0;
1815                        // Remeber the pressed keys
1816                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1817                        for (; iuiKey; ++iuiKey) {
1818                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1819                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1820                        }
1821                    }
1822                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1823                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1824                        pEngineChannel->SostenutoPedal = false;
1825    
1826                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1827                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1828                        #endif
1829    
1830                        // release voices if the damper pedal is up and their respective key is not pressed
1831                        for (int i = 0; i < SostenutoKeyCount; i++) {
1832                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1833                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1834                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1835                              if (itNewEvent) {                              if (itNewEvent) {
1836                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list                                  *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
# Line 1201  namespace LinuxSampler { namespace gig { Line 1842  namespace LinuxSampler { namespace gig {
1842                  }                  }
1843                  break;                  break;
1844              }              }
1845                case 100: { // RPN controller LSB
1846                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1847                    break;
1848                }
1849                case 101: { // RPN controller MSB
1850                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1851                    break;
1852                }
1853    
1854    
1855              // Channel Mode Messages              // Channel Mode Messages
# Line 1214  namespace LinuxSampler { namespace gig { Line 1863  namespace LinuxSampler { namespace gig {
1863                  break;                  break;
1864              }              }
1865              case 123: { // all notes off              case 123: { // all notes off
1866                    #if CONFIG_PROCESS_ALL_NOTES_OFF
1867                  ReleaseAllVoices(pEngineChannel, itControlChangeEvent);                  ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1868                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1869                    break;
1870                }
1871                case 126: { // mono mode on
1872                    if (!pEngineChannel->SoloMode)
1873                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1874                    pEngineChannel->SoloMode = true;
1875                    break;
1876                }
1877                case 127: { // poly mode on
1878                    if (pEngineChannel->SoloMode)
1879                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1880                    pEngineChannel->SoloMode = false;
1881                  break;                  break;
1882              }              }
1883          }          }
1884    
1885            // handle FX send controllers
1886            if (!pEngineChannel->fxSends.empty()) {
1887                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1888                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1889                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1890                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1891                        pFxSend->SetInfoChanged(true);
1892                    }
1893                }
1894            }
1895      }      }
1896    
1897      /**      /**
# Line 1226  namespace LinuxSampler { namespace gig { Line 1900  namespace LinuxSampler { namespace gig {
1900       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1901       */       */
1902      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1903          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1904    
1905          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1906          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1234  namespace LinuxSampler { namespace gig { Line 1908  namespace LinuxSampler { namespace gig {
1908          if (exclusive_status != 0xF0)       goto free_sysex_data;          if (exclusive_status != 0xF0)       goto free_sysex_data;
1909    
1910          switch (id) {          switch (id) {
1911                case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1912                    uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1913                    if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1914                    if (!reader.pop(&sub_id1)) goto free_sysex_data;
1915                    if (!reader.pop(&sub_id2)) goto free_sysex_data;
1916                    if (!reader.pop(&val_lsb)) goto free_sysex_data;
1917                    if (!reader.pop(&val_msb)) goto free_sysex_data;
1918                    //TODO: for now we simply ignore the sysex channel, seldom used anyway
1919                    switch (sub_id1) {
1920                        case 0x04: // Device Control
1921                            switch (sub_id2) {
1922                                case 0x01: { // Master Volume
1923                                    const double volume =
1924                                        double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1925                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1926                                    // apply volume to all sampler channels that
1927                                    // are connected to the same MIDI input port
1928                                    // this sysex message arrived on
1929                                    for (int i = 0; i < engineChannels.size(); ++i) {
1930                                        EngineChannel* pEngineChannel = engineChannels[i];
1931                                        if (pEngineChannel->GetMidiInputPort() ==
1932                                            itSysexEvent->pMidiInputPort)
1933                                        {
1934                                            pEngineChannel->Volume(volume);
1935                                        }
1936                                    }
1937                                    #else
1938                                    // apply volume globally to the whole sampler
1939                                    GLOBAL_VOLUME = volume;
1940                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1941                                    break;
1942                                }
1943                            }
1944                            break;
1945                    }
1946                    break;
1947                }
1948              case 0x41: { // Roland              case 0x41: { // Roland
1949                  dmsg(3,("Roland Sysex\n"));                  dmsg(3,("Roland Sysex\n"));
1950                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
# Line 1245  namespace LinuxSampler { namespace gig { Line 1956  namespace LinuxSampler { namespace gig {
1956    
1957                  // command address                  // command address
1958                  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)
1959                  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
1960                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1961                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1962                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
1963                        if (addr[2] == 0x7f) { // GS reset
1964                            for (int i = 0; i < engineChannels.size(); ++i) {
1965                                EngineChannel* pEngineChannel = engineChannels[i];
1966                                if (pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort) {
1967                                    KillAllVoices(pEngineChannel, itSysexEvent);
1968                                    pEngineChannel->ResetControllers();
1969                                }
1970                            }
1971                        }
1972                  }                  }
1973                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters                  else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
1974                      dmsg(3,("\tCommon Parameter\n"));                      dmsg(3,("\tCommon Parameter\n"));
# Line 1270  namespace LinuxSampler { namespace gig { Line 1990  namespace LinuxSampler { namespace gig {
1990                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
1991                              break;                              break;
1992                          }                          }
1993                            case 0x15: { // chromatic / drumkit mode
1994                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1995                                uint8_t part = addr[1] & 0x0f;
1996                                uint8_t map;
1997                                if (!reader.pop(&map)) goto free_sysex_data;
1998                                for (int i = 0; i < engineChannels.size(); ++i) {
1999                                    EngineChannel* pEngineChannel = engineChannels[i];
2000                                    if (
2001                                        (pEngineChannel->midiChannel == part ||
2002                                         pEngineChannel->midiChannel == midi_chan_all) &&
2003                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
2004                                    ) {
2005                                        try {
2006                                            pEngineChannel->SetMidiInstrumentMap(map);
2007                                        } catch (Exception e) {
2008                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
2009                                            goto free_sysex_data;
2010                                        } catch (...) {
2011                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
2012                                            goto free_sysex_data;
2013                                        }
2014                                    }
2015                                }
2016                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
2017                                break;
2018                            }
2019                      }                      }
2020                  }                  }
2021                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
# Line 1292  namespace LinuxSampler { namespace gig { Line 2038  namespace LinuxSampler { namespace gig {
2038       *                     question       *                     question
2039       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
2040       */       */
2041      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) {
2042          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
2043          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
2044          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
2045          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1357  namespace LinuxSampler { namespace gig { Line 2103  namespace LinuxSampler { namespace gig {
2103          }          }
2104      }      }
2105    
2106        /**
2107         * Determines whether the specified voice should be released.
2108         *
2109         * @param pEngineChannel - The engine channel on which the voice should be checked
2110         * @param Key - The key number
2111         * @returns true if the specified should be released, false otherwise.
2112         */
2113        bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
2114            if (pEngineChannel->SustainPedal) return false;
2115    
2116            if (pEngineChannel->SostenutoPedal) {
2117                for (int i = 0; i < SostenutoKeyCount; i++)
2118                    if (Key == SostenutoKeys[i]) return false;
2119            }
2120    
2121            return true;
2122        }
2123    
2124      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
2125          return ActiveVoiceCount;          return atomic_read(&ActiveVoiceCount);
2126        }
2127    
2128        void Engine::SetVoiceCount(uint Count) {
2129            atomic_set(&ActiveVoiceCount, Count);
2130      }      }
2131    
2132      uint Engine::VoiceCountMax() {      uint Engine::VoiceCountMax() {
2133          return ActiveVoiceCountMax;          return ActiveVoiceCountMax;
2134      }      }
2135    
2136        int Engine::MaxVoices() {
2137            return pVoicePool->poolSize();
2138        }
2139    
2140        void Engine::SetMaxVoices(int iVoices) throw (Exception) {
2141            if (iVoices < 1)
2142                throw Exception("Maximum voices for an engine cannot be set lower than 1");
2143    
2144            SuspendAll();
2145    
2146            // NOTE: we need to clear pDimRegionsInUse before deleting pDimRegionPool,
2147            // otherwise memory corruption will occur if there are active voices (see bug #118)
2148            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2149                engineChannels[iChannel]->ClearDimRegionsInUse();
2150            }
2151    
2152            if (pDimRegionPool[0]) delete pDimRegionPool[0];
2153            if (pDimRegionPool[1]) delete pDimRegionPool[1];
2154    
2155            pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices);
2156            pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices);
2157    
2158            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
2159                engineChannels[iChannel]->ResetDimRegionsInUse();
2160            }
2161    
2162            try {
2163                pVoicePool->resizePool(iVoices);
2164            } catch (...) {
2165                throw Exception("FATAL: Could not resize voice pool!");
2166            }
2167    
2168            for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2169                iterVoice->SetEngine(this);
2170                iterVoice->pDiskThread = this->pDiskThread;
2171            }
2172            pVoicePool->clear();
2173    
2174            ResumeAll();
2175        }
2176    
2177      bool Engine::DiskStreamSupported() {      bool Engine::DiskStreamSupported() {
2178          return true;          return true;
2179      }      }
2180    
2181      uint Engine::DiskStreamCount() {      uint Engine::DiskStreamCount() {
2182          return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;          return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0;
2183      }      }
2184    
2185      uint Engine::DiskStreamCountMax() {      uint Engine::DiskStreamCountMax() {
2186          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;          return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0;
2187      }      }
2188    
2189        int Engine::MaxDiskStreams() {
2190            return iMaxDiskStreams;
2191        }
2192    
2193        void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) {
2194            if (iStreams < 0)
2195                throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
2196    
2197            SuspendAll();
2198    
2199            iMaxDiskStreams = iStreams;
2200    
2201            // reconnect to audio output device, because that will automatically
2202            // recreate the disk thread with the required amount of streams
2203            if (pAudioOutputDevice) Connect(pAudioOutputDevice);
2204    
2205            ResumeAll();
2206        }
2207    
2208      String Engine::DiskStreamBufferFillBytes() {      String Engine::DiskStreamBufferFillBytes() {
2209          return pDiskThread->GetBufferFillBytes();          return pDiskThread->GetBufferFillBytes();
2210      }      }
# Line 1390  namespace LinuxSampler { namespace gig { Line 2218  namespace LinuxSampler { namespace gig {
2218      }      }
2219    
2220      String Engine::Description() {      String Engine::Description() {
2221          return "Gigasampler Engine";          return "Gigasampler Format Engine";
2222      }      }
2223    
2224      String Engine::Version() {      String Engine::Version() {
2225          String s = "$Revision: 1.54 $";          String s = "$Revision: 1.102 $";
2226          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
2227      }      }
2228    
2229        InstrumentManager* Engine::GetInstrumentManager() {
2230            return &instruments;
2231        }
2232    
2233        // static constant initializers
2234        const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2235        const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2236        const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2237    
2238        float* Engine::InitVolumeCurve() {
2239            // line-segment approximation
2240            const float segments[] = {
2241                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
2242                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
2243            };
2244            return InitCurve(segments);
2245        }
2246    
2247        float* Engine::InitPanCurve() {
2248            // line-segment approximation
2249            const float segments[] = {
2250                0, 0, 1, 0,
2251                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
2252                127, 1.41, 128, 1.41
2253            };
2254            return InitCurve(segments, 129);
2255        }
2256    
2257        float* Engine::InitCrossfadeCurve() {
2258            // line-segment approximation
2259            const float segments[] = {
2260                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
2261            };
2262            return InitCurve(segments);
2263        }
2264    
2265        float* Engine::InitCurve(const float* segments, int size) {
2266            float* y = new float[size];
2267            for (int x = 0 ; x < size ; x++) {
2268                if (x > segments[2]) segments += 2;
2269                y[x] = segments[1] + (x - segments[0]) *
2270                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
2271            }
2272            return y;
2273        }
2274    
2275  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.775  
changed lines
  Added in v.1893

  ViewVC Help
Powered by ViewVC