/[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 2618 by schoenebeck, Wed Jun 11 11:39:44 2014 UTC revision 2931 by schoenebeck, Sat Jul 9 14:38:33 2016 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-2016 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() : SuspendedRegions(128), noteIDPool(GLOBAL_MAX_NOTES) {
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 235  namespace LinuxSampler { Line 258  namespace LinuxSampler {
258                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
259                  }                  }
260    
261                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
262                  try {                  try {
263                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
264                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
265                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
266                  } catch (...) {                  } catch (...) {
267                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
268                  }                  }
269    
270                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
271                         iterVoice; iterVoice = pVoicePool->allocAppend())
272                    {
273                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
274                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
275                  }                  }
276                  pVoicePool->clear();                  pVoicePool->clear();
277    
278                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
279                         itNote = pNotePool->allocAppend())
280                    {
281                        itNote->init(pVoicePool, &noteIDPool);
282                    }
283                    pNotePool->clear();
284    
285                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
286                  ResumeAll();                  ResumeAll();
287              }              }
# Line 315  namespace LinuxSampler { Line 350  namespace LinuxSampler {
350                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
351                      // lower minimum release time                      // lower minimum release time
352                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
353                        pVoicePool->clear();
354                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
355                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
356                      }                      }
# Line 335  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
372                  }                  }
373    
374                    pVoicePool->clear();
375                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
376                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
377                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 432  namespace LinuxSampler { Line 469  namespace LinuxSampler {
469               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
470               */               */
471              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
472                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
473                  {                  {
474                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
475                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
476                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
477                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
478                  }                  }
479                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
480              }              }
481    
482              /**              /**
# Line 449  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
487               */               */
488              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
489                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
490                  {                  {
491                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
492                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
493                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
494                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  }                  }
496                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
497              }              }
498    
499              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 564  namespace LinuxSampler { Line 601  namespace LinuxSampler {
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 585  namespace LinuxSampler { Line 624  namespace LinuxSampler {
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
# Line 608  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648    
649              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
650              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
653              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
658              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // usually the new note (and its subsequent voices) will be
693                    // allocated on the key provided by the event's note number,
694                    // however if this new note is requested not to be a regular
695                    // note, but rather a child note, then this new note will be
696                    // allocated on the parent note's key instead in order to
697                    // release the child note simultaniously with its parent note
698                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
699    
700                    // in case this new note was requested to be a child note,
701                    // then retrieve its parent note and link them with each other
702                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
703                    if (parentNoteID) {
704                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
705                        if (itParentNote) {
706                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
707                            if (itChildNoteID) {
708                                // link parent and child note with each other
709                                *itChildNoteID = newNoteID;
710                                itNewNote->parentNoteID = parentNoteID;
711                                itNewNote->hostKey = itParentNote->hostKey;
712                            } else {    
713                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
714                                pNotePool->free(itNewNote);
715                                return 0; // error
716                            }
717                        } else {
718                            // the parent note was apparently released already, so
719                            // free the new note again and inform caller that it
720                            // should drop the event
721                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
722                            pNotePool->free(itNewNote);
723                            return 0; // error
724                        }
725                    }
726    
727                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
728    
729                    // copy event which caused this note
730                    itNewNote->cause = *pNoteOnEvent;
731                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
732    
733                    // move new note to its host key
734                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
735                    itNewNote.moveToEndOf(pKey->pActiveNotes);
736    
737                    // assign unique note ID of this new note to the original note on event
738                    pNoteOnEvent->Param.Note.ID = newNoteID;
739    
740                    return newNoteID; // success
741                }
742    
743              /**              /**
744               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
745               * engine channel.               * engine channel.
# Line 634  namespace LinuxSampler { Line 758  namespace LinuxSampler {
758                  // if a valid real-time instrument script is loaded, pre-process                  // if a valid real-time instrument script is loaded, pre-process
759                  // the event list by running the script now, since the script                  // the event list by running the script now, since the script
760                  // might filter events or add new ones for this cycle                  // might filter events or add new ones for this cycle
761                  if (pChannel->pScript && pChannel->pScript->bHasValidScript) {                  if (pChannel->pScript) {
762                      // resume any suspended script executions still hanging                      const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
763                      // around of previous audio fragment cycles  
764                      for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),                      // resume suspended script executions been scheduled for
765                          end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)                      // this audio fragment cycle (which were suspended in a
766                      {                      // previous audio fragment cycle)
767                          ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)                      ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
                     }  
768    
769                      // spawn new script executions for the new MIDI events of                      // spawn new script executions for the new MIDI events of
770                      // this audio fragment cycle                      // this audio fragment cycle
771                        //
772                        // 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
773                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
774                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
775                      {                      {
776                            //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).
777                            RTList<Event>::Iterator itNext = itEvent;
778                            ++itNext;
779    
780                          switch (itEvent->Type) {                          switch (itEvent->Type) {
781                              case Event::type_note_on:                              case Event::type_note_on:
782                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 667  namespace LinuxSampler { Line 796  namespace LinuxSampler {
796                                  //TODO: ...                                  //TODO: ...
797                                  break;                                  break;
798                          }                          }
799    
800                            // see HACK comment above
801                            itEvent = itNext;
802                        }
803    
804                        // this has to be run again, since the newly spawned scripts
805                        // above may have cause suspended scripts that must be
806                        // resumed within this same audio fragment cycle
807                        //
808                        // FIXME: see FIXME comment above
809                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
810                    }
811    
812                    // if there are any delayed events scheduled for the current
813                    // audio fragment cycle, then move and sort them into the main
814                    // event list
815                    if (!pChannel->delayedEvents.queue.isEmpty()) {
816                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
817                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
818                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
819                        while (true) {
820                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
821                                pEventGenerator->popNextScheduledEvent(
822                                    pChannel->delayedEvents.queue,
823                                    pChannel->delayedEvents.schedulerNodes,
824                                    fragmentEndTime
825                                );
826                            if (!itDelayedEventNode) break;
827                            // get the actual delayed event object and free the used scheduler node
828                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
829                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
830                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
831                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
832                                continue;
833                            }
834                            // skip all events on main event list which have a time
835                            // before (or equal to) the delayed event to be inserted
836                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
837                                 ++itEvent);
838                            // now move delayed event from delayedEvents.pList to
839                            // the current position on the main event list
840                            itEvent = itDelayedEvent.moveBefore(itEvent);
841                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
842                      }                      }
843                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
844                  }                  }
845    
846                  // now process all events regularly                  // now process all events regularly
# Line 700  namespace LinuxSampler { Line 873  namespace LinuxSampler {
873                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
874                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
875                                  break;                                  break;
876                                case Event::type_note_synth_param:
877                                    dmsg(5,("Engine: Note Synth Param received\n"));
878                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
879                                    break;
880                          }                          }
881                      }                      }
882                  }                  }
# Line 707  namespace LinuxSampler { Line 884  namespace LinuxSampler {
884                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
885                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
886                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
887                    itLastStolenNote          = NoteIterator();
888                    itLastStolenNoteGlobally  = NoteIterator();
889                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
890                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
891                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
892              }              }
893    
894                /**
895                 * Run all suspended script execution instances which are scheduled
896                 * to be resumed for the current audio fragment cycle.
897                 *
898                 * @param pChannel - engine channel on which suspended events occurred
899                 */
900                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
901                    while (true) {
902                        RTList<ScriptEvent>::Iterator itEvent =
903                            pEventGenerator->popNextScheduledScriptEvent(
904                                pChannel->pScript->suspendedEvents,
905                                *pChannel->pScript->pEvents, fragmentEndTime
906                            );
907                        if (!itEvent) break;
908                        ResumeScriptEvent(pChannel, itEvent);
909                    }
910                }
911    
912              /** @brief Call instrument script's event handler for this event.              /** @brief Call instrument script's event handler for this event.
913               *               *
914               * Causes a new execution instance of the currently loaded real-time               * Causes a new execution instance of the currently loaded real-time
915               * instrument script's event handler (callback) to be spawned for               * instrument script's event handler (callback) to be spawned for
916               * the given MIDI event.               * the given MIDI event.
917               *               *
918               * @param pChannel - engine channel on which the MIDI event occured               * @param pChannel - engine channel on which the MIDI event occurred
919               * @param itEvent - MIDI event that causes this new script execution               * @param itEvent - MIDI event that causes this new script execution
920               * @param pEventHandler - script's event handler to be executed               * @param pEventHandler - script's event handler to be executed
921               */               */
922              void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {              void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
923                  RTList<ScriptEvent>::Iterator itScriptEvent =                  const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
924                      pChannel->pScript->pEvents->allocAppend();                  // check if polyphonic data is passed from "note" to "release"
925                    // script event handlers
926                    if (pEventHandler == pChannel->pScript->handlerRelease &&
927                        pChannel->pScript->handlerNote &&
928                        pChannel->pScript->handlerNote->isPolyphonic() &&
929                        pChannel->pScript->handlerRelease->isPolyphonic() &&
930                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
931                    {
932                        // polyphonic variable data is used/passed from "note" to
933                        // "release" script callback, so we have to recycle the
934                        // original "note on" script event(s)
935                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
936                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
937                        for (; it != end; ++it) {
938                            ProcessScriptEvent(
939                                pChannel, itEvent, pEventHandler, it
940                            );
941                        }
942                    } else {
943                        // no polyphonic data is used/passed from "note" to
944                        // "release" script callback, so just use a new fresh
945                        // script event object
946                        RTList<ScriptEvent>::Iterator itScriptEvent =
947                            pChannel->pScript->pEvents->allocAppend();
948                        ProcessScriptEvent(
949                            pChannel, itEvent, pEventHandler, itScriptEvent
950                        );
951                    }
952                }
953    
954                  if (!itScriptEvent) return; // no free script event left for execution              /** @brief Spawn new execution instance of an instrument script handler.
955                 *
956                 * Will be called to initiate a new execution of a real-time
957                 * instrument script event right from the start of the script's
958                 * respective handler. If script execution did not complete after
959                 * calling this method, the respective script exeuction is then
960                 * suspended and a call to ResumeScriptEvent() will be used next
961                 * time to continue its execution.
962                 *
963                 * @param pChannel - engine channel this script is running for
964                 * @param itEvent - event which caused execution of this script
965                 *                  event handler
966                 * @param pEventHandler - VM representation of event handler to be
967                 *                        executed
968                 * @param itScriptEvent - script event that shall be processed
969                 */
970                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
971                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
972    
973                  // fill the list of script handlers to be executed by this event                  // fill the list of script handlers to be executed by this event
974                  int i = 0;                  int i = 0;
# Line 735  namespace LinuxSampler { Line 977  namespace LinuxSampler {
977    
978                  // initialize/reset other members                  // initialize/reset other members
979                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
                 itScriptEvent->id = pEventPool->getID(itEvent);  
980                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
981                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
982                    // this is the native representation of the $EVENT_ID script variable
983                    itScriptEvent->id =
984                        (itEvent->Type == Event::type_note_on)
985                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
986                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
987    
988                  // run script handler(s)                  // run script handler(s)
989                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
990                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
991                  );                  );
992    
993                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
994                  // ScriptEvent list to be continued on the next audio cycle,                  if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
995                  // otherwise if execution has been finished, free it for a new                      // in case the script was suspended, keep it on the allocated
996                  // future script event to be triggered from start                      // ScriptEvent list to be resume at the scheduled time in future,
997                  if (!(res & VM_EXEC_SUSPENDED))                      // additionally insert it into a sorted time queue
998                      pChannel->pScript->pEvents->free(itScriptEvent);                      pEventGenerator->scheduleAheadMicroSec(
999                            pChannel->pScript->suspendedEvents, // scheduler queue
1000                            *itScriptEvent, // script event
1001                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1002                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1003                        );
1004                    } else { // script execution has finished without 'suspended' status ...
1005                        // if "polyphonic" variable data is passed from script's
1006                        // "note" event handler to its "release" event handler, then
1007                        // the script event must be kept and recycled for the later
1008                        // occuring "release" script event ...
1009                        if (pEventHandler == pChannel->pScript->handlerNote &&
1010                            pChannel->pScript->handlerRelease &&
1011                            pChannel->pScript->handlerNote->isPolyphonic() &&
1012                            pChannel->pScript->handlerRelease->isPolyphonic())
1013                        {
1014                            const int key = itEvent->Param.Note.Key;
1015                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1016                        } else {
1017                            // ... otherwise if no polyphonic data is passed and
1018                            // script's execution has finished without suspension
1019                            // status, then free the script event for a new future
1020                            // script event to be triggered from start
1021                            pChannel->pScript->pEvents->free(itScriptEvent);
1022                        }
1023                    }
1024              }              }
1025    
1026              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1027               *               *
1028               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1029               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1030               *               *
1031               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1032               * 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 770  namespace LinuxSampler { Line 1040  namespace LinuxSampler {
1040               * @param itScriptEvent - script execution that shall be resumed               * @param itScriptEvent - script execution that shall be resumed
1041               */               */
1042              void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {              void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1043                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1044    
1045                  // run script                  // run script
1046                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
1047                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
1048                  );                  );
1049                  // in case the script was again suspended, keep it on the allocated  
1050                  // ScriptEvent list to be continued on the next audio cycle,                  // was the script suspended?
1051                  // otherwise if execution has been finished, free it for a new                  if (res & VM_EXEC_SUSPENDED) {
1052                  // future script event to be triggered from start                      // in case the script was suspended, keep it on the allocated
1053                  if (!(res & VM_EXEC_SUSPENDED))                      // ScriptEvent list to be resume at the scheduled time in future,
1054                      pChannel->pScript->pEvents->free(itScriptEvent);                      // additionally insert it into a sorted time queue
1055                        pEventGenerator->scheduleAheadMicroSec(
1056                            pChannel->pScript->suspendedEvents, // scheduler queue
1057                            *itScriptEvent, // script event
1058                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1059                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1060                        );
1061                    } else { // script execution has finished without 'suspended' status ...
1062                        // if "polyphonic" variable data is passed from script's
1063                        // "note" event handler to its "release" event handler, then
1064                        // the script event must be kept and recycled for the later
1065                        // occuring "release" script event ...
1066                        if (handler && handler == pChannel->pScript->handlerNote &&
1067                            pChannel->pScript->handlerRelease &&
1068                            pChannel->pScript->handlerNote->isPolyphonic() &&
1069                            pChannel->pScript->handlerRelease->isPolyphonic())
1070                        {
1071                            const int key = itScriptEvent->cause.Param.Note.Key;
1072                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1073                        } else {
1074                            // ... otherwise if no polyphonic data is passed and
1075                            // script's execution has finished without suspension
1076                            // status, then free the script event for a new future
1077                            // script event to be triggered from start
1078                            pChannel->pScript->pEvents->free(itScriptEvent);
1079                        }
1080                    }
1081              }              }
1082    
1083              /**              /**
# Line 788  namespace LinuxSampler { Line 1086  namespace LinuxSampler {
1086               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1087               *  voice actually died.               *  voice actually died.
1088               *               *
1089               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1090               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1091               *  @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
1092               */               */
1093              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1094                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1095                      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"));
1096                      return -1;                      return -1;
# Line 800  namespace LinuxSampler { Line 1098  namespace LinuxSampler {
1098    
1099                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1100    
1101                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1102                        dmsg(1,("Event pool emtpy!\n"));
1103                        return -1;
1104                    }
1105    
1106                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1107                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1108                          return 0;                      return 0;
1109                      }                  }
1110    
1111                      // 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
1112                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1113                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1114                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1115                      int                       iChannelIndex;                  int                          iChannelIndex;
1116                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1117    
1118                      // select engine channel                  // select engine channel
1119                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1120                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1121                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1122                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1123                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1124                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1125                      }                  }
1126    
1127                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1128                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1129                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1130                          do {                      do {
1131                              ++itSelectedVoice;                          ++itSelectedVoice;
1132                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1133                    }
1134                    // did we find a 'stealable' voice?
1135                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1136                        // remember which voice we stole, so we can simply proceed on next voice stealing
1137                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1138                        // done
1139                        goto stealable_voice_found;
1140                    }
1141    
1142                    // get (next) oldest note
1143                    if (this->itLastStolenNoteGlobally) {
1144                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1145                             itNote; ++itNote)
1146                        {
1147                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1148                                // proceed iterating if voice was created in this audio fragment cycle
1149                                if (itSelectedVoice->IsStealable()) {
1150                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1151                                    this->itLastStolenNoteGlobally  = itNote;
1152                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1153                                    goto stealable_voice_found; // selection succeeded
1154                                }
1155                            }
1156                      }                      }
1157                    }
1158    
1159                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1160                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1161                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1162    
1163                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1164                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1165                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1166                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1167                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1168                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1169                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1170                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1171                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1172                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1173                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1174                                itSelectedVoice = itNote->pActiveVoices->first();
1175                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1176                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1177                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1178                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1179                                  // 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
1180                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1181                                    this->itLastStolenNoteGlobally  = itNote;
1182                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1183                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1184                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1185                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1186                          }                          }
1187                          // get next engine channel                          ++iuiSelectedKey; // get next key on current 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);  
                         }  
                         #endif // CONFIG_DEVMODE  
