/[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 2645 by schoenebeck, Wed Jun 18 00:14:57 2014 UTC revision 3360 by schoenebeck, Fri Oct 27 21:19:18 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 178  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202                      PostProcess(engineChannels[i]);                      PostProcess(engineChannels[i]);
203                  }                  }
204    
205                    // Just for debugging: dump the amount of free Note objects to
206                    // the terminal (note due to the static variables being used,
207                    // this is currently just intended for debugging with only one
208                    // engine channel).
209                    #if (CONFIG_DEBUG_LEVEL >= 3)
210                    {
211                        static int slice = 0;
212                        static int noteCount = -1;
213                        if (slice++ % 10 == 0) {
214                            int n = pNotePool->countFreeElements();
215                            if (n != noteCount) {
216                                noteCount = n;
217                                dmsg(1,("[%d] free Note objects count = %d\n", slice / 10, n));
218                            }
219                        }
220                    }
221                    #endif
222    
223                  // empty the engine's event list for the next audio fragment                  // empty the engine's event list for the next audio fragment
224                  ClearEventLists();                  ClearEventLists();
# Line 235  namespace LinuxSampler { Line 276  namespace LinuxSampler {
276                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
277                  }                  }
278    
279                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
280                  try {                  try {
281                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
282                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
283                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
284                  } catch (...) {                  } catch (...) {
285                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
286                  }                  }
287    
288                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
289                         iterVoice; iterVoice = pVoicePool->allocAppend())
290                    {
291                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
292                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
293                  }                  }
294                  pVoicePool->clear();                  pVoicePool->clear();
295    
296                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
297                         itNote = pNotePool->allocAppend())
298                    {
299                        itNote->init(pVoicePool, &noteIDPool);
300                    }
301                    pNotePool->clear();
302    
303                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
304                  ResumeAll();                  ResumeAll();
305              }              }
# Line 315  namespace LinuxSampler { Line 368  namespace LinuxSampler {
368                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
369                      // lower minimum release time                      // lower minimum release time
370                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
371                        pVoicePool->clear();
372                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
373                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
374                      }                      }
# Line 335  namespace LinuxSampler { Line 389  namespace LinuxSampler {
389                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
390                  }                  }
391    
392                    pVoicePool->clear();
393                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
394                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
395                      dmsg(3,("d"));                      dmsg(3,("d"));
396                  }                  }
397                  pVoicePool->clear();                  pVoicePool->clear();
398    
399                  // (re)create event generator                  // update event generator
400                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
401    
402                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
403                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 432  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
487               */               */
488              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
489                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
490                  {                  {
491                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
492                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
493                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
494                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  }                  }
496                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
497              }              }
498    
499              /**              /**
# Line 449  namespace LinuxSampler { Line 503  namespace LinuxSampler {
503               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
504               */               */
505              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
506                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
507                  {                  {
508                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
509                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
510                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
511                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
512                  }                  }
513                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
514              }              }
515    
516              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 559  namespace LinuxSampler { Line 613  namespace LinuxSampler {
613              }              }
614    
615              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
616              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
617                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
618                  return pRegionPool[index];                  return pRegionPool[index];
619              }              }
620    
621              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
622              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
623                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
624                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
625    
626              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
627    
# Line 585  namespace LinuxSampler { Line 641  namespace LinuxSampler {
641                  }                  }
642    
643                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
644                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
645                        VoiceIterator itVoice = itNote->pActiveVoices->first();
646                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
647                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
648    
# Line 608  namespace LinuxSampler { Line 665  namespace LinuxSampler {
665    
666              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)
667              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.
668                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
669              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.
670              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.
671              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
672                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
673              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
674              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.
675              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).
676              int iMaxDiskStreams;              int iMaxDiskStreams;
677    
678                NoteBase* NoteByID(note_id_t id) OVERRIDE {
679                    NoteIterator itNote = GetNotePool()->fromID(id);
680                    if (!itNote) return NULL;
681                    return &*itNote;
682                }
683    
684                /**
685                 * Gets a new @c Note object from the note pool, initializes it
686                 * appropriately, links it with requested parent note (if
687                 * requested), moves it to the appropriate key's list of active
688                 * notes it, and sticks the new note's unique ID to the
689                 * passed @a pNoteOnEvent.
690                 *
691                 * @param pEngineChannel - engine channel on which this event happened
692                 * @param pNoteOnEvent - event which caused this
693                 * @returns new note's unique ID (or zero on error)
694                 */
695                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
696                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
697                    Pool< Note<V> >* pNotePool = GetNotePool();
698    
699                    if (pNotePool->poolIsEmpty()) {
700                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
701                        return 0; // error
702                    }
703    
704                    // create a new note (for new voices to be assigned to)
705                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
706                    NoteIterator itNewNote = pNotePool->allocAppend();
707                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
708    
709                    // remember the engine's time when this note was triggered exactly
710                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
711    
712                    // usually the new note (and its subsequent voices) will be
713                    // allocated on the key provided by the event's note number,
714                    // however if this new note is requested not to be a regular
715                    // note, but rather a child note, then this new note will be
716                    // allocated on the parent note's key instead in order to
717                    // release the child note simultaniously with its parent note
718                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
719    
720                    // in case this new note was requested to be a child note,
721                    // then retrieve its parent note and link them with each other
722                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
723                    if (parentNoteID) {
724                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
725                        if (itParentNote) {
726                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
727                            if (itChildNoteID) {
728                                // link parent and child note with each other
729                                *itChildNoteID = newNoteID;
730                                itNewNote->parentNoteID = parentNoteID;
731                                itNewNote->hostKey = itParentNote->hostKey;
732                            } else {    
733                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
734                                pNotePool->free(itNewNote);
735                                return 0; // error
736                            }
737                        } else {
738                            // the parent note was apparently released already, so
739                            // free the new note again and inform caller that it
740                            // should drop the event
741                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
742                            pNotePool->free(itNewNote);
743                            return 0; // error
744                        }
745                    }
746    
747                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
748    
749                    // copy event which caused this note
750                    itNewNote->cause = *itNoteOnEvent;
751                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
752                    if (!itNewNote->eventID) {
753                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
754                    }
755    
756                    // move new note to its host key
757                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
758                    itNewNote.moveToEndOf(pKey->pActiveNotes);
759                    pChannel->markKeyAsActive(pKey);
760    
761                    // assign unique note ID of this new note to the original note on event
762                    itNoteOnEvent->Param.Note.ID = newNoteID;
763    
764                    return newNoteID; // success
765                }
766    
767              /**              /**
768               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
769               * engine channel.               * engine channel.
# Line 634  namespace LinuxSampler { Line 782  namespace LinuxSampler {
782                  // if a valid real-time instrument script is loaded, pre-process                  // if a valid real-time instrument script is loaded, pre-process
783                  // the event list by running the script now, since the script                  // the event list by running the script now, since the script
784                  // might filter events or add new ones for this cycle                  // might filter events or add new ones for this cycle
785                  if (pChannel->pScript && pChannel->pScript->bHasValidScript) {                  if (pChannel->pScript) {
786                      // resume any suspended script executions still hanging                      const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
787                      // around of previous audio fragment cycles  
788                      for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),                      // resume suspended script executions been scheduled for
789                          end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)                      // this audio fragment cycle (which were suspended in a
790                      {                      // previous audio fragment cycle)
791                          ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)                      ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
                     }  
792    
793                      // spawn new script executions for the new MIDI events of                      // spawn new script executions for the new MIDI events of
794                      // this audio fragment cycle                      // this audio fragment cycle
795                        //
796                        // 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
797                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
798                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
799                      {                      {
800                            //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).
801                            RTList<Event>::Iterator itNext = itEvent;
802                            ++itNext;
803    
804                          switch (itEvent->Type) {                          switch (itEvent->Type) {
805                              case Event::type_note_on:                              case Event::type_note_on:
806                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 666  namespace LinuxSampler { Line 819  namespace LinuxSampler {
819                              case Event::type_note_pressure:                              case Event::type_note_pressure:
820                                  //TODO: ...                                  //TODO: ...
821                                  break;                                  break;
822    
823                                case Event::type_sysex:
824                                    //TODO: ...
825                                    break;
826    
827                                case Event::type_cancel_release_key:
828                                case Event::type_release_key:
829                                case Event::type_release_note:
830                                case Event::type_play_note:
831                                case Event::type_stop_note:
832                                case Event::type_kill_note:
833                                case Event::type_note_synth_param:
834                                    break; // noop
835                          }                          }
836    
837                            // see HACK comment above
838                            itEvent = itNext;
839                      }                      }
840    
841                        // this has to be run again, since the newly spawned scripts
842                        // above may have cause suspended scripts that must be
843                        // resumed within this same audio fragment cycle
844                        //
845                        // FIXME: see FIXME comment above
846                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
847                    }
848    
849                    // if there are any delayed events scheduled for the current
850                    // audio fragment cycle, then move and sort them into the main
851                    // event list
852                    if (!pChannel->delayedEvents.queue.isEmpty()) {
853                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
854                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
855                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
856                        while (true) {
857                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
858                                pEventGenerator->popNextScheduledEvent(
859                                    pChannel->delayedEvents.queue,
860                                    pChannel->delayedEvents.schedulerNodes,
861                                    fragmentEndTime
862                                );
863                            if (!itDelayedEventNode) break;
864                            // get the actual delayed event object and free the used scheduler node
865                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
866                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
867                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
868                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
869                                continue;
870                            }
871                            // skip all events on main event list which have a time
872                            // before (or equal to) the delayed event to be inserted
873                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
874                                 ++itEvent);
875                            // now move delayed event from delayedEvents.pList to
876                            // the current position on the main event list
877                            itEvent = itDelayedEvent.moveBefore(itEvent);
878                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
879                        }
880                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
881                  }                  }
882    
883                  // now process all events regularly                  // now process all events regularly
# Line 680  namespace LinuxSampler { Line 890  namespace LinuxSampler {
890                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
891                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
892                                  break;                                  break;
893                                case Event::type_play_note:
894                                    dmsg(5,("Engine: Play Note received\n"));
895                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
896                                    break;
897                              case Event::type_note_off:                              case Event::type_note_off:
898                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
899                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
900                                  break;                                  break;
901                                case Event::type_stop_note:
902                                    dmsg(5,("Engine: Stop Note received\n"));
903                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
904                                    break;
905                                case Event::type_kill_note:
906                                    dmsg(5,("Engine: Kill Note received\n"));
907                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
908                                    break;
909                              case Event::type_control_change:                              case Event::type_control_change:
910                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
911                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 700  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
923                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
924                                  break;                                  break;
925                                case Event::type_note_synth_param:
926                                    dmsg(5,("Engine: Note Synth Param received\n"));
927                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
928                                    break;
929                                case Event::type_sysex:
930                                    break; // TODO ...
931    
932                                case Event::type_cancel_release_key:
933                                case Event::type_release_key:
934                                case Event::type_release_note:
935                                    break; // noop
936                          }                          }
937                      }                      }
938                  }                  }
# Line 707  namespace LinuxSampler { Line 940  namespace LinuxSampler {
940                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
941                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
942                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
943                    itLastStolenNote          = NoteIterator();
944                    itLastStolenNoteGlobally  = NoteIterator();
945                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
946                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
947                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
948              }              }
949    
950                /**
951                 * Run all suspended script execution instances which are scheduled
952                 * to be resumed for the current audio fragment cycle.
953                 *
954                 * @param pChannel - engine channel on which suspended events occurred
955                 */
956                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
957                    while (true) {
958                        RTList<ScriptEvent>::Iterator itEvent =
959                            pEventGenerator->popNextScheduledScriptEvent(
960                                pChannel->pScript->suspendedEvents,
961                                *pChannel->pScript->pEvents, fragmentEndTime
962                            );
963                        if (!itEvent) break;
964                        ResumeScriptEvent(pChannel, itEvent);
965                    }
966                }
967    
968              /** @brief Call instrument script's event handler for this event.              /** @brief Call instrument script's event handler for this event.
969               *               *
970               * Causes a new execution instance of the currently loaded real-time               * Causes a new execution instance of the currently loaded real-time
971               * instrument script's event handler (callback) to be spawned for               * instrument script's event handler (callback) to be spawned for
972               * the given MIDI event.               * the given MIDI event.
973               *               *
974               * @param pChannel - engine channel on which the MIDI event occured               * @param pChannel - engine channel on which the MIDI event occurred
975               * @param itEvent - MIDI event that causes this new script execution               * @param itEvent - MIDI event that causes this new script execution
976               * @param pEventHandler - script's event handler to be executed               * @param pEventHandler - script's event handler to be executed
977               */               */
# Line 748  namespace LinuxSampler { Line 1001  namespace LinuxSampler {
1001                      // script event object                      // script event object
1002                      RTList<ScriptEvent>::Iterator itScriptEvent =                      RTList<ScriptEvent>::Iterator itScriptEvent =
1003                          pChannel->pScript->pEvents->allocAppend();                          pChannel->pScript->pEvents->allocAppend();
1004                        // if event handler uses polyphonic variables, reset them
1005                        // to zero values before starting to execute the handler
1006                        if (pEventHandler->isPolyphonic())
1007                            itScriptEvent->execCtx->resetPolyphonicData();
1008                      ProcessScriptEvent(                      ProcessScriptEvent(
1009                          pChannel, itEvent, pEventHandler, itScriptEvent                          pChannel, itEvent, pEventHandler, itScriptEvent
1010                      );                      );
1011                  }                  }
1012              }              }
1013    
1014                /** @brief Spawn new execution instance of an instrument script handler.
1015                 *
1016                 * Will be called to initiate a new execution of a real-time
1017                 * instrument script event right from the start of the script's
1018                 * respective handler. If script execution did not complete after
1019                 * calling this method, the respective script exeuction is then
1020                 * suspended and a call to ResumeScriptEvent() will be used next
1021                 * time to continue its execution.
1022                 *
1023                 * @param pChannel - engine channel this script is running for
1024                 * @param itEvent - event which caused execution of this script
1025                 *                  event handler
1026                 * @param pEventHandler - VM representation of event handler to be
1027                 *                        executed
1028                 * @param itScriptEvent - script event that shall be processed
1029                 */
1030              void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {              void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1031                  if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)                  if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1032    
# Line 764  namespace LinuxSampler { Line 1037  namespace LinuxSampler {
1037    
1038                  // initialize/reset other members                  // initialize/reset other members
1039                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1040                  itScriptEvent->id = pEventPool->getID(itEvent);                  itScriptEvent->scheduleTime = itEvent->SchedTime();
1041                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1042                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1043                    itScriptEvent->ignoreAllWaitCalls = false;
1044                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1045                    itScriptEvent->parentHandlerID = 0;
1046                    itScriptEvent->childHandlerID[0] = 0;
1047                    itScriptEvent->autoAbortByParent = false;
1048                    itScriptEvent->forkIndex = 0;
1049                    // this is the native representation of the $EVENT_ID script variable
1050                    itScriptEvent->id =
1051                        (itEvent->Type == Event::type_note_on)
1052                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1053                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1054    
1055                  // run script handler(s)                  // run script handler(s)
1056                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
1057                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
1058                  );                  );
1059    
1060                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
1061                  // ScriptEvent list to be continued on the next audio cycle                  if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1062                  if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...                      // in case the script was suspended, keep it on the allocated
1063                        // ScriptEvent list to be resume at the scheduled time in future,
1064                        // additionally insert it into a sorted time queue
1065                        pEventGenerator->scheduleAheadMicroSec(
1066                            pChannel->pScript->suspendedEvents, // scheduler queue
1067                            *itScriptEvent, // script event
1068                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1069                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1070                        );
1071                    } else { // script execution has finished without 'suspended' status ...
1072                      // if "polyphonic" variable data is passed from script's                      // if "polyphonic" variable data is passed from script's
1073                      // "note" event handler to its "release" event handler, then                      // "note" event handler to its "release" event handler, then
1074                      // the script event must be kept and recycled for the later                      // the script event must be kept and recycled for the later
# Line 800  namespace LinuxSampler { Line 1093  namespace LinuxSampler {
1093              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1094               *               *
1095               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1096               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1097               *               *
1098               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1099               * a script will be suspended if the script called the built-in               * a script will be suspended if the script called the built-in
# Line 822  namespace LinuxSampler { Line 1114  namespace LinuxSampler {
1114                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
1115                  );                  );
1116    
1117                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
1118                  // ScriptEvent list to be continued on the next audio cycle                  if (res & VM_EXEC_SUSPENDED) {
1119                  if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...                      // in case the script was suspended, keep it on the allocated
1120                        // ScriptEvent list to be resume at the scheduled time in future,
1121                        // additionally insert it into a sorted time queue
1122                        pEventGenerator->scheduleAheadMicroSec(
1123                            pChannel->pScript->suspendedEvents, // scheduler queue
1124                            *itScriptEvent, // script event
1125                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1126                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1127                        );
1128                    } else { // script execution has finished without 'suspended' status ...
1129                      // if "polyphonic" variable data is passed from script's                      // if "polyphonic" variable data is passed from script's
1130                      // "note" event handler to its "release" event handler, then                      // "note" event handler to its "release" event handler, then
1131                      // the script event must be kept and recycled for the later                      // the script event must be kept and recycled for the later
# Line 852  namespace LinuxSampler { Line 1153  namespace LinuxSampler {
1153               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1154               *  voice actually died.               *  voice actually died.
1155               *               *
1156               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1157               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1158               *  @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
1159               */               */
1160              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1161                    dmsg(3,("StealVoice()\n"));
1162                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1163                      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"));
1164                      return -1;                      return -1;
# Line 864  namespace LinuxSampler { Line 1166  namespace LinuxSampler {
1166    
1167                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1168    
1169                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1170                        dmsg(1,("Event pool emtpy!\n"));
1171                        return -1;
1172                    }
1173    
1174                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1175                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1176                          return 0;                      return 0;
1177                      }                  }
1178    
1179                      // 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
1180                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1181                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1182                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1183                      int                       iChannelIndex;                  int                          iChannelIndex;
1184                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
   
                     // select engine channel  
                     if (pLastStolenChannel) {  
                         pSelectedChannel = pLastStolenChannel;  
                         iChannelIndex    = pSelectedChannel->iEngineIndexSelf;  
                     } else { // pick the engine channel followed by this engine channel  
                         iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
                     }  
   
                     // if we already stole in this fragment, try to proceed on same key  
                     if (this->itLastStolenVoiceGlobally) {  
                         itSelectedVoice = this->itLastStolenVoiceGlobally;  
                         do {  
                             ++itSelectedVoice;  
                         } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle  
                     }  
