/[svn]/linuxsampler/trunk/src/engines/EngineBase.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/EngineBase.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2559 by schoenebeck, Sun May 18 17:38:25 2014 UTC revision 3293 by schoenebeck, Tue Jun 27 22:19:19 2017 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   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 32  Line 33 
33  #include "InstrumentManager.h"  #include "InstrumentManager.h"
34  #include "../common/global_private.h"  #include "../common/global_private.h"
35    
36    // a bit headroom over CONFIG_MAX_VOICES to avoid minor complications i.e. under voice stealing conditions
37    #define MAX_NOTES_HEADROOM  3
38    #define GLOBAL_MAX_NOTES    (GLOBAL_MAX_VOICES * MAX_NOTES_HEADROOM)
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
# Line 45  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49          class IM  /* Instrument Manager */,          class IM  /* Instrument Manager */,
50          class I   /* Instrument */          class I   /* Instrument */
51      >      >
52      class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {      class EngineBase: public AbstractEngine, public RegionPools<R>, public NotePool<V> {
53    
54          public:          public:
55                typedef typename RTList< Note<V> >::Iterator NoteIterator;
56              typedef typename RTList<V>::Iterator VoiceIterator;              typedef typename RTList<V>::Iterator VoiceIterator;
57              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 79  namespace LinuxSampler { Line 97  namespace LinuxSampler {
97                      dmsg(1,("OK\n"));                      dmsg(1,("OK\n"));
98                  }                  }
99    
100                    if (pNotePool) {
101                        pNotePool->clear();
102                        delete pNotePool;
103                    }
104    
105                  if (pVoicePool) {                  if (pVoicePool) {
106                      pVoicePool->clear();                      pVoicePool->clear();
107                      delete pVoicePool;                      delete pVoicePool;
# Line 140  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163                                  dmsg(5,("Engine: Sysex received\n"));                                  dmsg(5,("Engine: Sysex received\n"));
164                                  ProcessSysex(itEvent);                                  ProcessSysex(itEvent);
165                                  break;                                  break;
166                                default: ; // noop
167                          }                          }
168                      }                      }
169                  }                  }
# Line 235  namespace LinuxSampler { Line 259  namespace LinuxSampler {
259                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
260                  }                  }
261    
262                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
263                  try {                  try {
264                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
265                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
266                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
267                  } catch (...) {                  } catch (...) {
268                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
269                  }                  }
270    
271                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
272                         iterVoice; iterVoice = pVoicePool->allocAppend())
273                    {
274                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
275                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
276                  }                  }
277                  pVoicePool->clear();                  pVoicePool->clear();
278    
279                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
280                         itNote = pNotePool->allocAppend())
281                    {
282                        itNote->init(pVoicePool, &noteIDPool);
283                    }
284                    pNotePool->clear();
285    
286                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
287                  ResumeAll();                  ResumeAll();
288              }              }
# Line 315  namespace LinuxSampler { Line 351  namespace LinuxSampler {
351                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
352                      // lower minimum release time                      // lower minimum release time
353                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
354                        pVoicePool->clear();
355                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
356                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
357                      }                      }
# Line 335  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
373                  }                  }
374    
375                    pVoicePool->clear();
376                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
377                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
378                      dmsg(3,("d"));                      dmsg(3,("d"));
379                  }                  }
380                  pVoicePool->clear();                  pVoicePool->clear();
381    
382                  // (re)create event generator                  // update event generator
383                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
384    
385                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
386                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 432  namespace LinuxSampler { Line 469  namespace LinuxSampler {
469               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
470               */               */
471              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
472                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
473                  {                  {
474                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
475                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
476                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
477                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
478                  }                  }
479                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
480              }              }
481    
482              /**              /**
# Line 449  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
487               */               */
488              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
489                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
490                  {                  {
491                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
492                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
493                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
494                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  }                  }
496                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
497              }              }
498    
499              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 559  namespace LinuxSampler { Line 596  namespace LinuxSampler {
596              }              }
597    
598              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
599              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
600                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 585  namespace LinuxSampler { Line 624  namespace LinuxSampler {
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
# Line 608  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648    
649              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
650              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
653              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
658              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
694    
695                    // usually the new note (and its subsequent voices) will be
696                    // allocated on the key provided by the event's note number,
697                    // however if this new note is requested not to be a regular
698                    // note, but rather a child note, then this new note will be
699                    // allocated on the parent note's key instead in order to
700                    // release the child note simultaniously with its parent note
701                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
702    
703                    // in case this new note was requested to be a child note,
704                    // then retrieve its parent note and link them with each other
705                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
706                    if (parentNoteID) {
707                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
708                        if (itParentNote) {
709                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
710                            if (itChildNoteID) {
711                                // link parent and child note with each other
712                                *itChildNoteID = newNoteID;
713                                itNewNote->parentNoteID = parentNoteID;
714                                itNewNote->hostKey = itParentNote->hostKey;
715                            } else {    
716                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
717                                pNotePool->free(itNewNote);
718                                return 0; // error
719                            }
720                        } else {
721                            // the parent note was apparently released already, so
722                            // free the new note again and inform caller that it
723                            // should drop the event
724                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
725                            pNotePool->free(itNewNote);
726                            return 0; // error
727                        }
728                    }
729    
730                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
731    
732                    // copy event which caused this note
733                    itNewNote->cause = *itNoteOnEvent;
734                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
735                    if (!itNewNote->eventID) {
736                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
737                    }
738    
739                    // move new note to its host key
740                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
741                    itNewNote.moveToEndOf(pKey->pActiveNotes);
742    
743                    // assign unique note ID of this new note to the original note on event
744                    itNoteOnEvent->Param.Note.ID = newNoteID;
745    
746                    return newNoteID; // success
747                }
748    
749              /**              /**
750               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
751               * engine channel.               * engine channel.
# Line 631  namespace LinuxSampler { Line 761  namespace LinuxSampler {
761                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
762                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
763    
764                  // process events                  // if a valid real-time instrument script is loaded, pre-process
765                    // the event list by running the script now, since the script
766                    // might filter events or add new ones for this cycle
767                    if (pChannel->pScript) {
768                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
769    
770                        // resume suspended script executions been scheduled for
771                        // this audio fragment cycle (which were suspended in a
772                        // previous audio fragment cycle)
773                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
774    
775                        // spawn new script executions for the new MIDI events of
776                        // this audio fragment cycle
777                        //
778                        // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
779                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
780                            end = pChannel->pEvents->end(); itEvent != end; )
781                        {
782                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
783                            RTList<Event>::Iterator itNext = itEvent;
784                            ++itNext;
785    
786                            switch (itEvent->Type) {
787                                case Event::type_note_on:
788                                    if (pChannel->pScript->handlerNote)
789                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
790                                    break;
791                                case Event::type_note_off:
792                                    if (pChannel->pScript->handlerRelease)
793                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
794                                    break;
795                                case Event::type_control_change:
796                                case Event::type_channel_pressure:
797                                case Event::type_pitchbend:
798                                    if (pChannel->pScript->handlerController)
799                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
800                                    break;
801                                case Event::type_note_pressure:
802                                    //TODO: ...
803                                    break;
804    
805                                case Event::type_sysex:
806                                    //TODO: ...
807                                    break;
808    
809                                case Event::type_cancel_release_key:
810                                case Event::type_release_key:
811                                case Event::type_release_note:
812                                case Event::type_play_note:
813                                case Event::type_stop_note:
814                                case Event::type_kill_note:
815                                case Event::type_note_synth_param:
816                                    break; // noop
817                            }
818    
819                            // see HACK comment above
820                            itEvent = itNext;
821                        }
822    
823                        // this has to be run again, since the newly spawned scripts
824                        // above may have cause suspended scripts that must be
825                        // resumed within this same audio fragment cycle
826                        //
827                        // FIXME: see FIXME comment above
828                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
829                    }
830    
831                    // if there are any delayed events scheduled for the current
832                    // audio fragment cycle, then move and sort them into the main
833                    // event list
834                    if (!pChannel->delayedEvents.queue.isEmpty()) {
835                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
836                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
837                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
838                        while (true) {
839                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
840                                pEventGenerator->popNextScheduledEvent(
841                                    pChannel->delayedEvents.queue,
842                                    pChannel->delayedEvents.schedulerNodes,
843                                    fragmentEndTime
844                                );
845                            if (!itDelayedEventNode) break;
846                            // get the actual delayed event object and free the used scheduler node
847                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
848                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
849                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
850                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
851                                continue;
852                            }
853                            // skip all events on main event list which have a time
854                            // before (or equal to) the delayed event to be inserted
855                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
856                                 ++itEvent);
857                            // now move delayed event from delayedEvents.pList to
858                            // the current position on the main event list
859                            itEvent = itDelayedEvent.moveBefore(itEvent);
860                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
861                        }
862                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
863                    }
864    
865                    // now process all events regularly
866                  {                  {
867                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
868                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 641  namespace LinuxSampler { Line 872  namespace LinuxSampler {
872                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
873                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
874                                  break;                                  break;
875                                case Event::type_play_note:
876                                    dmsg(5,("Engine: Play Note received\n"));
877                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
878                                    break;
879                              case Event::type_note_off:                              case Event::type_note_off:
880                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
881                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
882                                  break;                                  break;
883                                case Event::type_stop_note:
884                                    dmsg(5,("Engine: Stop Note received\n"));
885                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
886                                    break;
887                                case Event::type_kill_note:
888                                    dmsg(5,("Engine: Kill Note received\n"));
889                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
890                                    break;
891                              case Event::type_control_change:                              case Event::type_control_change:
892                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
893                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 661  namespace LinuxSampler { Line 904  namespace LinuxSampler {
904                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
905                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
906                                  break;                                  break;
907                                case Event::type_note_synth_param:
908                                    dmsg(5,("Engine: Note Synth Param received\n"));
909                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
910                                    break;
911                                case Event::type_sysex:
912                                    break; // TODO ...
913    
914                                case Event::type_cancel_release_key:
915                                case Event::type_release_key:
916                                case Event::type_release_note:
917                                    break; // noop
918                          }                          }
919                      }                      }
920                  }                  }
# Line 668  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
923                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
924                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
925                    itLastStolenNote          = NoteIterator();
926                    itLastStolenNoteGlobally  = NoteIterator();
927                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
928                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
929                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
930              }              }
931    
932              /**              /**
933                 * Run all suspended script execution instances which are scheduled
934                 * to be resumed for the current audio fragment cycle.
935                 *
936                 * @param pChannel - engine channel on which suspended events occurred
937                 */
938                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
939                    while (true) {
940                        RTList<ScriptEvent>::Iterator itEvent =
941                            pEventGenerator->popNextScheduledScriptEvent(
942                                pChannel->pScript->suspendedEvents,
943                                *pChannel->pScript->pEvents, fragmentEndTime
944                            );
945                        if (!itEvent) break;
946                        ResumeScriptEvent(pChannel, itEvent);
947                    }
948                }
949    
950                /** @brief Call instrument script's event handler for this event.
951                 *
952                 * Causes a new execution instance of the currently loaded real-time
953                 * instrument script's event handler (callback) to be spawned for
954                 * the given MIDI event.
955                 *
956                 * @param pChannel - engine channel on which the MIDI event occurred
957                 * @param itEvent - MIDI event that causes this new script execution
958                 * @param pEventHandler - script's event handler to be executed
959                 */
960                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
961                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
962                    // check if polyphonic data is passed from "note" to "release"
963                    // script event handlers
964                    if (pEventHandler == pChannel->pScript->handlerRelease &&
965                        pChannel->pScript->handlerNote &&
966                        pChannel->pScript->handlerNote->isPolyphonic() &&
967                        pChannel->pScript->handlerRelease->isPolyphonic() &&
968                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
969                    {
970                        // polyphonic variable data is used/passed from "note" to
971                        // "release" script callback, so we have to recycle the
972                        // original "note on" script event(s)
973                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
974                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
975                        for (; it != end; ++it) {
976                            ProcessScriptEvent(
977                                pChannel, itEvent, pEventHandler, it
978                            );
979                        }
980                    } else {
981                        // no polyphonic data is used/passed from "note" to
982                        // "release" script callback, so just use a new fresh
983                        // script event object
984                        RTList<ScriptEvent>::Iterator itScriptEvent =
985                            pChannel->pScript->pEvents->allocAppend();
986                        // if event handler uses polyphonic variables, reset them
987                        // to zero values before starting to execute the handler
988                        if (pEventHandler->isPolyphonic())
989                            itScriptEvent->execCtx->resetPolyphonicData();
990                        ProcessScriptEvent(
991                            pChannel, itEvent, pEventHandler, itScriptEvent
992                        );
993                    }
994                }
995    
996                /** @brief Spawn new execution instance of an instrument script handler.
997                 *
998                 * Will be called to initiate a new execution of a real-time
999                 * instrument script event right from the start of the script's
1000                 * respective handler. If script execution did not complete after
1001                 * calling this method, the respective script exeuction is then
1002                 * suspended and a call to ResumeScriptEvent() will be used next
1003                 * time to continue its execution.
1004                 *
1005                 * @param pChannel - engine channel this script is running for
1006                 * @param itEvent - event which caused execution of this script
1007                 *                  event handler
1008                 * @param pEventHandler - VM representation of event handler to be
1009                 *                        executed
1010                 * @param itScriptEvent - script event that shall be processed
1011                 */
1012                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1013                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1014    
1015                    // fill the list of script handlers to be executed by this event
1016                    int i = 0;
1017                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1018                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1019    
1020                    // initialize/reset other members
1021                    itScriptEvent->cause = *itEvent;
1022                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1023                    itScriptEvent->currentHandler = 0;
1024                    itScriptEvent->executionSlices = 0;
1025                    itScriptEvent->ignoreAllWaitCalls = false;
1026                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1027                    itScriptEvent->parentHandlerID = 0;
1028                    itScriptEvent->childHandlerID[0] = 0;
1029                    itScriptEvent->autoAbortByParent = false;
1030                    itScriptEvent->forkIndex = 0;
1031                    // this is the native representation of the $EVENT_ID script variable
1032                    itScriptEvent->id =
1033                        (itEvent->Type == Event::type_note_on)
1034                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1035                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1036    
1037                    // run script handler(s)
1038                    VMExecStatus_t res = pScriptVM->exec(
1039                        pChannel->pScript->parserContext, &*itScriptEvent
1040                    );
1041    
1042                    // was the script suspended?
1043                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1044                        // in case the script was suspended, keep it on the allocated
1045                        // ScriptEvent list to be resume at the scheduled time in future,
1046                        // additionally insert it into a sorted time queue
1047                        pEventGenerator->scheduleAheadMicroSec(
1048                            pChannel->pScript->suspendedEvents, // scheduler queue
1049                            *itScriptEvent, // script event
1050                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1051                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1052                        );
1053                    } else { // script execution has finished without 'suspended' status ...
1054                        // if "polyphonic" variable data is passed from script's
1055                        // "note" event handler to its "release" event handler, then
1056                        // the script event must be kept and recycled for the later
1057                        // occuring "release" script event ...
1058                        if (pEventHandler == pChannel->pScript->handlerNote &&
1059                            pChannel->pScript->handlerRelease &&
1060                            pChannel->pScript->handlerNote->isPolyphonic() &&
1061                            pChannel->pScript->handlerRelease->isPolyphonic())
1062                        {
1063                            const int key = itEvent->Param.Note.Key;
1064                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1065                        } else {
1066                            // ... otherwise if no polyphonic data is passed and
1067                            // script's execution has finished without suspension
1068                            // status, then free the script event for a new future
1069                            // script event to be triggered from start
1070                            pChannel->pScript->pEvents->free(itScriptEvent);
1071                        }
1072                    }
1073                }
1074    
1075                /** @brief Resume execution of instrument script.
1076                 *
1077                 * Will be called to resume execution of a real-time instrument
1078                 * script event which has been suspended previously.
1079                 *
1080                 * Script execution might be suspended for various reasons. Usually
1081                 * a script will be suspended if the script called the built-in
1082                 * "wait()" function, but it might also be suspended automatically
1083                 * if the script took too much execution time in an audio fragment
1084                 * cycle. So in the latter case automatic suspension is performed in
1085                 * order to avoid harm for the sampler's overall real-time
1086                 * requirements.
1087                 *
1088                 * @param pChannel - engine channel this script is running for
1089                 * @param itScriptEvent - script execution that shall be resumed
1090                 */
1091                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1092                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1093    
1094                    // run script
1095                    VMExecStatus_t res = pScriptVM->exec(
1096                        pChannel->pScript->parserContext, &*itScriptEvent
1097                    );
1098    
1099                    // was the script suspended?
1100                    if (res & VM_EXEC_SUSPENDED) {
1101                        // in case the script was suspended, keep it on the allocated
1102                        // ScriptEvent list to be resume at the scheduled time in future,
1103                        // additionally insert it into a sorted time queue
1104                        pEventGenerator->scheduleAheadMicroSec(
1105                            pChannel->pScript->suspendedEvents, // scheduler queue
1106                            *itScriptEvent, // script event
1107                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1108                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1109                        );
1110                    } else { // script execution has finished without 'suspended' status ...
1111                        // if "polyphonic" variable data is passed from script's
1112                        // "note" event handler to its "release" event handler, then
1113                        // the script event must be kept and recycled for the later
1114                        // occuring "release" script event ...
1115                        if (handler && handler == pChannel->pScript->handlerNote &&
1116                            pChannel->pScript->handlerRelease &&
1117                            pChannel->pScript->handlerNote->isPolyphonic() &&
1118                            pChannel->pScript->handlerRelease->isPolyphonic())
1119                        {
1120                            const int key = itScriptEvent->cause.Param.Note.Key;
1121                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1122                        } else {
1123                            // ... otherwise if no polyphonic data is passed and
1124                            // script's execution has finished without suspension
1125                            // status, then free the script event for a new future
1126                            // script event to be triggered from start
1127                            pChannel->pScript->pEvents->free(itScriptEvent);
1128                        }
1129                    }
1130                }
1131    
1132                /**
1133               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1134               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1135               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1136               *  voice actually died.               *  voice actually died.
1137               *               *
1138               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1139               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1140               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1141               */               */
1142              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1143                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1144                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1145                      return -1;                      return -1;
# Line 691  namespace LinuxSampler { Line 1147  namespace LinuxSampler {
1147    
1148                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1149    
1150                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1151                        dmsg(1,("Event pool emtpy!\n"));
1152                        return -1;
1153                    }
1154    
1155                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1156                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1157                          return 0;                      return 0;
1158                      }                  }
1159    
1160                      // if we couldn't steal a voice from the same engine channel then                  // if we couldn't steal a voice from the same engine channel then
1161                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1162                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1163                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1164                      int                       iChannelIndex;                  int                          iChannelIndex;
1165                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1166    
1167                      // select engine channel                  // select engine channel
1168                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1169                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1170                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1171                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1172                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1173                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1174                      }                  }
1175    
1176                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1177                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1178                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1179                          do {                      do {
1180                              ++itSelectedVoice;                          ++itSelectedVoice;
1181                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1182                    }
1183                    // did we find a 'stealable' voice?
1184                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1185                        // remember which voice we stole, so we can simply proceed on next voice stealing
1186                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1187                        // done
1188                        goto stealable_voice_found;
1189                    }
1190    
1191                    // get (next) oldest note
1192                    if (this->itLastStolenNoteGlobally) {
1193                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1194                             itNote; ++itNote)
1195                        {
1196                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1197                                // proceed iterating if voice was created in this audio fragment cycle
1198                                if (itSelectedVoice->IsStealable()) {
1199                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1200                                    this->itLastStolenNoteGlobally  = itNote;
1201                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1202                                    goto stealable_voice_found; // selection succeeded
1203                                }
1204                            }
1205                      }                      }
1206                    }
1207    
1208                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1209                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1210                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1211    
1212                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1213                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1214                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1215                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1216                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1217                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1218                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1219                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1220                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1221                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1222                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1223                                itSelectedVoice = itNote->pActiveVoices->first();
1224                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1225                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1226                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1227                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1228                                  // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing                                  // remember which voice of which note on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1229                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1230                                    this->itLastStolenNoteGlobally  = itNote;
1231                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1232                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1233                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1234                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // get next engine channel  
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
1235                          }                          }
1236                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1237                      }                      }
1238                        // get next engine channel
1239                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1240                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1241    
1242                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1243                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1244                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1245                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1246                            dmsg(1,("Exiting.\n"));
1247                            exit(-1);
1248                      }                      }
1249                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1250                    }
1251    
1252                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1253                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
1254    
1255                      --VoiceSpawnsLeft;                  #if CONFIG_DEVMODE
1256                    if (!itSelectedVoice->IsActive()) {
1257                      return 0; // success                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                 }  
                 else {  
                     dmsg(1,("Event pool emtpy!\n"));  
1258                      return -1;                      return -1;
1259                  }                  }
1260                    #endif // CONFIG_DEVMODE
1261    
1262                    // now kill the selected voice
1263                    itSelectedVoice->Kill(itNoteOnEvent);
1264    
1265                    --VoiceSpawnsLeft;
1266    
1267                    return 0; // success
1268              }              }
1269    
1270              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 805  namespace LinuxSampler { Line 1286  namespace LinuxSampler {
1286                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1287                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1288                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1289                            pEngineChannel->pScript =
1290                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1291                          instrumentChanged = true;                          instrumentChanged = true;
1292    
1293                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1294    
1295                            // the script's "init" event handler is only executed
1296                            // once (when the script is loaded or reloaded)
1297                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1298                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1299                                RTList<ScriptEvent>::Iterator itScriptEvent =
1300                                    pEngineChannel->pScript->pEvents->allocAppend();
1301    
1302                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1303                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1304                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1305                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1306                                itScriptEvent->id = 0;
1307                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1308                                itScriptEvent->handlers[1] = NULL;
1309                                itScriptEvent->currentHandler = 0;
1310                                itScriptEvent->executionSlices = 0;
1311                                itScriptEvent->ignoreAllWaitCalls = false;
1312                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1313                                itScriptEvent->parentHandlerID = 0;
1314                                itScriptEvent->childHandlerID[0] = 0;
1315                                itScriptEvent->autoAbortByParent = false;
1316                                itScriptEvent->forkIndex = 0;
1317    
1318                                VMExecStatus_t res;
1319                                size_t instructionsCount = 0;
1320                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1321                                bool bWarningShown = false;
1322                                do {
1323                                    res = pScriptVM->exec(
1324                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1325                                    );
1326                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1327                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1328                                        bWarningShown = true;
1329                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1330                                    }
1331                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1332    
1333                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1334                            }
1335                      }                      }
1336                  }                  }
1337    
# Line 858  namespace LinuxSampler { Line 1382  namespace LinuxSampler {
1382                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1383                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1384                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1385                        
1386                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1387                          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);
1388                      if (itNewVoice) {                      if (itNewVoice) {
1389                            // usually there should already be a new Note object
1390                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1391                            if (!itNote) { // should not happen, but just to be sure ...
1392                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1393                                if (!noteID) {
1394                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1395                                    continue;
1396                                }
1397                                itNote = GetNotePool()->fromID(noteID);
1398                            }
1399                            // move voice from whereever it was, to the new note's list of active voices
1400                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1401                            // render audio of this new voice for the first time
1402                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1403                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1404                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 898  namespace LinuxSampler { Line 1436  namespace LinuxSampler {
1436                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1437    
1438                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1439                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1440                    pChannel->ClearEventListsOfCurrentFragment();
1441              }              }
1442    
1443              /**              /**
# Line 963  namespace LinuxSampler { Line 1502  namespace LinuxSampler {
1502                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1503                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1504                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1505                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1506                                      if (note < 128)                                      if (note < 128)
1507                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1508                                      break;                                      break;
# Line 971  namespace LinuxSampler { Line 1510  namespace LinuxSampler {
1510                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1511                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1512                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1513                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1514                                      if (note < 128)                                      if (note < 128)
1515                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1516                                      break;                                      break;
# Line 1124  namespace LinuxSampler { Line 1663  namespace LinuxSampler {
1663              /**              /**
1664               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1665               *               *
1666               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1667               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1668               */               */
1669              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1670                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1671                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1672    
                 //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  
                 int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;  
                 if (k < 0 || k > 127) return; //ignore keys outside the key range  
   
                 itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;  
                 int vel = itNoteOnEvent->Param.Note.Velocity;  
   
1673                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1674                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1675                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1676    
1677                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1678    
1679                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1680                    // programmatically spawned notes (Event::type_play_note). We have
1681                    // to distinguish between them, since certain processing below
1682                    // must only be done on real MIDI note-on events (i.e. for
1683                    // correctly updating which MIDI keys are currently pressed down).
1684                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1685    
1686                    if (isRealMIDINoteOnEvent)
1687                        pChannel->listeners.PreProcessNoteOn(key, vel);
1688    
1689                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1690                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1691                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1692                            pChannel->listeners.PostProcessNoteOn(key, vel);
1693                      return;                      return;
1694                  }                  }
1695                  #endif                  #endif
1696    
1697                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1698                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1699                            pChannel->listeners.PostProcessNoteOn(key, vel);
1700                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1701                  }                  }
1702    
# Line 1158  namespace LinuxSampler { Line 1704  namespace LinuxSampler {
1704                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1705    
1706                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1707                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1708                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1709                      if (itYoungestKey) {                      if (itYoungestKey) {
1710                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1166  namespace LinuxSampler { Line 1712  namespace LinuxSampler {
1712                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1713                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1714                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1715                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1716                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1717                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1718                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1719                                    }
1720                              }                              }
1721                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1722                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1723                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1724                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1725                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1726                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1727                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1728                                    }
1729                              }                              }
1730                          }                          }
1731                      }                      }
# Line 1182  namespace LinuxSampler { Line 1733  namespace LinuxSampler {
1733                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1734                  }                  }
1735    
1736                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1737                        pChannel->ProcessKeySwitchChange(key);
1738    
1739                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1740                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1741                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1742                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1743                    }
1744    
1745                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1746                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1747                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1748                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1749                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1750                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1751                      }                      }
1752                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1753                  }                  }
# Line 1204  namespace LinuxSampler { Line 1758  namespace LinuxSampler {
1758                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1759                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1760    
1761                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1762                        pChannel->PortamentoPos = (float) key;
1763    
1764                    //NOTE: Hmm, I guess its a matter of taste whether round robin should be advanced only on real MIDI note-on events, isn't it?
1765                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1766                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1767                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1768                  }                  }
1769                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1770                    if (isRealMIDINoteOnEvent)
1771                        pChannel->listeners.PostProcessNoteOn(key, vel);
1772              }              }
1773    
1774              /**              /**
# Line 1235  namespace LinuxSampler { Line 1794  namespace LinuxSampler {
1794               *  sustain pedal will be released or voice turned inactive by itself (e.g.               *  sustain pedal will be released or voice turned inactive by itself (e.g.
1795               *  due to completion of sample playback).               *  due to completion of sample playback).
1796               *               *
1797               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1798               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1799               */               */
1800              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1801                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1802    
                 int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;  
                 if (k < 0 || k > 127) return; //ignore keys outside the key range  
   
                 //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  
                 itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;  
                 int vel = itNoteOffEvent->Param.Note.Velocity;  
   
