/[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 3073 by schoenebeck, Thu Jan 5 16:04:00 2017 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 32  Line 33 
33  #include "InstrumentManager.h"  #include "InstrumentManager.h"
34  #include "../common/global_private.h"  #include "../common/global_private.h"
35    
36    // a bit headroom over CONFIG_MAX_VOICES to avoid minor complications i.e. under voice stealing conditions
37    #define MAX_NOTES_HEADROOM  3
38    #define GLOBAL_MAX_NOTES    (GLOBAL_MAX_VOICES * MAX_NOTES_HEADROOM)
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
# Line 45  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49          class IM  /* Instrument Manager */,          class IM  /* Instrument Manager */,
50          class I   /* Instrument */          class I   /* Instrument */
51      >      >
52      class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {      class EngineBase: public AbstractEngine, public RegionPools<R>, public NotePool<V> {
53    
54          public:          public:
55                typedef typename RTList< Note<V> >::Iterator NoteIterator;
56              typedef typename RTList<V>::Iterator VoiceIterator;              typedef typename RTList<V>::Iterator VoiceIterator;
57              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 79  namespace LinuxSampler { Line 97  namespace LinuxSampler {
97                      dmsg(1,("OK\n"));                      dmsg(1,("OK\n"));
98                  }                  }
99    
100                    if (pNotePool) {
101                        pNotePool->clear();
102                        delete pNotePool;
103                    }
104    
105                  if (pVoicePool) {                  if (pVoicePool) {
106                      pVoicePool->clear();                      pVoicePool->clear();
107                      delete pVoicePool;                      delete pVoicePool;
# Line 140  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163                                  dmsg(5,("Engine: Sysex received\n"));                                  dmsg(5,("Engine: Sysex received\n"));
164                                  ProcessSysex(itEvent);                                  ProcessSysex(itEvent);
165                                  break;                                  break;
166                                default: ; // noop
167                          }                          }
168                      }                      }
169                  }                  }
# Line 235  namespace LinuxSampler { Line 259  namespace LinuxSampler {
259                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
260                  }                  }
261    
262                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
263                  try {                  try {
264                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
265                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
266                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
267                  } catch (...) {                  } catch (...) {
268                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
269                  }                  }
270    
271                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
272                         iterVoice; iterVoice = pVoicePool->allocAppend())
273                    {
274                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
275                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
276                  }                  }
277                  pVoicePool->clear();                  pVoicePool->clear();
278    
279                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
280                         itNote = pNotePool->allocAppend())
281                    {
282                        itNote->init(pVoicePool, &noteIDPool);
283                    }
284                    pNotePool->clear();
285    
286                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
287                  ResumeAll();                  ResumeAll();
288              }              }
# Line 315  namespace LinuxSampler { Line 351  namespace LinuxSampler {
351                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
352                      // lower minimum release time                      // lower minimum release time
353                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
354                        pVoicePool->clear();
355                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
356                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
357                      }                      }
# Line 335  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
373                  }                  }
374    
375                    pVoicePool->clear();
376                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
377                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
378                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 432  namespace LinuxSampler { Line 470  namespace LinuxSampler {
470               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
471               */               */
472              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
473                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
474                  {                  {
475                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
476                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
477                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
478                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
479                  }                  }
480                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
481              }              }
482    
483              /**              /**
# Line 449  namespace LinuxSampler { Line 487  namespace LinuxSampler {
487               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
488               */               */
489              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
490                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
491                  {                  {
492                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
493                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
494                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
495                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
496                  }                  }
497                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
498              }              }
499    
500              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 559  namespace LinuxSampler { Line 597  namespace LinuxSampler {
597              }              }
598    
599              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
600              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
601                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
602                  return pRegionPool[index];                  return pRegionPool[index];
603              }              }
604    
605              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
606              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
607                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
608                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
609    
610              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
611    
# Line 585  namespace LinuxSampler { Line 625  namespace LinuxSampler {
625                  }                  }
626    
627                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
628                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
629                        VoiceIterator itVoice = itNote->pActiveVoices->first();
630                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
631                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
632    
# Line 608  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649    
650              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)
651              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.
652                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
653              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.
654              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.
655              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
656                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
657              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
658              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.
659              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).
660              int iMaxDiskStreams;              int iMaxDiskStreams;
661    
662                NoteBase* NoteByID(note_id_t id) OVERRIDE {
663                    NoteIterator itNote = GetNotePool()->fromID(id);
664                    if (!itNote) return NULL;
665                    return &*itNote;
666                }
667    
668                /**
669                 * Gets a new @c Note object from the note pool, initializes it
670                 * appropriately, links it with requested parent note (if
671                 * requested), moves it to the appropriate key's list of active
672                 * notes it, and sticks the new note's unique ID to the
673                 * passed @a pNoteOnEvent.
674                 *
675                 * @param pEngineChannel - engine channel on which this event happened
676                 * @param pNoteOnEvent - event which caused this
677                 * @returns new note's unique ID (or zero on error)
678                 */
679                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
680                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
681                    Pool< Note<V> >* pNotePool = GetNotePool();
682    
683                    if (pNotePool->poolIsEmpty()) {
684                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
685                        return 0; // error
686                    }
687    
688                    // create a new note (for new voices to be assigned to)
689                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
690                    NoteIterator itNewNote = pNotePool->allocAppend();
691                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
692    
693                    // remember the engine's time when this note was triggered exactly
694                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
695    
696                    // usually the new note (and its subsequent voices) will be
697                    // allocated on the key provided by the event's note number,
698                    // however if this new note is requested not to be a regular
699                    // note, but rather a child note, then this new note will be
700                    // allocated on the parent note's key instead in order to
701                    // release the child note simultaniously with its parent note
702                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
703    
704                    // in case this new note was requested to be a child note,
705                    // then retrieve its parent note and link them with each other
706                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
707                    if (parentNoteID) {
708                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
709                        if (itParentNote) {
710                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
711                            if (itChildNoteID) {
712                                // link parent and child note with each other
713                                *itChildNoteID = newNoteID;
714                                itNewNote->parentNoteID = parentNoteID;
715                                itNewNote->hostKey = itParentNote->hostKey;
716                            } else {    
717                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
718                                pNotePool->free(itNewNote);
719                                return 0; // error
720                            }
721                        } else {
722                            // the parent note was apparently released already, so
723                            // free the new note again and inform caller that it
724                            // should drop the event
725                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
726                            pNotePool->free(itNewNote);
727                            return 0; // error
728                        }
729                    }
730    
731                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
732    
733                    // copy event which caused this note
734                    itNewNote->cause = *pNoteOnEvent;
735                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
736    
737                    // move new note to its host key
738                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
739                    itNewNote.moveToEndOf(pKey->pActiveNotes);
740    
741                    // assign unique note ID of this new note to the original note on event
742                    pNoteOnEvent->Param.Note.ID = newNoteID;
743    
744                    return newNoteID; // success
745                }
746    
747              /**              /**
748               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
749               * engine channel.               * engine channel.
# Line 634  namespace LinuxSampler { Line 762  namespace LinuxSampler {
762                  // if a valid real-time instrument script is loaded, pre-process                  // if a valid real-time instrument script is loaded, pre-process
763                  // the event list by running the script now, since the script                  // the event list by running the script now, since the script
764                  // might filter events or add new ones for this cycle                  // might filter events or add new ones for this cycle
765                  if (pChannel->pScript && pChannel->pScript->bHasValidScript) {                  if (pChannel->pScript) {
766                      // resume any suspended script executions still hanging                      const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
767                      // around of previous audio fragment cycles  
768                      for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),                      // resume suspended script executions been scheduled for
769                          end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)                      // this audio fragment cycle (which were suspended in a
770                      {                      // previous audio fragment cycle)
771                          ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)                      ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
                     }  
772    
773                      // spawn new script executions for the new MIDI events of                      // spawn new script executions for the new MIDI events of
774                      // this audio fragment cycle                      // this audio fragment cycle
775                        //
776                        // 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
777                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
778                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
779                      {                      {
780                            //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).
781                            RTList<Event>::Iterator itNext = itEvent;
782                            ++itNext;
783    
784                          switch (itEvent->Type) {                          switch (itEvent->Type) {
785                              case Event::type_note_on:                              case Event::type_note_on:
786                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 666  namespace LinuxSampler { Line 799  namespace LinuxSampler {
799                              case Event::type_note_pressure:                              case Event::type_note_pressure:
800                                  //TODO: ...                                  //TODO: ...
801                                  break;                                  break;
802    
803                                case Event::type_sysex:
804                                    //TODO: ...
805                                    break;
806    
807                                case Event::type_cancel_release_key:
808                                case Event::type_release_key:
809                                case Event::type_release_note:
810                                case Event::type_play_note:
811                                case Event::type_stop_note:
812                                case Event::type_note_synth_param:
813                                    break; // noop
814                          }                          }
815    
816                            // see HACK comment above
817                            itEvent = itNext;
818                      }                      }
819    
820                        // this has to be run again, since the newly spawned scripts
821                        // above may have cause suspended scripts that must be
822                        // resumed within this same audio fragment cycle
823                        //
824                        // FIXME: see FIXME comment above
825                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
826                    }
827    
828                    // if there are any delayed events scheduled for the current
829                    // audio fragment cycle, then move and sort them into the main
830                    // event list
831                    if (!pChannel->delayedEvents.queue.isEmpty()) {
832                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
833                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
834                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
835                        while (true) {
836                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
837                                pEventGenerator->popNextScheduledEvent(
838                                    pChannel->delayedEvents.queue,
839                                    pChannel->delayedEvents.schedulerNodes,
840                                    fragmentEndTime
841                                );
842                            if (!itDelayedEventNode) break;
843                            // get the actual delayed event object and free the used scheduler node
844                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
845                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
846                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
847                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
848                                continue;
849                            }
850                            // skip all events on main event list which have a time
851                            // before (or equal to) the delayed event to be inserted
852                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
853                                 ++itEvent);
854                            // now move delayed event from delayedEvents.pList to
855                            // the current position on the main event list
856                            itEvent = itDelayedEvent.moveBefore(itEvent);
857                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
858                        }
859                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
860                  }                  }
861    
862                  // now process all events regularly                  // now process all events regularly
# Line 680  namespace LinuxSampler { Line 869  namespace LinuxSampler {
869                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
870                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
871                                  break;                                  break;
872                                case Event::type_play_note:
873                                    dmsg(5,("Engine: Play Note received\n"));
874                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
875                                    break;
876                              case Event::type_note_off:                              case Event::type_note_off:
877                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
878                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
879                                  break;                                  break;
880                                case Event::type_stop_note:
881                                    dmsg(5,("Engine: Stop Note received\n"));
882                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
883                                    break;
884                              case Event::type_control_change:                              case Event::type_control_change:
885                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
886                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 700  namespace LinuxSampler { Line 897  namespace LinuxSampler {
897                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
898                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
899                                  break;                                  break;
900                                case Event::type_note_synth_param:
901                                    dmsg(5,("Engine: Note Synth Param received\n"));
902                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
903                                    break;
904                                case Event::type_sysex:
905                                    break; // TODO ...
906    
907                                case Event::type_cancel_release_key:
908                                case Event::type_release_key:
909                                case Event::type_release_note:
910                                    break; // noop
911                          }                          }
912                      }                      }
913                  }                  }
# Line 707  namespace LinuxSampler { Line 915  namespace LinuxSampler {
915                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
916                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
917                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
918                    itLastStolenNote          = NoteIterator();
919                    itLastStolenNoteGlobally  = NoteIterator();
920                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
921                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
922                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
923              }              }
924    
925                /**
926                 * Run all suspended script execution instances which are scheduled
927                 * to be resumed for the current audio fragment cycle.
928                 *
929                 * @param pChannel - engine channel on which suspended events occurred
930                 */
931                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
932                    while (true) {
933                        RTList<ScriptEvent>::Iterator itEvent =
934                            pEventGenerator->popNextScheduledScriptEvent(
935                                pChannel->pScript->suspendedEvents,
936                                *pChannel->pScript->pEvents, fragmentEndTime
937                            );
938                        if (!itEvent) break;
939                        ResumeScriptEvent(pChannel, itEvent);
940                    }
941                }
942    
943              /** @brief Call instrument script's event handler for this event.              /** @brief Call instrument script's event handler for this event.
944               *               *
945               * Causes a new execution instance of the currently loaded real-time               * Causes a new execution instance of the currently loaded real-time
946               * instrument script's event handler (callback) to be spawned for               * instrument script's event handler (callback) to be spawned for
947               * the given MIDI event.               * the given MIDI event.
948               *               *
949               * @param pChannel - engine channel on which the MIDI event occured               * @param pChannel - engine channel on which the MIDI event occurred
950               * @param itEvent - MIDI event that causes this new script execution               * @param itEvent - MIDI event that causes this new script execution
951               * @param pEventHandler - script's event handler to be executed               * @param pEventHandler - script's event handler to be executed
952               */               */
953              void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {              void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
954                  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
955                      pChannel->pScript->pEvents->allocAppend();                  // check if polyphonic data is passed from "note" to "release"
956                    // script event handlers
957                    if (pEventHandler == pChannel->pScript->handlerRelease &&
958                        pChannel->pScript->handlerNote &&
959                        pChannel->pScript->handlerNote->isPolyphonic() &&
960                        pChannel->pScript->handlerRelease->isPolyphonic() &&
961                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
962                    {
963                        // polyphonic variable data is used/passed from "note" to
964                        // "release" script callback, so we have to recycle the
965                        // original "note on" script event(s)
966                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
967                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
968                        for (; it != end; ++it) {
969                            ProcessScriptEvent(
970                                pChannel, itEvent, pEventHandler, it
971                            );
972                        }
973                    } else {
974                        // no polyphonic data is used/passed from "note" to
975                        // "release" script callback, so just use a new fresh
976                        // script event object
977                        RTList<ScriptEvent>::Iterator itScriptEvent =
978                            pChannel->pScript->pEvents->allocAppend();
979                        ProcessScriptEvent(
980                            pChannel, itEvent, pEventHandler, itScriptEvent
981                        );
982                    }
983                }
984    
985                  if (!itScriptEvent) return; // no free script event left for execution              /** @brief Spawn new execution instance of an instrument script handler.
986                 *
987                 * Will be called to initiate a new execution of a real-time
988                 * instrument script event right from the start of the script's
989                 * respective handler. If script execution did not complete after
990                 * calling this method, the respective script exeuction is then
991                 * suspended and a call to ResumeScriptEvent() will be used next
992                 * time to continue its execution.
993                 *
994                 * @param pChannel - engine channel this script is running for
995                 * @param itEvent - event which caused execution of this script
996                 *                  event handler
997                 * @param pEventHandler - VM representation of event handler to be
998                 *                        executed
999                 * @param itScriptEvent - script event that shall be processed
1000                 */
1001                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1002                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1003    
1004                  // fill the list of script handlers to be executed by this event                  // fill the list of script handlers to be executed by this event
1005                  int i = 0;                  int i = 0;
# Line 735  namespace LinuxSampler { Line 1008  namespace LinuxSampler {
1008    
1009                  // initialize/reset other members                  // initialize/reset other members
1010                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
                 itScriptEvent->id = pEventPool->getID(itEvent);  
1011                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1012                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1013                    itScriptEvent->ignoreAllWaitCalls = false;
1014                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1015                    // this is the native representation of the $EVENT_ID script variable
1016                    itScriptEvent->id =
1017                        (itEvent->Type == Event::type_note_on)
1018                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1019                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1020    
1021                  // run script handler(s)                  // run script handler(s)
1022                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
1023                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
1024                  );                  );
1025    
1026                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
1027                  // ScriptEvent list to be continued on the next audio cycle,                  if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1028                  // otherwise if execution has been finished, free it for a new                      // in case the script was suspended, keep it on the allocated
1029                  // future script event to be triggered from start                      // ScriptEvent list to be resume at the scheduled time in future,
1030                  if (!(res & VM_EXEC_SUSPENDED))                      // additionally insert it into a sorted time queue
1031                      pChannel->pScript->pEvents->free(itScriptEvent);                      pEventGenerator->scheduleAheadMicroSec(
1032                            pChannel->pScript->suspendedEvents, // scheduler queue
1033                            *itScriptEvent, // script event
1034                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1035                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1036                        );
1037                    } else { // script execution has finished without 'suspended' status ...
1038                        // if "polyphonic" variable data is passed from script's
1039                        // "note" event handler to its "release" event handler, then
1040                        // the script event must be kept and recycled for the later
1041                        // occuring "release" script event ...
1042                        if (pEventHandler == pChannel->pScript->handlerNote &&
1043                            pChannel->pScript->handlerRelease &&
1044                            pChannel->pScript->handlerNote->isPolyphonic() &&
1045                            pChannel->pScript->handlerRelease->isPolyphonic())
1046                        {
1047                            const int key = itEvent->Param.Note.Key;
1048                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1049                        } else {
1050                            // ... otherwise if no polyphonic data is passed and
1051                            // script's execution has finished without suspension
1052                            // status, then free the script event for a new future
1053                            // script event to be triggered from start
1054                            pChannel->pScript->pEvents->free(itScriptEvent);
1055                        }
1056                    }
1057              }              }
1058    
1059              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1060               *               *
1061               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1062               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1063               *               *
1064               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1065               * 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 1073  namespace LinuxSampler {
1073               * @param itScriptEvent - script execution that shall be resumed               * @param itScriptEvent - script execution that shall be resumed
1074               */               */
1075              void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {              void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1076                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1077    
1078                  // run script                  // run script
1079                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
1080                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
1081                  );                  );
1082                  // in case the script was again suspended, keep it on the allocated  
1083                  // ScriptEvent list to be continued on the next audio cycle,                  // was the script suspended?
1084                  // otherwise if execution has been finished, free it for a new                  if (res & VM_EXEC_SUSPENDED) {
1085                  // future script event to be triggered from start                      // in case the script was suspended, keep it on the allocated
1086                  if (!(res & VM_EXEC_SUSPENDED))                      // ScriptEvent list to be resume at the scheduled time in future,
1087                      pChannel->pScript->pEvents->free(itScriptEvent);                      // additionally insert it into a sorted time queue
1088                        pEventGenerator->scheduleAheadMicroSec(
1089                            pChannel->pScript->suspendedEvents, // scheduler queue
1090                            *itScriptEvent, // script event
1091                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1092                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1093                        );
1094                    } else { // script execution has finished without 'suspended' status ...
1095                        // if "polyphonic" variable data is passed from script's
1096                        // "note" event handler to its "release" event handler, then
1097                        // the script event must be kept and recycled for the later
1098                        // occuring "release" script event ...
1099                        if (handler && handler == pChannel->pScript->handlerNote &&
1100                            pChannel->pScript->handlerRelease &&
1101                            pChannel->pScript->handlerNote->isPolyphonic() &&
1102                            pChannel->pScript->handlerRelease->isPolyphonic())
1103                        {
1104                            const int key = itScriptEvent->cause.Param.Note.Key;
1105                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1106                        } else {
1107                            // ... otherwise if no polyphonic data is passed and
1108                            // script's execution has finished without suspension
1109                            // status, then free the script event for a new future
1110                            // script event to be triggered from start
1111                            pChannel->pScript->pEvents->free(itScriptEvent);
1112                        }
1113                    }
1114              }              }
1115    
1116              /**              /**
# Line 788  namespace LinuxSampler { Line 1119  namespace LinuxSampler {
1119               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1120               *  voice actually died.               *  voice actually died.
1121               *               *
1122               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1123               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1124               *  @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
1125               */               */
1126              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1127                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1128                      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"));
1129                      return -1;                      return -1;
# Line 800  namespace LinuxSampler { Line 1131  namespace LinuxSampler {
1131    
1132                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1133    
1134                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1135                        dmsg(1,("Event pool emtpy!\n"));
1136                        return -1;
1137                    }
1138    
1139                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1140                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1141                          return 0;                      return 0;
1142                      }                  }
1143    
1144                      // 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
1145                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1146                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1147                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1148                      int                       iChannelIndex;                  int                          iChannelIndex;
1149                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1150    
1151                      // select engine channel                  // select engine channel
1152                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1153                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1154                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1155                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1156                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1157                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1158                      }                  }
1159    
1160                      // 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
1161                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1162                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1163                          do {                      do {
1164                              ++itSelectedVoice;                          ++itSelectedVoice;
1165                          } 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
1166                    }
1167                    // did we find a 'stealable' voice?
1168                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1169                        // remember which voice we stole, so we can simply proceed on next voice stealing
1170                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1171                        // done
1172                        goto stealable_voice_found;
1173                    }
1174    
1175                    // get (next) oldest note
1176                    if (this->itLastStolenNoteGlobally) {
1177                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1178                             itNote; ++itNote)
1179                        {
1180                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1181                                // proceed iterating if voice was created in this audio fragment cycle
1182                                if (itSelectedVoice->IsStealable()) {
1183                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1184                                    this->itLastStolenNoteGlobally  = itNote;
1185                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1186                                    goto stealable_voice_found; // selection succeeded
1187                                }
1188                            }
1189                      }                      }
1190                    }
1191    
1192                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1193                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1194                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1195    
1196                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1197                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1198                          // 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();
1199                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1200                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1201                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1202                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1203                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1204                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1205                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1206                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1207                                itSelectedVoice = itNote->pActiveVoices->first();
1208                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1209                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1210                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1211                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1212                                  // 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
1213                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1214                                    this->itLastStolenNoteGlobally  = itNote;
1215                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1216                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1217                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1218                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // get next engine channel  
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
1219                          }                          }
1220                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1221                      }                      }
1222                        // get next engine channel
1223                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1224                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1225    
1226                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1227                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1228                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1229                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1230                            dmsg(1,("Exiting.\n"));
1231                            exit(-1);
1232                      }                      }
1233                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1234                    }
1235    
1236                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1237                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1238    
1239                      return 0; // success                  #if CONFIG_DEVMODE
1240                  }                  if (!itSelectedVoice->IsActive()) {
1241                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1242                      return -1;                      return -1;
1243                  }                  }
1244                    #endif // CONFIG_DEVMODE
1245    
1246                    // now kill the selected voice
1247                    itSelectedVoice->Kill(itNoteOnEvent);
1248    
1249                    --VoiceSpawnsLeft;
1250    
1251                    return 0; // success
1252              }              }
1253    
1254              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 914  namespace LinuxSampler { Line 1270  namespace LinuxSampler {
1270                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1271                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1272                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1273                          pEngineChannel->pScript = cmd.pScript;                          pEngineChannel->pScript =
1274                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1275                          instrumentChanged = true;                          instrumentChanged = true;
1276    
1277                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
# Line 922  namespace LinuxSampler { Line 1279  namespace LinuxSampler {
1279                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1280                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1281                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1282                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1283                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1284                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1285    
1286                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1287                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1288                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1289                                itScriptEvent->currentHandler = 0;
1290                                itScriptEvent->executionSlices = 0;
1291                                itScriptEvent->ignoreAllWaitCalls = false;
1292                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1293    
1294                              VMExecStatus_t res = pScriptVM->exec(                              /*VMExecStatus_t res = */ pScriptVM->exec(
1295                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                                  pEngineChannel->pScript->parserContext, &*itScriptEvent
1296                              );                              );
1297    
# Line 985  namespace LinuxSampler { Line 1347  namespace LinuxSampler {
1347                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1348                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1349                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1350                        
1351                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1352                          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);
1353                      if (itNewVoice) {                      if (itNewVoice) {
1354                            // usually there should already be a new Note object
1355                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1356                            if (!itNote) { // should not happen, but just to be sure ...
1357                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1358                                if (!noteID) {
1359                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1360                                    continue;
1361                                }
1362                                itNote = GetNotePool()->fromID(noteID);
1363                            }
1364                            // move voice from whereever it was, to the new note's list of active voices
1365                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1366                            // render audio of this new voice for the first time
1367                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1368                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1369                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1025  namespace LinuxSampler { Line 1401  namespace LinuxSampler {
1401                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1402    
1403                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1404                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1405                    pChannel->ClearEventListsOfCurrentFragment();
1406              }              }
1407    
1408              /**              /**
# Line 1090  namespace LinuxSampler { Line 1467  namespace LinuxSampler {
1467                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1468                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1469                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1470                                      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));
1471                                      if (note < 128)                                      if (note < 128)
1472                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1473                                      break;                                      break;
# Line 1098  namespace LinuxSampler { Line 1475  namespace LinuxSampler {
1475                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1476                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1477                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1478                                      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));
1479                                      if (note < 128)                                      if (note < 128)
1480                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1481                                      break;                                      break;
# Line 1251  namespace LinuxSampler { Line 1628  namespace LinuxSampler {
1628              /**              /**
1629               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1630               *               *
1631               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1632               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1633               */               */
1634              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1635                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1636                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1637    
                 //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;  
   
1638                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1639                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1640                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1641    
1642                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1643    
1644                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1645                    // programmatically spawned notes (Event::type_play_note). We have
1646                    // to distinguish between them, since certain processing below
1647                    // must only be done on real MIDI note-on events (i.e. for
1648                    // correctly updating which MIDI keys are currently pressed down).
1649                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1650    
1651                    if (isRealMIDINoteOnEvent)
1652                        pChannel->listeners.PreProcessNoteOn(key, vel);
1653    
1654                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1655                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1656                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1657                            pChannel->listeners.PostProcessNoteOn(key, vel);
1658                      return;                      return;
1659                  }                  }
1660                  #endif                  #endif
1661    
1662                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1663                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1664                            pChannel->listeners.PostProcessNoteOn(key, vel);
1665                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1666                  }                  }
1667    
# Line 1285  namespace LinuxSampler { Line 1669  namespace LinuxSampler {
1669                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1670    
1671                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1672                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1673                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1674                      if (itYoungestKey) {                      if (itYoungestKey) {
1675                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1293  namespace LinuxSampler { Line 1677  namespace LinuxSampler {
1677                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1678                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1679                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1680                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1681                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1682                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1683                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1684                                    }
1685                              }                              }
1686                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1687                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1688                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1689                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1690                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1691                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1692                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1693                                    }
1694                              }                              }
1695                          }                          }
1696                      }                      }
# Line 1309  namespace LinuxSampler { Line 1698  namespace LinuxSampler {
1698                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1699                  }                  }
1700    
1701                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1702                        pChannel->ProcessKeySwitchChange(key);
1703    
1704                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1705                  pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1706                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1707                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1708                    }
1709    
1710                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1711                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1712                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1713                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1714                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1715                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1716                      }                      }
1717                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1718                  }                  }
# Line 1332  namespace LinuxSampler { Line 1723  namespace LinuxSampler {
1723                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1724                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1725    
1726                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1727                        pChannel->PortamentoPos = (float) key;
1728    
1729                    //NOTE: Hmm, I guess its a matter of taste whether round robin should be advanced only on real MIDI note-on events, isn't it?
1730                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1731                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1732                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1733                  }                  }
1734                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1735                    if (isRealMIDINoteOnEvent)
1736                        pChannel->listeners.PostProcessNoteOn(key, vel);
1737              }              }
1738    
1739              /**              /**
# Line 1363  namespace LinuxSampler { Line 1759  namespace LinuxSampler {
1759               *  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.
1760               *  due to completion of sample playback).               *  due to completion of sample playback).
1761               *               *
1762               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1763               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1764               */               */
1765              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1766                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1767    
                 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;  
   