1185    
1186                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1187                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = NULL; // to detect endless loop
1188                      #endif // CONFIG_DEVMODE                  #endif
1189    
1190                      // did we find a 'stealable' voice?                  // select engine channel
1191                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                  if (pLastStolenChannel) {
1192                          // remember which voice we stole, so we can simply proceed on next voice stealing                      pSelectedChannel = pLastStolenChannel;
1193                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1194                      } else while (true) { // iterate through engine channels                  } else { // pick the engine channel followed by this engine channel
1195                          // get (next) oldest key                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1196                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1197                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                  }
1198                          while (iuiSelectedKey) {  
1199                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                  // if we already stole in this fragment, try to proceed on same note
1200                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                  if (this->itLastStolenVoiceGlobally) {
1201                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1202                        do {
1203                            ++itSelectedVoice;
1204                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1205                    }
1206                    // did we find a 'stealable' voice?
1207                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1208                        // remember which voice we stole, so we can simply proceed on next voice stealing
1209                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1210                        // done
1211                        goto stealable_voice_found;
1212                    }
1213    
1214                    // get (next) oldest note
1215                    if (this->itLastStolenNoteGlobally) {
1216                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1217                             itNote; ++itNote)
1218                        {
1219                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1220                                // proceed iterating if voice was created in this audio fragment cycle
1221                                if (itSelectedVoice->IsStealable()) {
1222                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1223                                    this->itLastStolenNoteGlobally  = itNote;
1224                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1225                                    goto stealable_voice_found; // selection succeeded
1226                                }
1227                            }
1228                        }
1229                    }
1230    
1231                    #if CONFIG_DEVMODE
1232                    pBegin = pSelectedChannel; // to detect endless loop
1233                    #endif // CONFIG_DEVMODE
1234    
1235                    while (true) { // iterate through engine channels                        
1236                        // get (next) oldest key
1237                        RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1238                        this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1239                        while (iuiSelectedKey) {
1240                            MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1241    
1242                            for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1243                                 itNotesEnd = pSelectedKey->pActiveNotes->end();
1244                                 itNote != itNotesEnd; ++itNote)
1245                            {
1246                                itSelectedVoice = itNote->pActiveVoices->first();
1247                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1248                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1249                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1250                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1251                                  // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing                                  // remember which voice of which note on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1252                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1253                                    this->itLastStolenNoteGlobally  = itNote;
1254                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1255                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1256                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1257                              }                              }
                             ++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);  
