/[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 1043 by schoenebeck, Wed Feb 7 21:02:04 2007 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005-2007 Christian Schoenebeck                        *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 51  namespace LinuxSampler { namespace gig { Line 51  namespace LinuxSampler { namespace gig {
51          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
52              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
53              pEngine = engines[pDevice];              pEngine = engines[pDevice];
54    
55                // Disable the engine while the new engine channel is
56                // added and initialized. The engine will be enabled again
57                // in EngineChannel::Connect.
58                pEngine->DisableAndLock();
59          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
60              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
61              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
# Line 97  namespace LinuxSampler { namespace gig { Line 102  namespace LinuxSampler { namespace gig {
102          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
103          pDiskThread        = NULL;          pDiskThread        = NULL;
104          pEventGenerator    = NULL;          pEventGenerator    = NULL;
105          pSysexBuffer       = new RingBuffer<uint8_t>(CONFIG_SYSEX_BUFFER_SIZE, 0);          pSysexBuffer       = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0);
106          pEventQueue        = new RingBuffer<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
107          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
108          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
109            pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];
110          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
111          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
112            InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);
113            InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);
114    
115          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
116              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
117          }          }
# Line 116  namespace LinuxSampler { namespace gig { Line 125  namespace LinuxSampler { namespace gig {
125       * Destructor       * Destructor
126       */       */
127      Engine::~Engine() {      Engine::~Engine() {
128            MidiInputPort::RemoveSysexListener(this);
129          if (pDiskThread) {          if (pDiskThread) {
130              dmsg(1,("Stopping disk thread..."));              dmsg(1,("Stopping disk thread..."));
131              pDiskThread->StopThread();              pDiskThread->StopThread();
# Line 131  namespace LinuxSampler { namespace gig { Line 141  namespace LinuxSampler { namespace gig {
141          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
142          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
143          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
144          EngineFactory::Destroy(this);          Unregister();
145      }      }
146    
147      void Engine::Enable() {      void Engine::Enable() {
# Line 165  namespace LinuxSampler { namespace gig { Line 175  namespace LinuxSampler { namespace gig {
175    
176      /**      /**
177       *  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
178       *  control and status variables. This method is not thread safe!       *  control and status variables. This method is protected by a mutex.
179       */       */
180      void Engine::ResetInternal() {      void Engine::ResetInternal() {
181            ResetInternalMutex.Lock();
182    
183            // make sure that the engine does not get any sysex messages
184            // while it's reseting
185            bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
186          ActiveVoiceCount    = 0;          ActiveVoiceCount    = 0;
187          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
188    
# Line 191  namespace LinuxSampler { namespace gig { Line 206  namespace LinuxSampler { namespace gig {
206          // delete all input events          // delete all input events
207          pEventQueue->init();          pEventQueue->init();
208          pSysexBuffer->init();          pSysexBuffer->init();
209            if (sysexDisabled) MidiInputPort::AddSysexListener(this);
210            ResetInternalMutex.Unlock();
211      }      }
212    
213      /**      /**
# Line 220  namespace LinuxSampler { namespace gig { Line 237  namespace LinuxSampler { namespace gig {
237          }          }
238          catch (AudioOutputException e) {          catch (AudioOutputException e) {
239              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();
240              throw LinuxSamplerException(msg);              throw Exception(msg);
241          }          }
242    
243          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
# Line 249  namespace LinuxSampler { namespace gig { Line 266  namespace LinuxSampler { namespace gig {
266              delete this->pDiskThread;              delete this->pDiskThread;
267              dmsg(1,("OK\n"));              dmsg(1,("OK\n"));
268          }          }
269          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6); //FIXME: assuming stereo          this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
270                                               &instruments);
271          if (!pDiskThread) {          if (!pDiskThread) {
272              dmsg(0,("gig::Engine  new diskthread = NULL\n"));              dmsg(0,("gig::Engine  new diskthread = NULL\n"));
273              exit(EXIT_FAILURE);              exit(EXIT_FAILURE);
# Line 298  namespace LinuxSampler { namespace gig { Line 316  namespace LinuxSampler { namespace gig {
316       *                  current audio cycle       *                  current audio cycle
317       */       */
318      void Engine::ImportEvents(uint Samples) {      void Engine::ImportEvents(uint Samples) {
319          RingBuffer<Event>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();          RingBuffer<Event,false>::NonVolatileReader eventQueueReader = pEventQueue->get_non_volatile_reader();
320          Event* pEvent;          Event* pEvent;
321          while (true) {          while (true) {
322              // get next event from input event queue              // get next event from input event queue
# Line 321  namespace LinuxSampler { namespace gig { Line 339  namespace LinuxSampler { namespace gig {
339      }      }
340    
341      /**      /**
342       *  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.
343       *  calculated audio data of all voices of this engine will be placed into       * The engine will iterate through all engine channels and render audio
344       *  the engine's audio sum buffer which has to be copied and eventually be       * for each engine channel independently. The calculated audio data of
345       *  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
346       *  AlsaIO or JackIO) right after.       * buffers of the respective audio output device, connected to the
347         * respective engine channel.
348       *       *
349       *  @param Samples - number of sample points to be rendered       *  @param Samples - number of sample points to be rendered
350       *  @returns       0 on success       *  @returns       0 on success
351       */       */
352      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
353          dmsg(5,("RenderAudio(Samples=%d)\n", Samples));          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));
354    
355          // return if engine disabled          // return if engine disabled
356          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 368  namespace LinuxSampler { namespace gig { Line 387  namespace LinuxSampler { namespace gig {
387          // reset internal voice counter (just for statistic of active voices)          // reset internal voice counter (just for statistic of active voices)
388          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
389    
390            // handle instrument change commands
391            instrument_change_command_t command;
392            if (InstrumentChangeQueue->pop(&command) > 0) {
393                EngineChannel* pEngineChannel = command.pEngineChannel;
394                pEngineChannel->pInstrument = command.pInstrument;
395    
396                // iterate through all active voices and mark their
397                // dimension regions as "in use". The instrument resource
398                // manager may delete all of the instrument except the
399                // dimension regions and samples that are in use.
400                int i = 0;
401                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
402                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
403                while (iuiKey != end) { // iterate through all active keys
404                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
405                    ++iuiKey;
406    
407                    RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
408                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
409                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
410                        if (!itVoice->Orphan) {
411                            itVoice->Orphan = true;
412                            pDimRegionsInUse[i++] = itVoice->pDimRgn;
413                        }
414                    }
415                }
416                pDimRegionsInUse[i] = 0; // end of list
417    
418                // send a reply to the calling thread, which is waiting
419                instrument_change_reply_t reply;
420                InstrumentChangeReplyQueue->push(&reply);
421            }
422    
423          // handle events on all engine channels          // handle events on all engine channels
424          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  
425              ProcessEvents(engineChannels[i], Samples);              ProcessEvents(engineChannels[i], Samples);
426          }          }
427    
428          // render all 'normal', active voices on all engine channels          // render all 'normal', active voices on all engine channels
429          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  
430              RenderActiveVoices(engineChannels[i], Samples);              RenderActiveVoices(engineChannels[i], Samples);
431          }          }
432    
433          // 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
434          RenderStolenVoices(Samples);          RenderStolenVoices(Samples);
435    
436            // handle audio routing for engine channels with FX sends
437            for (int i = 0; i < engineChannels.size(); i++) {
438                if (engineChannels[i]->fxSends.empty()) continue; // ignore if no FX sends
439                RouteAudio(engineChannels[i], Samples);
440            }
441    
442          // handle cleanup on all engine channels for the next audio fragment          // handle cleanup on all engine channels for the next audio fragment
443          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  
444              PostProcess(engineChannels[i]);              PostProcess(engineChannels[i]);
445          }          }
446    
# Line 504  namespace LinuxSampler { namespace gig { Line 559  namespace LinuxSampler { namespace gig {
559          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();          RTList<Event>::Iterator end               = pVoiceStealingQueue->end();
560          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {          for (; itVoiceStealEvent != end; ++itVoiceStealEvent) {
561              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;              EngineChannel* pEngineChannel = (EngineChannel*) itVoiceStealEvent->pEngineChannel;
562                if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
563              Pool<Voice>::Iterator itNewVoice =              Pool<Voice>::Iterator itNewVoice =
564                  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);
565              if (itNewVoice) {              if (itNewVoice) {
# Line 523  namespace LinuxSampler { namespace gig { Line 579  namespace LinuxSampler { namespace gig {
579      }      }
580    
581      /**      /**
582         * Will be called in case the respective engine channel sports FX send
583         * channels. In this particular case, engine channel local buffers are
584         * used to render and mix all voices to. This method is responsible for
585         * copying the audio data from those local buffers to the master audio
586         * output channels as well as to the FX send audio output channels with
587         * their respective FX send levels.
588         *
589         * @param pEngineChannel - engine channel from which audio should be
590         *                         routed
591         * @param Samples        - amount of sample points to be routed in
592         *                         this audio fragment cycle
593         */
594        void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
595            // route master signal
596            {
597                AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
598                AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
599                pEngineChannel->pChannelLeft->MixTo(pDstL, Samples);
600                pEngineChannel->pChannelRight->MixTo(pDstR, Samples);
601            }
602            // route FX send signal
603            {
604                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
605                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
606                    // left channel
607                    const int iDstL = pFxSend->DestinationChannel(0);
608                    if (iDstL < 0) {
609                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
610                    } else {
611                        AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);
612                        if (!pDstL) {
613                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));
614                        } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());
615                    }
616                    // right channel
617                    const int iDstR = pFxSend->DestinationChannel(1);
618                    if (iDstR < 0) {
619                        dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
620                    } else {
621                        AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);
622                        if (!pDstR) {
623                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));
624                        } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());
625                    }
626                }
627            }
628            // reset buffers with silence (zero out) for the next audio cycle
629            pEngineChannel->pChannelLeft->Clear();
630            pEngineChannel->pChannelRight->Clear();
631        }
632    
633        /**
634       * Free all keys which have turned inactive in this audio fragment, from       * Free all keys which have turned inactive in this audio fragment, from
635       * 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
636       * channel.       * channel.
# Line 599  namespace LinuxSampler { namespace gig { Line 707  namespace LinuxSampler { namespace gig {
707          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
708          #endif          #endif
709    
710            if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
711    
712            //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
713            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
714    
715          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
716            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
717    
718            // move note on event to the key's own event list
719            RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
720    
721            // if Solo Mode then kill all already active voices
722            if (pEngineChannel->SoloMode) {
723                Pool<uint>::Iterator itYoungestKey = pEngineChannel->pActiveKeys->last();
724                if (itYoungestKey) {
725                    const int iYoungestKey = *itYoungestKey;
726                    const midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[iYoungestKey];
727                    if (pOtherKey->Active) {
728                        // get final portamento position of currently active voice
729                        if (pEngineChannel->PortamentoMode) {
730                            RTList<Voice>::Iterator itVoice = pOtherKey->pActiveVoices->last();
731                            if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
732                        }
733                        // kill all voices on the (other) key
734                        RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
735                        RTList<Voice>::Iterator end               = pOtherKey->pActiveVoices->end();
736                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
737                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
738                                itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
739                        }
740                    }
741                }
742                // set this key as 'currently active solo key'
743                pEngineChannel->SoloKey = key;
744            }
745    
746          // Change key dimension value if key is in keyswitching area          // Change key dimension value if key is in keyswitching area
747          {          {
748              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;              const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument;
749              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)              if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high)
750                  pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) /                  pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) /
751                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);                      (pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1);
752          }          }
753    
         midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];  
   
754          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
755          pKey->Velocity   = itNoteOnEvent->Param.Note.Velocity;          pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
756          pKey->NoteOnTime = FrameTime + itNoteOnEvent->FragmentPos(); // will be used to calculate note length          pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
757    
758          // cancel release process of voices on this key if needed          // cancel release process of voices on this key if needed
759          if (pKey->Active && !pEngineChannel->SustainPedal) {          if (pKey->Active && !pEngineChannel->SustainPedal) {
760              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();              RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
761              if (itCancelReleaseEvent) {              if (itCancelReleaseEvent) {
762                  *itCancelReleaseEvent = *itNoteOnEvent;                  // copy event                  *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
763                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                  itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type
764              }              }
765              else dmsg(1,("Event pool emtpy!\n"));              else dmsg(1,("Event pool emtpy!\n"));
766          }          }
767    
         // move note on event to the key's own event list  
         RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);  
   
768          // allocate and trigger new voice(s) for the key          // allocate and trigger new voice(s) for the key
769          {          {
770              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
# Line 644  namespace LinuxSampler { namespace gig { Line 781  namespace LinuxSampler { namespace gig {
781          if (!pKey->Active && !pKey->VoiceTheftsQueued)          if (!pKey->Active && !pKey->VoiceTheftsQueued)
782              pKey->pEvents->free(itNoteOnEventOnKeyList);              pKey->pEvents->free(itNoteOnEventOnKeyList);
783    
784            if (!pEngineChannel->SoloMode || pEngineChannel->PortamentoPos < 0.0f) pEngineChannel->PortamentoPos = (float) key;
785          pKey->RoundRobinIndex++;          pKey->RoundRobinIndex++;
786      }      }
787    
# Line 661  namespace LinuxSampler { namespace gig { Line 799  namespace LinuxSampler { namespace gig {
799          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
800          #endif          #endif
801    
802          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
803            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
804    
805            const int iKey = itNoteOffEvent->Param.Note.Key;
806            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
807          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
808    
809          // release voices on this key if needed          // move event to the key's own event list
810          if (pKey->Active && !pEngineChannel->SustainPedal) {          RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
811              itNoteOffEvent->Type = Event::type_release; // transform event type  
812            bool bShouldRelease = pKey->Active && ShouldReleaseVoice(pEngineChannel, itNoteOffEventOnKeyList->Param.Note.Key);
813    
814            // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
815            if (pEngineChannel->SoloMode && pEngineChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
816                bool bOtherKeysPressed = false;
817                if (iKey == pEngineChannel->SoloKey) {
818                    pEngineChannel->SoloKey = -1;
819                    // if there's still a key pressed down, respawn a voice (group) on the highest key
820                    for (int i = 127; i > 0; i--) {
821                        midi_key_info_t* pOtherKey = &pEngineChannel->pMIDIKeyInfo[i];
822                        if (pOtherKey->KeyPressed) {
823                            bOtherKeysPressed = true;
824                            // make the other key the new 'currently active solo key'
825                            pEngineChannel->SoloKey = i;
826                            // get final portamento position of currently active voice
827                            if (pEngineChannel->PortamentoMode) {
828                                RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
829                                if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
830                            }
831                            // create a pseudo note on event
832                            RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
833                            if (itPseudoNoteOnEvent) {
834                                // copy event
835                                *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
836                                // transform event to a note on event
837                                itPseudoNoteOnEvent->Type                = Event::type_note_on;
838                                itPseudoNoteOnEvent->Param.Note.Key      = i;
839                                itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
840                                // allocate and trigger new voice(s) for the other key
841                                {
842                                    // first, get total amount of required voices (dependant on amount of layers)
843                                    ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(i);
844                                    if (pRegion) {
845                                        int voicesRequired = pRegion->Layers;
846                                        // now launch the required amount of voices
847                                        for (int iLayer = 0; iLayer < voicesRequired; iLayer++)
848                                            LaunchVoice(pEngineChannel, itPseudoNoteOnEvent, iLayer, false, true, false);
849                                    }
850                                }
851                                // if neither a voice was spawned or postponed then remove note on event from key again
852                                if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
853                                    pOtherKey->pEvents->free(itPseudoNoteOnEvent);
854    
855                            } else dmsg(1,("Could not respawn voice, no free event left\n"));
856                            break; // done
857                        }
858                    }
859                }
860                if (bOtherKeysPressed) {
861                    if (pKey->Active) { // kill all voices on this key
862                        bShouldRelease = false; // no need to release, as we kill it here
863                        RTList<Voice>::Iterator itVoiceToBeKilled = pKey->pActiveVoices->first();
864                        RTList<Voice>::Iterator end               = pKey->pActiveVoices->end();
865                        for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
866                            if (itVoiceToBeKilled->Type != Voice::type_release_trigger)
867                                itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
868                        }
869                    }
870                } else pEngineChannel->PortamentoPos = -1.0f;
871            }
872    
873              // 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
874              RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);          if (bShouldRelease) {
875                itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
876    
877              // spawn release triggered voice(s) if needed              // spawn release triggered voice(s) if needed
878              if (pKey->ReleaseTrigger) {              if (pKey->ReleaseTrigger && pEngineChannel->pInstrument) {
879                  // first, get total amount of required voices (dependant on amount of layers)                  // first, get total amount of required voices (dependant on amount of layers)
880                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);                  ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOffEventOnKeyList->Param.Note.Key);
881                  if (pRegion) {                  if (pRegion) {
# Line 687  namespace LinuxSampler { namespace gig { Line 890  namespace LinuxSampler { namespace gig {
890                  }                  }
891                  pKey->ReleaseTrigger = false;                  pKey->ReleaseTrigger = false;
892              }              }
   
             // 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);  
893          }          }
894    
895            // if neither a voice was spawned or postponed on this key then remove note off event from key again
896            if (!pKey->Active && !pKey->VoiceTheftsQueued)
897                pKey->pEvents->free(itNoteOffEventOnKeyList);
898      }      }
899    
900      /**      /**
# Line 775  namespace LinuxSampler { namespace gig { Line 978  namespace LinuxSampler { namespace gig {
978                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;                      DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
979                      break;                      break;
980                  case ::gig::dimension_channelaftertouch:                  case ::gig::dimension_channelaftertouch:
981                      DimValues[i] = 0; //TODO: we currently ignore this dimension                      DimValues[i] = pEngineChannel->ControllerTable[128];
982                      break;                      break;
983                  case ::gig::dimension_releasetrigger:                  case ::gig::dimension_releasetrigger:
984                      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;
985                      DimValues[i] = (uint) ReleaseTriggerVoice;                      DimValues[i] = (uint) ReleaseTriggerVoice;
986                      break;                      break;
987                  case ::gig::dimension_keyboard:                  case ::gig::dimension_keyboard:
988                      DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension;                      DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
989                      break;                      break;
990                  case ::gig::dimension_roundrobin:                  case ::gig::dimension_roundrobin:
991                      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 1070  namespace LinuxSampler { namespace gig {
1070                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;                      std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
1071              }              }
1072          }          }
1073    
1074            // return if this is a release triggered voice and there is no
1075            // releasetrigger dimension (could happen if an instrument
1076            // change has occured between note on and off)
1077            if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
1078    
1079          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);          ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
1080    
1081          // no need to continue if sample is silent          // no need to continue if sample is silent
# Line 1096  namespace LinuxSampler { namespace gig { Line 1305  namespace LinuxSampler { namespace gig {
1305    
1306              uint keygroup = itVoice->KeyGroup;              uint keygroup = itVoice->KeyGroup;
1307    
1308                // if the sample and dimension region belong to an
1309                // instrument that is unloaded, tell the disk thread to
1310                // release them
1311                if (itVoice->Orphan) {
1312                    pDiskThread->OrderDeletionOfDimreg(itVoice->pDimRgn);
1313                }
1314    
1315              // free the voice object              // free the voice object
1316              pVoicePool->free(itVoice);              pVoicePool->free(itVoice);
1317    
# Line 1140  namespace LinuxSampler { namespace gig { Line 1356  namespace LinuxSampler { namespace gig {
1356          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1357          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1358    
1359            // handle hard coded MIDI controllers
1360          switch (itControlChangeEvent->Param.CC.Controller) {          switch (itControlChangeEvent->Param.CC.Controller) {
1361                case 5: { // portamento time
1362                    pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1363                    break;
1364                }
1365                case 6: { // data entry (currently only used for RPN controllers)
1366                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1367                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1368                        // limit to +- two octaves for now
1369                        transpose = RTMath::Min(transpose,  24);
1370                        transpose = RTMath::Max(transpose, -24);
1371                        pEngineChannel->GlobalTranspose = transpose;
1372                        // workaround, so we won't have hanging notes
1373                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1374                    }
1375                    break;
1376                }
1377              case 7: { // volume              case 7: { // volume
1378                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1379                  pEngineChannel->GlobalVolume = (float) itControlChangeEvent->Param.CC.Value / 127.0f;                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
1380                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag                  pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag
1381                  break;                  break;
1382              }              }
1383              case 10: { // panpot              case 10: { // panpot
1384                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1385                  const int pan = (int) itControlChangeEvent->Param.CC.Value - 64;                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1386                  pEngineChannel->GlobalPanLeft  = 1.0f - float(RTMath::Max(pan, 0)) /  63.0f;                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
                 pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f;  
1387                  break;                  break;
1388              }              }
1389              case 64: { // sustain              case 64: { // sustain
1390                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SustainPedal) {
1391                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
1392                      pEngineChannel->SustainPedal = true;                      pEngineChannel->SustainPedal = true;
1393    
1394                      #if !CONFIG_PROCESS_MUTED_CHANNELS                      #if !CONFIG_PROCESS_MUTED_CHANNELS
# Line 1178  namespace LinuxSampler { namespace gig { Line 1410  namespace LinuxSampler { namespace gig {
1410                      }                      }
1411                  }                  }
1412                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {                  if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SustainPedal) {
1413                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("DAMPER (RIGHT) PEDAL UP\n"));
1414                      pEngineChannel->SustainPedal = false;                      pEngineChannel->SustainPedal = false;
1415    
1416                      #if !CONFIG_PROCESS_MUTED_CHANNELS                      #if !CONFIG_PROCESS_MUTED_CHANNELS
# Line 1189  namespace LinuxSampler { namespace gig { Line 1421  namespace LinuxSampler { namespace gig {
1421                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1422                      for (; iuiKey; ++iuiKey) {                      for (; iuiKey; ++iuiKey) {
1423                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];                          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1424                          if (!pKey->KeyPressed) {                          if (!pKey->KeyPressed && ShouldReleaseVoice(pEngineChannel, *iuiKey)) {
1425                                RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1426                                if (itNewEvent) {
1427                                    *itNewEvent = *itControlChangeEvent; // copy event to the key's own event list
1428                                    itNewEvent->Type = Event::type_release; // transform event type
1429                                }
1430                                else dmsg(1,("Event pool emtpy!\n"));
1431                            }
1432                        }
1433                    }
1434                    break;
1435                }
1436                case 65: { // portamento on / off
1437                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1438                    pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64;
1439                    break;
1440                }
1441                case 66: { // sostenuto
1442                    if (itControlChangeEvent->Param.CC.Value >= 64 && !pEngineChannel->SostenutoPedal) {
1443                        dmsg(4,("SOSTENUTO (CENTER) PEDAL DOWN\n"));
1444                        pEngineChannel->SostenutoPedal = true;
1445    
1446                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1447                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1448                        #endif
1449    
1450                        SostenutoKeyCount = 0;
1451                        // Remeber the pressed keys
1452                        RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
1453                        for (; iuiKey; ++iuiKey) {
1454                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
1455                            if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
1456                        }
1457                    }
1458                    if (itControlChangeEvent->Param.CC.Value < 64 && pEngineChannel->SostenutoPedal) {
1459                        dmsg(4,("SOSTENUTO (CENTER) PEDAL UP\n"));
1460                        pEngineChannel->SostenutoPedal = false;
1461    
1462                        #if !CONFIG_PROCESS_MUTED_CHANNELS
1463                        if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1464                        #endif
1465    
1466                        // release voices if the damper pedal is up and their respective key is not pressed
1467                        for (int i = 0; i < SostenutoKeyCount; i++) {
1468                            midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[SostenutoKeys[i]];
1469                            if (!pKey->KeyPressed && !pEngineChannel->SustainPedal) {
1470                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                              RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
1471                              if (itNewEvent) {                              if (itNewEvent) {
1472                                  *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 1478  namespace LinuxSampler { namespace gig {
1478                  }                  }
1479                  break;                  break;
1480              }              }
1481                case 100: { // RPN controller LSB
1482                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1483                    break;
1484                }
1485                case 101: { // RPN controller MSB
1486                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1487                    break;
1488                }
1489    
1490    
1491              // Channel Mode Messages              // Channel Mode Messages
# Line 1214  namespace LinuxSampler { namespace gig { Line 1499  namespace LinuxSampler { namespace gig {
1499                  break;                  break;
1500              }              }
1501              case 123: { // all notes off              case 123: { // all notes off
1502                    #if CONFIG_PROCESS_ALL_NOTES_OFF
1503                  ReleaseAllVoices(pEngineChannel, itControlChangeEvent);                  ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1504                    #endif // CONFIG_PROCESS_ALL_NOTES_OFF
1505                    break;
1506                }
1507                case 126: { // mono mode on
1508                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1509                    pEngineChannel->SoloMode = true;
1510                  break;                  break;
1511              }              }
1512                case 127: { // poly mode on
1513                    KillAllVoices(pEngineChannel, itControlChangeEvent);
1514                    pEngineChannel->SoloMode = false;
1515                    break;
1516                }
1517            }
1518    
1519            // handle FX send controllers
1520            if (!pEngineChannel->fxSends.empty()) {
1521                for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1522                    FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1523                    if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1524                        pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1525                }
1526          }          }
1527      }      }
1528    
# Line 1226  namespace LinuxSampler { namespace gig { Line 1532  namespace LinuxSampler { namespace gig {
1532       *  @param itSysexEvent - sysex data size and time stamp of the sysex event       *  @param itSysexEvent - sysex data size and time stamp of the sysex event
1533       */       */
1534      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {      void Engine::ProcessSysex(Pool<Event>::Iterator& itSysexEvent) {
1535          RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();          RingBuffer<uint8_t,false>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
1536    
1537          uint8_t exclusive_status, id;          uint8_t exclusive_status, id;
1538          if (!reader.pop(&exclusive_status)) goto free_sysex_data;          if (!reader.pop(&exclusive_status)) goto free_sysex_data;
# Line 1245  namespace LinuxSampler { namespace gig { Line 1551  namespace LinuxSampler { namespace gig {
1551    
1552                  // command address                  // command address
1553                  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)
1554                  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
1555                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;                  if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
1556                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters                  if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
1557                      dmsg(3,("\tSystem Parameter\n"));                      dmsg(3,("\tSystem Parameter\n"));
# Line 1292  namespace LinuxSampler { namespace gig { Line 1598  namespace LinuxSampler { namespace gig {
1598       *                     question       *                     question
1599       * @param DataSize   - size of the GS message data (in bytes)       * @param DataSize   - size of the GS message data (in bytes)
1600       */       */
1601      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) {
1602          RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;          RingBuffer<uint8_t,false>::NonVolatileReader reader = AddrReader;
1603          uint bytes = 3 /*addr*/ + DataSize;          uint bytes = 3 /*addr*/ + DataSize;
1604          uint8_t addr_and_data[bytes];          uint8_t addr_and_data[bytes];
1605          reader.read(&addr_and_data[0], bytes);          reader.read(&addr_and_data[0], bytes);
# Line 1357  namespace LinuxSampler { namespace gig { Line 1663  namespace LinuxSampler { namespace gig {
1663          }          }
1664      }      }
1665    
1666        /**
1667         * Determines whether the specified voice should be released.
1668         *
1669         * @param pEngineChannel - The engine channel on which the voice should be checked
1670         * @param Key - The key number
1671         * @returns true if the specified should be released, false otherwise.
1672         */
1673        bool Engine::ShouldReleaseVoice(EngineChannel* pEngineChannel, int Key) {
1674            if (pEngineChannel->SustainPedal) return false;
1675    
1676            if (pEngineChannel->SostenutoPedal) {
1677                for (int i = 0; i < SostenutoKeyCount; i++)
1678                    if (Key == SostenutoKeys[i]) return false;
1679            }
1680    
1681            return true;
1682        }
1683    
1684      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
1685          return ActiveVoiceCount;          return ActiveVoiceCount;
1686      }      }
# Line 1394  namespace LinuxSampler { namespace gig { Line 1718  namespace LinuxSampler { namespace gig {
1718      }      }
1719    
1720      String Engine::Version() {      String Engine::Version() {
1721          String s = "$Revision: 1.54 $";          String s = "$Revision: 1.74 $";
1722          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
1723      }      }
1724    
1725        InstrumentManager* Engine::GetInstrumentManager() {
1726            return &instruments;
1727        }
1728    
1729        // static constant initializers
1730        const float* Engine::VolumeCurve(InitVolumeCurve());
1731        const float* Engine::PanCurve(InitPanCurve());
1732        const float* Engine::CrossfadeCurve(InitCrossfadeCurve());
1733    
1734        float* Engine::InitVolumeCurve() {
1735            // line-segment approximation
1736            const float segments[] = {
1737                0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2,
1738                64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2
1739            };
1740            return InitCurve(segments);
1741        }
1742    
1743        float* Engine::InitPanCurve() {
1744            // line-segment approximation
1745            const float segments[] = {
1746                0, 0, 1, 0,
1747                2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12,
1748                127, 1.41, 128, 1.41
1749            };
1750            return InitCurve(segments, 129);
1751        }
1752    
1753        float* Engine::InitCrossfadeCurve() {
1754            // line-segment approximation
1755            const float segments[] = {
1756                0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1
1757            };
1758            return InitCurve(segments);
1759        }
1760    
1761        float* Engine::InitCurve(const float* segments, int size) {
1762            float* y = new float[size];
1763            for (int x = 0 ; x < size ; x++) {
1764                if (x > segments[2]) segments += 2;
1765                y[x] = segments[1] + (x - segments[0]) *
1766                    (segments[3] - segments[1]) / (segments[2] - segments[0]);
1767            }
1768            return y;
1769        }
1770    
1771        /**
1772         * Changes the instrument for an engine channel.
1773         *
1774         * @param pEngineChannel - engine channel on which the instrument
1775         *                         should be changed
1776         * @param pInstrument - new instrument
1777         * @returns a list of dimension regions from the old instrument
1778         *          that are still in use
1779         */
1780        ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {
1781            instrument_change_command_t command;
1782            command.pEngineChannel = pEngineChannel;
1783            command.pInstrument = pInstrument;
1784            InstrumentChangeQueue->push(&command);
1785    
1786            // wait for the audio thread to confirm that the instrument
1787            // change has been done
1788            instrument_change_reply_t reply;
1789            while (InstrumentChangeReplyQueue->pop(&reply) == 0) {
1790                usleep(10000);
1791            }
1792            return pDimRegionsInUse;
1793        }
1794    
1795  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

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

  ViewVC Help
Powered by ViewVC