1803                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1804                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1805                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1806    
1807                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1808    
1809                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1810                    // programmatically spawned notes (Event::type_stop_note). We have
1811                    // to distinguish between them, since certain processing below
1812                    // must only be done on real MIDI note-off events (i.e. for
1813                    // correctly updating which MIDI keys are currently pressed down),
1814                    // plus a stop-note event just releases voices of one particular
1815                    // note, whereas a note-off event releases all voices on a
1816                    // particular MIDI key instead.
1817                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1818    
1819                    if (isRealMIDINoteOffEvent)
1820                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1821    
1822                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1823                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1824                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1825                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1826                      return;                      return;
1827                  }                  }
1828                  #endif                  #endif
1829    
1830                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1831                        pKey->KeyPressed = false; // the MIDI key was now released
1832                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1833                    }
1834    
1835                  // move event to the key's own event list                  // move event to the key's own event list
1836                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1837    
1838                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1839                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1840    
1841                  // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)                      // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1842                  if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P                      if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1843                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1844                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1845                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1846                          // if there's still a key pressed down, respawn a voice (group) on the highest key                              // if there's still a key pressed down, respawn a voice (group) on the highest key
1847                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1848                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1849                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1850                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1851                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1852                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1853                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1854                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1855                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1856                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1857                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1858                                  // create a pseudo note on event                                      }
1859                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1860                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1861                                      // copy event                                      if (itPseudoNoteOnEvent) {
1862                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1863                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1864                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1865                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                          itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1866                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1867                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1868                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1869                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1870                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1871                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1872                                            }
1873                                            // if neither a voice was spawned or postponed then remove note on event from key again
1874                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1875                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1876    
1877                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1878                                  break; // done                                      break; // done
1879                                    }
1880                              }                              }
1881                          }                          }
1882                      }                          if (bOtherKeysPressed) {
1883                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1884                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1885                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1886                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1887                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1888                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1889                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1890                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1891                                        }
1892                                    }
1893                              }                              }
1894                          }                          } else pChannel->PortamentoPos = -1.0f;
1895                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
   
                 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed  
                 if (bShouldRelease) {  
                     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type  
1896    
1897                      // spawn release triggered voice(s) if needed                      // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1898                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1899                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1900                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1901                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1902                        }
1903                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1904                        // This programmatically caused event is caused by a call to
1905                        // the built-in instrument script function note_off(). In
1906                        // contrast to a real MIDI note-off event the stop-note
1907                        // event just intends to release voices of one particular note.
1908                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1909                        if (pNote) { // the requested note is still alive ...
1910                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1911                        } else { // note is dead and gone ..
1912                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1913                            return; // prevent event to be removed a 2nd time below
1914                      }                      }
1915                  }                  }
1916    
# Line 1332  namespace LinuxSampler { Line 1918  namespace LinuxSampler {
1918                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1919                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1920    
1921                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1922                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1923                }
1924    
1925                /**
1926                 * Called on sustain pedal up events to check and if required,
1927                 * launch release trigger voices on the respective active key.
1928                 *
1929                 * @param pEngineChannel - engine channel on which this event occurred on
1930                 * @param itEvent - release trigger event (contains note number)
1931                 */
1932                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1933                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1934    
1935                    const int iKey = itEvent->Param.Note.Key;
1936                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1937    
1938                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1939    
1940                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1941                }
1942    
1943                /**
1944                 * Called on note-off and sustain pedal up events to check and if
1945                 * required, launch release trigger voices on the respective active
1946                 * key.
1947                 *
1948                 * @param pEngineChannel - engine channel on which this event occurred on
1949                 * @param itEvent - note off event / release trigger event
1950                 * @param pKey - key on which the release trigger voices shall be spawned
1951                 */
1952                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1953                    // spawn release triggered voice(s) if needed
1954                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1955                        // assign a new note to this release event
1956                        if (LaunchNewNote(pChannel, itEvent)) {
1957                            // allocate and trigger new release voice(s)
1958                            TriggerReleaseVoices(pChannel, itEvent);
1959                        }
1960                        pKey->ReleaseTrigger = false;
1961                    }
1962                }
1963    
1964                /**
1965                 * Called on "kill note" events, which currently only happens on
1966                 * built-in real-time instrument script function fade_out(). This
1967                 * method only fulfills one task: moving the even to the Note's own
1968                 * event list so that its voices can process the kill event sample
1969                 * accurately.
1970                 */
1971                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1972                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1973    
1974                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1975                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1976    
1977                    // move note kill event to its MIDI key
1978                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1979                    itEvent.moveToEndOf(pKey->pEvents);
1980                }
1981    
1982                /**
1983                 * Called on note synthesis parameter change events. These are
1984                 * internal events caused by calling built-in real-time instrument
1985                 * script functions like change_vol(), change_tune(), etc.
1986                 *
1987                 * This method performs two tasks:
1988                 *
1989                 * - It converts the event's relative values changes (Deltas) to
1990                 *   the respective final new synthesis parameter value (AbsValue),
1991                 *   for that particular moment of the event that is.
1992                 *
1993                 * - It moves the individual events to the Note's own event list
1994                 *   (or actually to the event list of the MIDI key), so that
1995                 *   voices can process those events sample accurately.
1996                 *
1997                 * @param pEngineChannel - engine channel on which this event occurred on
1998                 * @param itEvent - note synthesis parameter change event
1999                 */
2000                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2001                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2002    
2003                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2004                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2005    
2006                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
2007    
2008                    switch (itEvent->Param.NoteSynthParam.Type) {
2009                        case Event::synth_param_volume:
2010                            if (relative)
2011                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2012                            else
2013                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2014                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2015                            break;
2016                        case Event::synth_param_volume_time:
2017                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2018                            break;
2019                        case Event::synth_param_volume_curve:
2020                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2021                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2022                            break;
2023                        case Event::synth_param_pitch:
2024                            if (relative)
2025                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2026                            else
2027                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2028                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2029                            break;
2030                        case Event::synth_param_pitch_time:
2031                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2032                            break;
2033                        case Event::synth_param_pitch_curve:
2034                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2035                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2036                            break;
2037                        case Event::synth_param_pan:
2038                            if (relative) {
2039                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2040                            } else {
2041                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2042                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2043                            }
2044                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2045                            break;
2046                        case Event::synth_param_cutoff:
2047                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2048                            break;
2049                        case Event::synth_param_resonance:
2050                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2051                            break;
2052                        case Event::synth_param_attack:
2053                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2054                            break;
2055                        case Event::synth_param_decay:
2056                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2057                            break;
2058                        case Event::synth_param_release:
2059                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2060                            break;
2061                        case Event::synth_param_amp_lfo_depth:
2062                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2063                            break;
2064                        case Event::synth_param_amp_lfo_freq:
2065                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2066                            break;
2067                        case Event::synth_param_pitch_lfo_depth:
2068                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2069                            break;
2070                        case Event::synth_param_pitch_lfo_freq:
2071                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2072                            break;
2073                    }
2074    
2075                    // move note parameter event to its MIDI key
2076                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2077                    itEvent.moveToEndOf(pKey->pEvents);
2078              }              }
2079    
2080              /**              /**
2081               *  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
2082               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2083               */               */
2084              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2085                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2086    
2087                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1352  namespace LinuxSampler { Line 2094  namespace LinuxSampler {
2094                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2095                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2096                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2097                    itLastStolenNote           = NoteIterator();
2098                    itLastStolenNoteGlobally   = NoteIterator();
2099                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2100                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2101                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2102    
2103                    // reset all notes
2104                    pNotePool->clear();
2105                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2106                         itNote = pNotePool->allocAppend())
2107                    {
2108                        itNote->reset();
2109                    }
2110                    pNotePool->clear();
2111    
2112                  // reset all voices                  // reset all voices
2113                    pVoicePool->clear();
2114                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2115                      iterVoice->Reset();                      iterVoice->Reset();
2116                  }                  }
2117                  pVoicePool->clear();                  pVoicePool->clear();
2118    
2119                    // reset all engine channels
2120                    for (int i = 0; i < engineChannels.size(); i++) {
2121                        AbstractEngineChannel* pEngineChannel =
2122                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2123                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2124                    }
2125    
2126                  // reset disk thread                  // reset disk thread
2127                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2128    
# Line 1379  namespace LinuxSampler { Line 2140  namespace LinuxSampler {
2140               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2141               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2142               */               */
2143              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2144                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2145                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2146                  VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead                  VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
# Line 1390  namespace LinuxSampler { Line 2151  namespace LinuxSampler {
2151               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2152               *  (e.g. to spawn further voices on the same key for layered sounds).               *  (e.g. to spawn further voices on the same key for layered sounds).
2153               *               *
2154               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2155               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2156               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2157               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1414  namespace LinuxSampler { Line 2175  namespace LinuxSampler {
2175                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2176              ) = 0;              ) = 0;
2177    
2178              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2179    
2180              int InitNewVoice (              int InitNewVoice (
2181                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1433  namespace LinuxSampler { Line 2194  namespace LinuxSampler {
2194                      // launch the new voice                      // launch the new voice
2195                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2196                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2197                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2198                      }                      }
2199                      else { // on success                      else { // on success
2200                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1482  namespace LinuxSampler { Line 2243  namespace LinuxSampler {
2243              }              }
2244    
2245          private:          private:
2246                Pool< Note<V> >* pNotePool;
2247                Pool<note_id_t> noteIDPool;
2248              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2249              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2250              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2559  
changed lines
  Added in v.3293

  ViewVC Help
Powered by ViewVC