1258                          }                          }
1259                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1260                      }                      }
1261                        // get next engine channel
1262                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1263                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1264    
1265                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1266                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1267                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1268                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1269                            dmsg(1,("Exiting.\n"));
1270                            exit(-1);
1271                      }                      }
1272                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1273                    }
1274    
1275                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1276                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1277    
1278                      return 0; // success                  #if CONFIG_DEVMODE
1279                  }                  if (!itSelectedVoice->IsActive()) {
1280                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1281                      return -1;                      return -1;
1282                  }                  }
1283                    #endif // CONFIG_DEVMODE
1284    
1285                    // now kill the selected voice
1286                    itSelectedVoice->Kill(itNoteOnEvent);
1287    
1288                    --VoiceSpawnsLeft;
1289    
1290                    return 0; // success
1291              }              }
1292    
1293              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 978  namespace LinuxSampler { Line 1309  namespace LinuxSampler {
1309                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1310                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1311                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1312                          pEngineChannel->pScript = cmd.pScript;                          pEngineChannel->pScript =
1313                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1314                          instrumentChanged = true;                          instrumentChanged = true;
1315    
1316                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
# Line 986  namespace LinuxSampler { Line 1318  namespace LinuxSampler {
1318                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1319                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1320                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1321                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1322                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1323                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1324    
1325                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1326                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1327                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1328                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1329                                itScriptEvent->id = 0;
1330                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1331                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1332                                itScriptEvent->currentHandler = 0;
1333                              VMExecStatus_t res = pScriptVM->exec(                              itScriptEvent->executionSlices = 0;
1334                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                              itScriptEvent->ignoreAllWaitCalls = false;
1335                              );                              itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1336                                itScriptEvent->parentHandlerID = 0;
1337                                itScriptEvent->childHandlerID[0] = 0;
1338                                itScriptEvent->autoAbortByParent = false;
1339                                itScriptEvent->forkIndex = 0;
1340    
1341                                VMExecStatus_t res;
1342                                size_t instructionsCount = 0;
1343                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1344                                bool bWarningShown = false;
1345                                do {
1346                                    res = pScriptVM->exec(
1347                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1348                                    );
1349                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1350                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1351                                        bWarningShown = true;
1352                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1353                                    }
1354                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1355    
1356                              pEngineChannel->pScript->pEvents->free(itScriptEvent);                              pEngineChannel->pScript->pEvents->free(itScriptEvent);
1357                          }                          }
# Line 1049  namespace LinuxSampler { Line 1405  namespace LinuxSampler {
1405                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1406                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1407                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1408                        
1409                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1410                          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);
1411                      if (itNewVoice) {                      if (itNewVoice) {
1412                            // usually there should already be a new Note object
1413                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1414                            if (!itNote) { // should not happen, but just to be sure ...
1415                                dmsg(2,("Engine: No Note object for stolen voice!\n"));
1416                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1417                                if (!noteID) {
1418                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1419                                    continue;
1420                                }
1421                                itNote = GetNotePool()->fromID(noteID);
1422                            }
1423                            // move voice from whereever it was, to the new note's list of active voices
1424                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1425                            // render audio of this new voice for the first time
1426                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1427                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1428                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1086  namespace LinuxSampler { Line 1457  namespace LinuxSampler {
1457              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1458                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1459                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1460                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1461    
1462                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1463                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1464                    pChannel->ClearEventListsOfCurrentFragment();
1465              }              }
1466    
1467              /**              /**
# Line 1154  namespace LinuxSampler { Line 1526  namespace LinuxSampler {
1526                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1527                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1528                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1529                                      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));
1530                                      if (note < 128)                                      if (note < 128)
1531                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1532                                      break;                                      break;
# Line 1162  namespace LinuxSampler { Line 1534  namespace LinuxSampler {
1534                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1535                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1536                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1537                                      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));
1538                                      if (note < 128)                                      if (note < 128)
1539                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1540                                      break;                                      break;
# Line 1315  namespace LinuxSampler { Line 1687  namespace LinuxSampler {
1687              /**              /**
1688               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1689               *               *
1690               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1691               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1692               */               */
1693              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1694                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1695                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1696    
                 //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;  
   
1697                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1698                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1699                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1700    
1701                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1702    
1703                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1704                    // programmatically spawned notes (Event::type_play_note). We have
1705                    // to distinguish between them, since certain processing below
1706                    // must only be done on real MIDI note-on events (i.e. for
1707                    // correctly updating which MIDI keys are currently pressed down).
1708                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1709    
1710                    if (isRealMIDINoteOnEvent)
1711                        pChannel->listeners.PreProcessNoteOn(key, vel);
1712    
1713                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1714                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1715                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1716                            pChannel->listeners.PostProcessNoteOn(key, vel);
1717                      return;                      return;
1718                  }                  }
1719                  #endif                  #endif
1720    
1721                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1722                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1723                            pChannel->listeners.PostProcessNoteOn(key, vel);
1724                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1725                  }                  }
1726    
# Line 1349  namespace LinuxSampler { Line 1728  namespace LinuxSampler {
1728                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1729    
1730                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1731                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1732                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1733                      if (itYoungestKey) {                      if (itYoungestKey) {
1734                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1357  namespace LinuxSampler { Line 1736  namespace LinuxSampler {
1736                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1737                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1738                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1739                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1740                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1741                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1742                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1743                                    }
1744                              }                              }
1745                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1746                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1747                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1748                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1749                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1750                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1751                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1752                                    }
1753                              }                              }
1754                          }                          }
1755                      }                      }
# Line 1373  namespace LinuxSampler { Line 1757  namespace LinuxSampler {
1757                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1758                  }                  }
1759    
1760                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1761                        pChannel->ProcessKeySwitchChange(key);
1762    
1763                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1764                  pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1765                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1766                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1767                    }
1768    
1769                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1770                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1771                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1772                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1773                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1774                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1775                      }                      }
1776                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1777                  }                  }
# Line 1396  namespace LinuxSampler { Line 1782  namespace LinuxSampler {
1782                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1783                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1784    
1785                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1786                        pChannel->PortamentoPos = (float) key;
1787    
1788                    //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?
1789                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1790                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1791                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1792                  }                  }
1793                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1794                    if (isRealMIDINoteOnEvent)
1795                        pChannel->listeners.PostProcessNoteOn(key, vel);
1796              }              }
1797    
1798              /**              /**
# Line 1427  namespace LinuxSampler { Line 1818  namespace LinuxSampler {
1818               *  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.
1819               *  due to completion of sample playback).               *  due to completion of sample playback).
1820               *               *
1821               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1822               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1823               */               */
1824              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1825                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1826    
                 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;  
   