1188                      }                      }
1189                        // get next engine channel
1190                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1191                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1192    
1193                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1194                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1195                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1196                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1197                            dmsg(1,("Exiting.\n"));
1198                            exit(-1);
1199                      }                      }
1200                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1201                    }
1202    
1203                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1204                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1205    
1206                      return 0; // success                  #if CONFIG_DEVMODE
1207                  }                  if (!itSelectedVoice->IsActive()) {
1208                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1209                      return -1;                      return -1;
1210                  }                  }
1211                    #endif // CONFIG_DEVMODE
1212    
1213                    // now kill the selected voice
1214                    itSelectedVoice->Kill(itNoteOnEvent);
1215    
1216                    --VoiceSpawnsLeft;
1217    
1218                    return 0; // success
1219              }              }
1220    
1221              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 914  namespace LinuxSampler { Line 1237  namespace LinuxSampler {
1237                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1238                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1239                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1240                          pEngineChannel->pScript = cmd.pScript;                          pEngineChannel->pScript =
1241                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1242                          instrumentChanged = true;                          instrumentChanged = true;
1243    
1244                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
# Line 985  namespace LinuxSampler { Line 1309  namespace LinuxSampler {
1309                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1310                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1311                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1312                        
1313                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1314                          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);
1315                      if (itNewVoice) {                      if (itNewVoice) {
1316                            // usually there should already be a new Note object
1317                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1318                            if (!itNote) { // should not happen, but just to be sure ...
1319                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1320                                if (!noteID) {
1321                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1322                                    continue;
1323                                }
1324                                itNote = GetNotePool()->fromID(noteID);
1325                            }
1326                            // move voice from whereever it was, to the new note's list of active voices
1327                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1328                            // render audio of this new voice for the first time
1329                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1330                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1331                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1025  namespace LinuxSampler { Line 1363  namespace LinuxSampler {
1363                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1364    
1365                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1366                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1367                    pChannel->ClearEventListsOfCurrentFragment();
1368              }              }
1369    
1370              /**              /**
# Line 1090  namespace LinuxSampler { Line 1429  namespace LinuxSampler {
1429                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1430                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1431                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1432                                      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));
1433                                      if (note < 128)                                      if (note < 128)
1434                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1435                                      break;                                      break;
# Line 1098  namespace LinuxSampler { Line 1437  namespace LinuxSampler {
1437                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1438                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1439                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1440                                      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));
1441                                      if (note < 128)                                      if (note < 128)
1442                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1443                                      break;                                      break;
# Line 1251  namespace LinuxSampler { Line 1590  namespace LinuxSampler {
1590              /**              /**
1591               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1592               *               *
1593               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1594               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1595               */               */
1596              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1597                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1598                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1599    
                 //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;  
   
1600                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1601                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1602                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1603    
1604                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1605    
1606                  pChannel->listeners.PreProcessNoteOn(key, vel);                  pChannel->listeners.PreProcessNoteOn(key, vel);
# Line 1293  namespace LinuxSampler { Line 1628  namespace LinuxSampler {
1628                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1629                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1630                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1631                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1632                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1633                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1634                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1635                                    }
1636                              }                              }
1637                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1638                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1639                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1640                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1641                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1642                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1643                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1644                                    }
1645                              }                              }
1646                          }                          }
1647                      }                      }
# Line 1363  namespace LinuxSampler { Line 1703  namespace LinuxSampler {
1703               *  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.
1704               *  due to completion of sample playback).               *  due to completion of sample playback).
1705               *               *
1706               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1707               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1708               */               */
1709              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1710                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1711    
                 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;  
   