1768                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1769                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1770                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1771    
1772                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1773    
1774                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1775                    // programmatically spawned notes (Event::type_stop_note). We have
1776                    // to distinguish between them, since certain processing below
1777                    // must only be done on real MIDI note-off events (i.e. for
1778                    // correctly updating which MIDI keys are currently pressed down),
1779                    // plus a stop-note event just releases voices of one particular
1780                    // note, whereas a note-off event releases all voices on a
1781                    // particular MIDI key instead.
1782                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1783    
1784                    if (isRealMIDINoteOffEvent)
1785                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1786    
1787                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1788                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1789                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1790                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1791                      return;                      return;
1792                  }                  }
1793                  #endif                  #endif
1794    
1795                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1796                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1797                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1798                    }
1799    
1800                  // move event to the key's own event list                  // move event to the key's own event list
1801                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1802    
1803                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1804                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1805    
1806                  // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)                      // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1807                  if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P                      if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1808                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1809                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1810                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1811                          // if there's still a key pressed down, respawn a voice (group) on the highest key                              // if there's still a key pressed down, respawn a voice (group) on the highest key
1812                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1813                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1814                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1815                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1816                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1817                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1818                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1819                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1820                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1821                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1822                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1823                                  // create a pseudo note on event                                      }
1824                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1825                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1826                                      // copy event                                      if (itPseudoNoteOnEvent) {
1827                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1828                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1829                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1830                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                          itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1831                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1832                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1833                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1834                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1835                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1836                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1837                                            }
1838                                            // if neither a voice was spawned or postponed then remove note on event from key again
1839                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1840                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1841    
1842                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1843                                  break; // done                                      break; // done
1844                                    }
1845                              }                              }
1846                          }                          }
1847                      }                          if (bOtherKeysPressed) {
1848                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1849                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1850                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1851                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1852                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1853                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1854                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1855                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1856                                        }
1857                                    }
1858                              }                              }
1859                          }                          } else pChannel->PortamentoPos = -1.0f;
1860                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
   
                 // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed  
                 if (bShouldRelease) {  
                     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type  
1861    
1862                      // spawn release triggered voice(s) if needed                      // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1863                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1864                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1865                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1866                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1867                        }
1868                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1869                        // This programmatically caused event is caused by a call to
1870                        // the built-in instrument script function note_off(). In
1871                        // contrast to a real MIDI note-off event the stop-note
1872                        // event just intends to release voices of one particular note.
1873                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1874                        if (pNote) { // the requested note is still alive ...
1875                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1876                        } else { // note is dead and gone ..
1877                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1878                            return; // prevent event to be removed a 2nd time below
1879                      }                      }
1880                  }                  }
1881    
# Line 1461  namespace LinuxSampler { Line 1883  namespace LinuxSampler {
1883                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1884                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1885    
1886                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1887                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1888                }
1889    
1890                /**
1891                 * Called on sustain pedal up events to check and if required,
1892                 * launch release trigger voices on the respective active key.
1893                 *
1894                 * @param pEngineChannel - engine channel on which this event occurred on
1895                 * @param itEvent - release trigger event (contains note number)
1896                 */
1897                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1898                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1899    
1900                    const int iKey = itEvent->Param.Note.Key;
1901                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1902    
1903                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1904    
1905                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1906                }
1907    
1908                /**
1909                 * Called on note-off and sustain pedal up events to check and if
1910                 * required, launch release trigger voices on the respective active
1911                 * key.
1912                 *
1913                 * @param pEngineChannel - engine channel on which this event occurred on
1914                 * @param itEvent - note off event / release trigger event
1915                 * @param pKey - key on which the release trigger voices shall be spawned
1916                 */
1917                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1918                    // spawn release triggered voice(s) if needed
1919                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1920                        // assign a new note to this release event
1921                        if (LaunchNewNote(pChannel, &*itEvent)) {
1922                            // allocate and trigger new release voice(s)
1923                            TriggerReleaseVoices(pChannel, itEvent);
1924                        }
1925                        pKey->ReleaseTrigger = false;
1926                    }
1927                }
1928    
1929                /**
1930                 * Called on note synthesis parameter change events. These are
1931                 * internal events caused by calling built-in real-time instrument
1932                 * script functions like change_vol(), change_pitch(), etc.
1933                 *
1934                 * This method performs two tasks:
1935                 *
1936                 * - It converts the event's relative values changes (Deltas) to
1937                 *   the respective final new synthesis parameter value (AbsValue),
1938                 *   for that particular moment of the event that is.
1939                 *
1940                 * - It moves the individual events to the Note's own event list
1941                 *   (or actually to the event list of the MIDI key), so that
1942                 *   voices can process those events sample accurately.
1943                 *
1944                 * @param pEngineChannel - engine channel on which this event occurred on
1945                 * @param itEvent - note synthesis parameter change event
1946                 */
1947                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1948                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1949    
1950                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1951                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1952    
1953                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1954    
1955                    switch (itEvent->Param.NoteSynthParam.Type) {
1956                        case Event::synth_param_volume:
1957                            if (relative)
1958                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1959                            else
1960                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1961                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1962                            break;
1963                        case Event::synth_param_pitch:
1964                            if (relative)
1965                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1966                            else
1967                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1968                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1969                            break;
1970                        case Event::synth_param_pan:
1971                            if (relative) {
1972                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1973                            } else {
1974                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1975                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1976                            }
1977                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1978                            break;
1979                        case Event::synth_param_cutoff:
1980                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1981                            break;
1982                        case Event::synth_param_resonance:
1983                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1984                            break;
1985                        case Event::synth_param_attack:
1986                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1987                            break;
1988                        case Event::synth_param_decay:
1989                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1990                            break;
1991                        case Event::synth_param_release:
1992                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1993                            break;
1994                    }
1995    
1996                    // move note parameter event to its MIDI key
1997                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1998                    itEvent.moveToEndOf(pKey->pEvents);
1999              }              }
2000    
2001              /**              /**
2002               *  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
2003               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2004               */               */
2005              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2006                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2007    
2008                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1481  namespace LinuxSampler { Line 2015  namespace LinuxSampler {
2015                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2016                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2017                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2018                    itLastStolenNote           = NoteIterator();
2019                    itLastStolenNoteGlobally   = NoteIterator();
2020                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2021                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2022                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2023    
2024                    // reset all notes
2025                    pNotePool->clear();
2026                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2027                         itNote = pNotePool->allocAppend())
2028                    {
2029                        itNote->reset();
2030                    }
2031                    pNotePool->clear();
2032    
2033                  // reset all voices                  // reset all voices
2034                    pVoicePool->clear();
2035                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2036                      iterVoice->Reset();                      iterVoice->Reset();
2037                  }                  }
2038                  pVoicePool->clear();                  pVoicePool->clear();
2039    
2040                    // reset all engine channels
2041                    for (int i = 0; i < engineChannels.size(); i++) {
2042                        AbstractEngineChannel* pEngineChannel =
2043                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2044                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2045                    }
2046    
2047                  // reset disk thread                  // reset disk thread
2048                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2049    
# Line 1508  namespace LinuxSampler { Line 2061  namespace LinuxSampler {
2061               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2062               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2063               */               */
2064              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2065                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2066                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2067                  VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead                  VoiceSpawnsLeft -= count; //FIXME: just a temporary workaround, we should check the cause in StealVoice() instead
# Line 1519  namespace LinuxSampler { Line 2072  namespace LinuxSampler {
2072               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2073               *  (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).
2074               *               *
2075               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2076               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2077               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2078               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1543  namespace LinuxSampler { Line 2096  namespace LinuxSampler {
2096                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2097              ) = 0;              ) = 0;
2098    
2099              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2100    
2101              int InitNewVoice (              int InitNewVoice (
2102                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1562  namespace LinuxSampler { Line 2115  namespace LinuxSampler {
2115                      // launch the new voice                      // launch the new voice
2116                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2117                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2118                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2119                      }                      }
2120                      else { // on success                      else { // on success
2121                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1611  namespace LinuxSampler { Line 2164  namespace LinuxSampler {
2164              }              }
2165    
2166          private:          private:
2167                Pool< Note<V> >* pNotePool;
2168                Pool<note_id_t> noteIDPool;
2169              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2170              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2171              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

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

  ViewVC Help
Powered by ViewVC