1827                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1828                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1829                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1830    
1831                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1832    
1833                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1834                    // programmatically spawned notes (Event::type_stop_note). We have
1835                    // to distinguish between them, since certain processing below
1836                    // must only be done on real MIDI note-off events (i.e. for
1837                    // correctly updating which MIDI keys are currently pressed down),
1838                    // plus a stop-note event just releases voices of one particular
1839                    // note, whereas a note-off event releases all voices on a
1840                    // particular MIDI key instead.
1841                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1842    
1843                    if (isRealMIDINoteOffEvent)
1844                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1845    
1846                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1847                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1848                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1849                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1850                      return;                      return;
1851                  }                  }
1852                  #endif                  #endif
1853    
1854                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1855                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1856                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1857                    }
1858    
1859                  // move event to the key's own event list                  // move event to the key's own event list
1860                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1861    
1862                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1863                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1864    
1865                  // 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)
1866                  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
1867                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1868                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1869                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1870                          // 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
1871                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1872                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1873                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1874                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1875                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1876                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1877                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1878                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1879                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1880                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1881                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1882                                  // create a pseudo note on event                                      }
1883                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1884                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1885                                      // copy event                                      if (itPseudoNoteOnEvent) {
1886                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1887                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1888                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1889                                      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)
1890                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1891                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1892                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1893                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1894                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1895                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1896                                            }
1897                                            // if neither a voice was spawned or postponed then remove note on event from key again
1898                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1899                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1900    
1901                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1902                                  break; // done                                      break; // done
1903                                    }
1904                              }                              }
1905                          }                          }
1906                      }                          if (bOtherKeysPressed) {
1907                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1908                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1909                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1910                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1911                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1912                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1913                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1914                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1915                                        }
1916                                    }
1917                              }                              }
1918                          }                          } else pChannel->PortamentoPos = -1.0f;
1919                      } 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  
1920    
1921                      // 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
1922                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1923                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1924                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1925                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1926                        }
1927                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1928                        // This programmatically caused event is caused by a call to
1929                        // the built-in instrument script function note_off(). In
1930                        // contrast to a real MIDI note-off event the stop-note
1931                        // event just intends to release voices of one particular note.
1932                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1933                        if (pNote) { // the requested note is still alive ...
1934                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1935                        } else { // note is dead and gone ..
1936                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1937                            return; // prevent event to be removed a 2nd time below
1938                      }                      }
1939                  }                  }
1940    
# Line 1525  namespace LinuxSampler { Line 1942  namespace LinuxSampler {
1942                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1943                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1944    
1945                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1946                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1947                }
1948    
1949                /**
1950                 * Called on sustain pedal up events to check and if required,
1951                 * launch release trigger voices on the respective active key.
1952                 *
1953                 * @param pEngineChannel - engine channel on which this event occurred on
1954                 * @param itEvent - release trigger event (contains note number)
1955                 */
1956                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1957                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1958    
1959                    const int iKey = itEvent->Param.Note.Key;
1960                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1961    
1962                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1963    
1964                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1965                }
1966    
1967                /**
1968                 * Called on note-off and sustain pedal up events to check and if
1969                 * required, launch release trigger voices on the respective active
1970                 * key.
1971                 *
1972                 * @param pEngineChannel - engine channel on which this event occurred on
1973                 * @param itEvent - note off event / release trigger event
1974                 * @param pKey - key on which the release trigger voices shall be spawned
1975                 */
1976                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1977                    // spawn release triggered voice(s) if needed
1978                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1979                        // assign a new note to this release event
1980                        if (LaunchNewNote(pChannel, itEvent)) {
1981                            // allocate and trigger new release voice(s)
1982                            TriggerReleaseVoices(pChannel, itEvent);
1983                        }
1984                        pKey->ReleaseTrigger = false;
1985                    }
1986                }
1987    
1988                /**
1989                 * Called on "kill note" events, which currently only happens on
1990                 * built-in real-time instrument script function fade_out(). This
1991                 * method only fulfills one task: moving the even to the Note's own
1992                 * event list so that its voices can process the kill event sample
1993                 * accurately.
1994                 */
1995                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1996                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1997    
1998                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1999                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2000    
2001                    // move note kill event to its MIDI key
2002                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2003                    itEvent.moveToEndOf(pKey->pEvents);
2004                }
2005    
2006                /**
2007                 * Called on note synthesis parameter change events. These are
2008                 * internal events caused by calling built-in real-time instrument
2009                 * script functions like change_vol(), change_tune(), etc.
2010                 *
2011                 * This method performs two tasks:
2012                 *
2013                 * - It converts the event's relative values changes (Deltas) to
2014                 *   the respective final new synthesis parameter value (AbsValue),
2015                 *   for that particular moment of the event that is.
2016                 *
2017                 * - It moves the individual events to the Note's own event list
2018                 *   (or actually to the event list of the MIDI key), so that
2019                 *   voices can process those events sample accurately.
2020                 *
2021                 * @param pEngineChannel - engine channel on which this event occurred on
2022                 * @param itEvent - note synthesis parameter change event
2023                 */
2024                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2025                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2026    
2027                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2028                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2029    
2030                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
2031    
2032                    switch (itEvent->Param.NoteSynthParam.Type) {
2033                        case Event::synth_param_volume:
2034                            if (relative)
2035                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2036                            else
2037                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2038                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2039                            break;
2040                        case Event::synth_param_volume_time:
2041                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2042                            break;
2043                        case Event::synth_param_volume_curve:
2044                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2045                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2046                            break;
2047                        case Event::synth_param_pitch:
2048                            if (relative)
2049                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2050                            else
2051                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2052                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2053                            break;
2054                        case Event::synth_param_pitch_time:
2055                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2056                            break;
2057                        case Event::synth_param_pitch_curve:
2058                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2059                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2060                            break;
2061                        case Event::synth_param_pan:
2062                            if (relative) {
2063                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2064                            } else {
2065                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2066                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2067                            }
2068                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2069                            break;
2070                        case Event::synth_param_pan_time:
2071                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2072                            break;
2073                        case Event::synth_param_pan_curve:
2074                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2075                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2076                            break;
2077                        case Event::synth_param_cutoff:
2078                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2079                            break;
2080                        case Event::synth_param_resonance:
2081                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2082                            break;
2083                        case Event::synth_param_attack:
2084                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2085                            break;
2086                        case Event::synth_param_decay:
2087                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2088                            break;
2089                        case Event::synth_param_sustain:
2090                            pNote->Override.Sustain = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2091                            break;
2092                        case Event::synth_param_release:
2093                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2094                            break;
2095    
2096                        case Event::synth_param_cutoff_attack:
2097                            pNote->Override.CutoffAttack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2098                            break;
2099                        case Event::synth_param_cutoff_decay:
2100                            pNote->Override.CutoffDecay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2101                            break;
2102                        case Event::synth_param_cutoff_sustain:
2103                            pNote->Override.CutoffSustain = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2104                            break;
2105                        case Event::synth_param_cutoff_release:
2106                            pNote->Override.CutoffRelease = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2107                            break;
2108    
2109                        case Event::synth_param_amp_lfo_depth:
2110                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2111                            break;
2112                        case Event::synth_param_amp_lfo_freq:
2113                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2114                            break;
2115                        case Event::synth_param_cutoff_lfo_depth:
2116                            pNote->Override.CutoffLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2117                            break;
2118                        case Event::synth_param_cutoff_lfo_freq:
2119                            pNote->Override.CutoffLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2120                            break;
2121                        case Event::synth_param_pitch_lfo_depth:
2122                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2123                            break;
2124                        case Event::synth_param_pitch_lfo_freq:
2125                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2126                            break;
2127                    }
2128    
2129                    // move note parameter event to its MIDI key
2130                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2131                    itEvent.moveToEndOf(pKey->pEvents);
2132              }              }
2133    
2134              /**              /**
2135               *  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
2136               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2137               */               */
2138              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2139                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2140    
2141                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1545  namespace LinuxSampler { Line 2148  namespace LinuxSampler {
2148                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2149                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2150                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2151                    itLastStolenNote           = NoteIterator();
2152                    itLastStolenNoteGlobally   = NoteIterator();
2153                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2154                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2155                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2156    
2157                    // reset all notes
2158                    pNotePool->clear();
2159                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2160                         itNote = pNotePool->allocAppend())
2161                    {
2162                        itNote->reset();
2163                    }
2164                    pNotePool->clear();
2165    
2166                  // reset all voices                  // reset all voices
2167                    pVoicePool->clear();
2168                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2169                      iterVoice->Reset();                      iterVoice->Reset();
2170                  }                  }
2171                  pVoicePool->clear();                  pVoicePool->clear();
2172    
2173                    // reset all engine channels
2174                    for (int i = 0; i < engineChannels.size(); i++) {
2175                        AbstractEngineChannel* pEngineChannel =
2176                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2177                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2178                    }
2179    
2180                  // reset disk thread                  // reset disk thread
2181                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2182    
# Line 1572  namespace LinuxSampler { Line 2194  namespace LinuxSampler {
2194               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2195               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2196               */               */
2197              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2198                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2199                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2200                  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 1583  namespace LinuxSampler { Line 2205  namespace LinuxSampler {
2205               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2206               *  (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).
2207               *               *
2208               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2209               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2210               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2211               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1607  namespace LinuxSampler { Line 2229  namespace LinuxSampler {
2229                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2230              ) = 0;              ) = 0;
2231    
2232              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2233    
2234              int InitNewVoice (              int InitNewVoice (
2235                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1626  namespace LinuxSampler { Line 2248  namespace LinuxSampler {
2248                      // launch the new voice                      // launch the new voice
2249                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2250                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2251                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2252                      }                      }
2253                      else { // on success                      else { // on success
2254                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2255                          if (!pKey->Active) { // mark as active key  
2256                              pKey->Active = true;                          // should actually be superfluous now, since this is
2257                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2258                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2259                          }  
2260                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
2261                          return 0; // success                          return 0; // success
2262                      }                      }
# Line 1675  namespace LinuxSampler { Line 2297  namespace LinuxSampler {
2297              }              }
2298    
2299          private:          private:
2300                Pool< Note<V> >* pNotePool;
2301                Pool<note_id_t> noteIDPool;
2302              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2303              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2304              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2645  
changed lines
  Added in v.3360

  ViewVC Help
Powered by ViewVC