1712                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1713                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1714                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1715    
1716                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1717    
1718                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  pChannel->listeners.PreProcessNoteOff(iKey, vel);
# Line 1410  namespace LinuxSampler { Line 1746  namespace LinuxSampler {
1746                                  pChannel->SoloKey = i;                                  pChannel->SoloKey = i;
1747                                  // get final portamento position of currently active voice                                  // get final portamento position of currently active voice
1748                                  if (pChannel->PortamentoMode) {                                  if (pChannel->PortamentoMode) {
1749                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                      NoteIterator itNote = pKey->pActiveNotes->first();
1750                                        VoiceIterator itVoice = itNote->pActiveVoices->first();
1751                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1752                                  }                                  }
1753                                  // create a pseudo note on event                                  // create a pseudo note on event
# Line 1422  namespace LinuxSampler { Line 1759  namespace LinuxSampler {
1759                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;
1760                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                      itPseudoNoteOnEvent->Param.Note.Key      = i;
1761                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1762                                      // allocate and trigger new voice(s) for the other key                                      // assign a new note to this note-on event
1763                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                      if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1764                                            // allocate and trigger new voice(s) for the other key
1765                                            TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1766                                        }
1767                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // if neither a voice was spawned or postponed then remove note on event from key again
1768                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1769                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);
# Line 1436  namespace LinuxSampler { Line 1776  namespace LinuxSampler {
1776                      if (bOtherKeysPressed) {                      if (bOtherKeysPressed) {
1777                          if (pKey->Active) { // kill all voices on this key                          if (pKey->Active) { // kill all voices on this key
1778                              bShouldRelease = false; // no need to release, as we kill it here                              bShouldRelease = false; // no need to release, as we kill it here
1779                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1780                              VoiceIterator end               = pKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1781                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1782                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1783                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1784                                            itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1785                                    }
1786                              }                              }
1787                          }                          }
1788                      } else pChannel->PortamentoPos = -1.0f;                      } else pChannel->PortamentoPos = -1.0f;
# Line 1449  namespace LinuxSampler { Line 1791  namespace LinuxSampler {
1791                  // 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 no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1792                  if (bShouldRelease) {                  if (bShouldRelease) {
1793                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
   
1794                      // spawn release triggered voice(s) if needed                      // spawn release triggered voice(s) if needed
1795                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
                         TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);  
                         pKey->ReleaseTrigger = false;  
                     }  
1796                  }                  }
1797    
1798                  // if neither a voice was spawned or postponed on this key then remove note off event from key again                  // if neither a voice was spawned or postponed on this key then remove note off event from key again
# Line 1465  namespace LinuxSampler { Line 1803  namespace LinuxSampler {
1803              }              }
1804    
1805              /**              /**
1806                 * Called on sustain pedal up events to check and if required,
1807                 * launch release trigger voices on the respective active key.
1808                 *
1809                 * @param pEngineChannel - engine channel on which this event occurred on
1810                 * @param itEvent - release trigger event (contains note number)
1811                 */
1812                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1813                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1814    
1815                    const int iKey = itEvent->Param.Note.Key;
1816                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1817    
1818                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1819    
1820                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1821                }
1822    
1823                /**
1824                 * Called on note-off and sustain pedal up events to check and if
1825                 * required, launch release trigger voices on the respective active
1826                 * key.
1827                 *
1828                 * @param pEngineChannel - engine channel on which this event occurred on
1829                 * @param itEvent - note off event / release trigger event
1830                 * @param pKey - key on which the release trigger voices shall be spawned
1831                 */
1832                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1833                    // spawn release triggered voice(s) if needed
1834                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1835                        // assign a new note to this release event
1836                        if (LaunchNewNote(pChannel, &*itEvent)) {
1837                            // allocate and trigger new release voice(s)
1838                            TriggerReleaseVoices(pChannel, itEvent);
1839                        }
1840                        pKey->ReleaseTrigger = false;
1841                    }
1842                }
1843    
1844                /**
1845                 * Called on note synthesis parameter change events. These are
1846                 * internal events caused by calling built-in real-time instrument
1847                 * script functions like change_vol(), change_pitch(), etc.
1848                 *
1849                 * This method performs two tasks:
1850                 *
1851                 * - It converts the event's relative values changes (Deltas) to
1852                 *   the respective final new synthesis parameter value (AbsValue),
1853                 *   for that particular moment of the event that is.
1854                 *
1855                 * - It moves the individual events to the Note's own event list
1856                 *   (or actually to the event list of the MIDI key), so that
1857                 *   voices can process those events sample accurately.
1858                 *
1859                 * @param pEngineChannel - engine channel on which this event occurred on
1860                 * @param itEvent - note synthesis parameter change event
1861                 */
1862                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1863                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1864    
1865                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1866                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1867    
1868                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1869    
1870                    switch (itEvent->Param.NoteSynthParam.Type) {
1871                        case Event::synth_param_volume:
1872                            if (relative)
1873                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1874                            else
1875                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1876                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1877                            break;
1878                        case Event::synth_param_pitch:
1879                            if (relative)
1880                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1881                            else
1882                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1883                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1884                            break;
1885                        case Event::synth_param_pan:
1886                            if (relative) {
1887                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1888                            } else {
1889                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1890                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1891                            }
1892                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1893                            break;
1894                    }
1895    
1896                    // move note parameter event to its MIDI key
1897                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1898                    itEvent.moveToEndOf(pKey->pEvents);
1899                }
1900    
1901                /**
1902               *  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
1903               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
1904               */               */
# Line 1481  namespace LinuxSampler { Line 1915  namespace LinuxSampler {
1915                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1916                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1917                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1918                    itLastStolenNote           = NoteIterator();
1919                    itLastStolenNoteGlobally   = NoteIterator();
1920                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
1921                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
1922                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
1923    
1924                    // reset all notes
1925                    pNotePool->clear();
1926                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
1927                         itNote = pNotePool->allocAppend())
1928                    {
1929                        itNote->reset();
1930                    }
1931                    pNotePool->clear();
1932    
1933                  // reset all voices                  // reset all voices
1934                    pVoicePool->clear();
1935                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1936                      iterVoice->Reset();                      iterVoice->Reset();
1937                  }                  }
1938                  pVoicePool->clear();                  pVoicePool->clear();
1939    
1940                    // reset all engine channels
1941                    for (int i = 0; i < engineChannels.size(); i++) {
1942                        AbstractEngineChannel* pEngineChannel =
1943                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
1944                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
1945                    }
1946    
1947                  // reset disk thread                  // reset disk thread
1948                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
1949    
# Line 1519  namespace LinuxSampler { Line 1972  namespace LinuxSampler {
1972               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
1973               *  (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).
1974               *               *
1975               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
1976               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
1977               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
1978               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1562  namespace LinuxSampler { Line 2015  namespace LinuxSampler {
2015                      // launch the new voice                      // launch the new voice
2016                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2017                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2018                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2019                      }                      }
2020                      else { // on success                      else { // on success
2021                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1611  namespace LinuxSampler { Line 2064  namespace LinuxSampler {
2064              }              }
2065    
2066          private:          private:
2067                Pool< Note<V> >* pNotePool;
2068                Pool<note_id_t> noteIDPool;
2069              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2070              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2071              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2618  
changed lines
  Added in v.2931

  ViewVC Help
Powered by ViewVC