/[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 2410 by schoenebeck, Sat Feb 2 18:52:15 2013 UTC revision 3207 by schoenebeck, Thu May 25 10:53:45 2017 UTC
# Line 5  Line 5 
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-2012 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 104  namespace LinuxSampler { Line 127  namespace LinuxSampler {
127               *  @param Samples - number of sample points to be rendered               *  @param Samples - number of sample points to be rendered
128               *  @returns       0 on success               *  @returns       0 on success
129               */               */
130              virtual int RenderAudio(uint Samples) {              virtual int RenderAudio(uint Samples) OVERRIDE {
131                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
132    
133                  // return if engine disabled                  // return if engine disabled
# 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                  }                  }
170                    
171                    // In case scale tuning has been changed, recalculate pitch for
172                    // all active voices.
173                    ProcessScaleTuningChange();
174    
175                  // reset internal voice counter (just for statistic of active voices)                  // reset internal voice counter (just for statistic of active voices)
176                  ActiveVoiceCountTemp = 0;                  ActiveVoiceCountTemp = 0;
# Line 205  namespace LinuxSampler { Line 233  namespace LinuxSampler {
233                  return 0;                  return 0;
234              }              }
235    
236              virtual int MaxVoices() { return pVoicePool->poolSize(); }              virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
237    
238              virtual void SetMaxVoices(int iVoices) throw (Exception) {              virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
239                  if (iVoices < 1)                  if (iVoices < 1)
240                      throw Exception("Maximum voices for an engine cannot be set lower than 1");                      throw Exception("Maximum voices for an engine cannot be set lower than 1");
241    
# Line 231  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 250  namespace LinuxSampler { Line 290  namespace LinuxSampler {
290              /** Called after the new max number of voices is set and before resuming the engine. */              /** Called after the new max number of voices is set and before resuming the engine. */
291              virtual void PostSetMaxVoices(int iVoices) { }              virtual void PostSetMaxVoices(int iVoices) { }
292    
293              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
294              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
295              virtual int  MaxDiskStreams() { return iMaxDiskStreams; }              virtual int  MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
296    
297              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
298                  if (iStreams < 0)                  if (iStreams < 0)
299                      throw Exception("Maximum disk streams for an engine cannot be set lower than 0");                      throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
300    
# Line 269  namespace LinuxSampler { Line 309  namespace LinuxSampler {
309                  ResumeAll();                  ResumeAll();
310              }              }
311    
312              virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }              virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
313              virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }              virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
314              virtual InstrumentManager* GetInstrumentManager() { return &instruments; }              virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
315    
316              /**              /**
317               * Connect this engine instance with the given audio output device.               * Connect this engine instance with the given audio output device.
# Line 282  namespace LinuxSampler { Line 322  namespace LinuxSampler {
322               *               *
323               * @param pAudioOut - audio output device to connect to               * @param pAudioOut - audio output device to connect to
324               */               */
325              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
326                  // caution: don't ignore if connecting to the same device here,                  // caution: don't ignore if connecting to the same device here,
327                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!
328    
# Line 311  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 331  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 370  namespace LinuxSampler { Line 412  namespace LinuxSampler {
412              }              }
413                    
414              // Implementattion for abstract method derived from Engine.              // Implementattion for abstract method derived from Engine.
415              virtual void ReconnectAudioOutputDevice() {              virtual void ReconnectAudioOutputDevice() OVERRIDE {
416                  SuspendAll();                  SuspendAll();
417                  if (pAudioOutputDevice) Connect(pAudioOutputDevice);                  if (pAudioOutputDevice) Connect(pAudioOutputDevice);
418                  ResumeAll();                  ResumeAll();
# Line 428  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                  SuspendedRegionsMutex.Lock();                  {
475                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
476                  pPendingRegionSuspension = pRegion;                      SuspensionChangeOngoing.Set(true);
477                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionSuspension = pRegion;
478                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
479                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  }
480                    dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
481              }              }
482    
483              /**              /**
# Line 444  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                  SuspendedRegionsMutex.Lock();                  {
492                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
493                  pPendingRegionResumption = pRegion;                      SuspensionChangeOngoing.Set(true);
494                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionResumption = pRegion;
495                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
496                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  }
497                    dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
498              }              }
499    
500              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 553  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 572  namespace LinuxSampler { Line 618  namespace LinuxSampler {
618              public:              public:
619                  int PendingStreamDeletions;                  int PendingStreamDeletions;
620                  RR* pPendingRegionSuspension;                  RR* pPendingRegionSuspension;
621    
622                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
623                      PendingStreamDeletions = 0;                      PendingStreamDeletions = 0;
624                      this->pPendingRegionSuspension = pPendingRegionSuspension;                      this->pPendingRegionSuspension = pPendingRegionSuspension;
625                  }                  }
626    
627                  virtual bool Process(MidiKey* pMidiKey) {                  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    
633                      return true;                      return true;
634                  }                  }
635    
636                  virtual void Process(VoiceIterator& itVoice) {                  virtual void Process(VoiceIterator& itVoice) OVERRIDE {
637                      // request a notification from disk thread side for stream deletion                      // request a notification from disk thread side for stream deletion
638                      const Stream::Handle hStream = itVoice->KillImmediately(true);                      const Stream::Handle hStream = itVoice->KillImmediately(true);
639                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
# Line 601  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, Pool<Event>::Iterator& itNoteOnEvent) 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 = itNoteOnEvent->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 = itNoteOnEvent->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 = itNoteOnEvent->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 = *itNoteOnEvent;
735                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
736                    if (!itNewNote->eventID) {
737                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
738                    }
739    
740                    // move new note to its host key
741                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
742                    itNewNote.moveToEndOf(pKey->pActiveNotes);
743    
744                    // assign unique note ID of this new note to the original note on event
745                    itNoteOnEvent->Param.Note.ID = newNoteID;
746    
747                    return newNoteID; // success
748                }
749    
750              /**              /**
751               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
752               * engine channel.               * engine channel.
# Line 624  namespace LinuxSampler { Line 762  namespace LinuxSampler {
762                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
763                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
764    
765                  // process events                  // if a valid real-time instrument script is loaded, pre-process
766                    // the event list by running the script now, since the script
767                    // might filter events or add new ones for this cycle
768                    if (pChannel->pScript) {
769                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
770    
771                        // resume suspended script executions been scheduled for
772                        // this audio fragment cycle (which were suspended in a
773                        // previous audio fragment cycle)
774                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
775    
776                        // spawn new script executions for the new MIDI events of
777                        // this audio fragment cycle
778                        //
779                        // 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
780                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
781                            end = pChannel->pEvents->end(); itEvent != end; )
782                        {
783                            //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).
784                            RTList<Event>::Iterator itNext = itEvent;
785                            ++itNext;
786    
787                            switch (itEvent->Type) {
788                                case Event::type_note_on:
789                                    if (pChannel->pScript->handlerNote)
790                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
791                                    break;
792                                case Event::type_note_off:
793                                    if (pChannel->pScript->handlerRelease)
794                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
795                                    break;
796                                case Event::type_control_change:
797                                case Event::type_channel_pressure:
798                                case Event::type_pitchbend:
799                                    if (pChannel->pScript->handlerController)
800                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
801                                    break;
802                                case Event::type_note_pressure:
803                                    //TODO: ...
804                                    break;
805    
806                                case Event::type_sysex:
807                                    //TODO: ...
808                                    break;
809    
810                                case Event::type_cancel_release_key:
811                                case Event::type_release_key:
812                                case Event::type_release_note:
813                                case Event::type_play_note:
814                                case Event::type_stop_note:
815                                case Event::type_kill_note:
816                                case Event::type_note_synth_param:
817                                    break; // noop
818                            }
819    
820                            // see HACK comment above
821                            itEvent = itNext;
822                        }
823    
824                        // this has to be run again, since the newly spawned scripts
825                        // above may have cause suspended scripts that must be
826                        // resumed within this same audio fragment cycle
827                        //
828                        // FIXME: see FIXME comment above
829                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
830                    }
831    
832                    // if there are any delayed events scheduled for the current
833                    // audio fragment cycle, then move and sort them into the main
834                    // event list
835                    if (!pChannel->delayedEvents.queue.isEmpty()) {
836                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
837                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
838                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
839                        while (true) {
840                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
841                                pEventGenerator->popNextScheduledEvent(
842                                    pChannel->delayedEvents.queue,
843                                    pChannel->delayedEvents.schedulerNodes,
844                                    fragmentEndTime
845                                );
846                            if (!itDelayedEventNode) break;
847                            // get the actual delayed event object and free the used scheduler node
848                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
849                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
850                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
851                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
852                                continue;
853                            }
854                            // skip all events on main event list which have a time
855                            // before (or equal to) the delayed event to be inserted
856                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
857                                 ++itEvent);
858                            // now move delayed event from delayedEvents.pList to
859                            // the current position on the main event list
860                            itEvent = itDelayedEvent.moveBefore(itEvent);
861                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
862                        }
863                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
864                    }
865    
866                    // now process all events regularly
867                  {                  {
868                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
869                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 634  namespace LinuxSampler { Line 873  namespace LinuxSampler {
873                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
874                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
875                                  break;                                  break;
876                                case Event::type_play_note:
877                                    dmsg(5,("Engine: Play Note received\n"));
878                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
879                                    break;
880                              case Event::type_note_off:                              case Event::type_note_off:
881                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
882                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
883                                  break;                                  break;
884                                case Event::type_stop_note:
885                                    dmsg(5,("Engine: Stop Note received\n"));
886                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
887                                    break;
888                                case Event::type_kill_note:
889                                    dmsg(5,("Engine: Kill Note received\n"));
890                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
891                                    break;
892                              case Event::type_control_change:                              case Event::type_control_change:
893                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
894                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
895                                  break;                                  break;
896                                case Event::type_channel_pressure:
897                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
898                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
899                                    break;
900                                case Event::type_note_pressure:
901                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
902                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
903                                    break;
904                              case Event::type_pitchbend:                              case Event::type_pitchbend:
905                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
906                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
907                                  break;                                  break;
908                                case Event::type_note_synth_param:
909                                    dmsg(5,("Engine: Note Synth Param received\n"));
910                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
911                                    break;
912                                case Event::type_sysex:
913                                    break; // TODO ...
914    
915                                case Event::type_cancel_release_key:
916                                case Event::type_release_key:
917                                case Event::type_release_note:
918                                    break; // noop
919                          }                          }
920                      }                      }
921                  }                  }
# Line 653  namespace LinuxSampler { Line 923  namespace LinuxSampler {
923                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
924                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
925                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
926                    itLastStolenNote          = NoteIterator();
927                    itLastStolenNoteGlobally  = NoteIterator();
928                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
929                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
930                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
931              }              }
932    
933              /**              /**
934                 * Run all suspended script execution instances which are scheduled
935                 * to be resumed for the current audio fragment cycle.
936                 *
937                 * @param pChannel - engine channel on which suspended events occurred
938                 */
939                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
940                    while (true) {
941                        RTList<ScriptEvent>::Iterator itEvent =
942                            pEventGenerator->popNextScheduledScriptEvent(
943                                pChannel->pScript->suspendedEvents,
944                                *pChannel->pScript->pEvents, fragmentEndTime
945                            );
946                        if (!itEvent) break;
947                        ResumeScriptEvent(pChannel, itEvent);
948                    }
949                }
950    
951                /** @brief Call instrument script's event handler for this event.
952                 *
953                 * Causes a new execution instance of the currently loaded real-time
954                 * instrument script's event handler (callback) to be spawned for
955                 * the given MIDI event.
956                 *
957                 * @param pChannel - engine channel on which the MIDI event occurred
958                 * @param itEvent - MIDI event that causes this new script execution
959                 * @param pEventHandler - script's event handler to be executed
960                 */
961                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
962                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
963                    // check if polyphonic data is passed from "note" to "release"
964                    // script event handlers
965                    if (pEventHandler == pChannel->pScript->handlerRelease &&
966                        pChannel->pScript->handlerNote &&
967                        pChannel->pScript->handlerNote->isPolyphonic() &&
968                        pChannel->pScript->handlerRelease->isPolyphonic() &&
969                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
970                    {
971                        // polyphonic variable data is used/passed from "note" to
972                        // "release" script callback, so we have to recycle the
973                        // original "note on" script event(s)
974                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
975                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
976                        for (; it != end; ++it) {
977                            ProcessScriptEvent(
978                                pChannel, itEvent, pEventHandler, it
979                            );
980                        }
981                    } else {
982                        // no polyphonic data is used/passed from "note" to
983                        // "release" script callback, so just use a new fresh
984                        // script event object
985                        RTList<ScriptEvent>::Iterator itScriptEvent =
986                            pChannel->pScript->pEvents->allocAppend();
987                        // if event handler uses polyphonic variables, reset them
988                        // to zero values before starting to execute the handler
989                        if (pEventHandler->isPolyphonic())
990                            itScriptEvent->execCtx->resetPolyphonicData();
991                        ProcessScriptEvent(
992                            pChannel, itEvent, pEventHandler, itScriptEvent
993                        );
994                    }
995                }
996    
997                /** @brief Spawn new execution instance of an instrument script handler.
998                 *
999                 * Will be called to initiate a new execution of a real-time
1000                 * instrument script event right from the start of the script's
1001                 * respective handler. If script execution did not complete after
1002                 * calling this method, the respective script exeuction is then
1003                 * suspended and a call to ResumeScriptEvent() will be used next
1004                 * time to continue its execution.
1005                 *
1006                 * @param pChannel - engine channel this script is running for
1007                 * @param itEvent - event which caused execution of this script
1008                 *                  event handler
1009                 * @param pEventHandler - VM representation of event handler to be
1010                 *                        executed
1011                 * @param itScriptEvent - script event that shall be processed
1012                 */
1013                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1014                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1015    
1016                    // fill the list of script handlers to be executed by this event
1017                    int i = 0;
1018                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1019                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1020    
1021                    // initialize/reset other members
1022                    itScriptEvent->cause = *itEvent;
1023                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1024                    itScriptEvent->currentHandler = 0;
1025                    itScriptEvent->executionSlices = 0;
1026                    itScriptEvent->ignoreAllWaitCalls = false;
1027                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1028                    // this is the native representation of the $EVENT_ID script variable
1029                    itScriptEvent->id =
1030                        (itEvent->Type == Event::type_note_on)
1031                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1032                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1033    
1034                    // run script handler(s)
1035                    VMExecStatus_t res = pScriptVM->exec(
1036                        pChannel->pScript->parserContext, &*itScriptEvent
1037                    );
1038    
1039                    // was the script suspended?
1040                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1041                        // in case the script was suspended, keep it on the allocated
1042                        // ScriptEvent list to be resume at the scheduled time in future,
1043                        // additionally insert it into a sorted time queue
1044                        pEventGenerator->scheduleAheadMicroSec(
1045                            pChannel->pScript->suspendedEvents, // scheduler queue
1046                            *itScriptEvent, // script event
1047                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1048                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1049                        );
1050                    } else { // script execution has finished without 'suspended' status ...
1051                        // if "polyphonic" variable data is passed from script's
1052                        // "note" event handler to its "release" event handler, then
1053                        // the script event must be kept and recycled for the later
1054                        // occuring "release" script event ...
1055                        if (pEventHandler == pChannel->pScript->handlerNote &&
1056                            pChannel->pScript->handlerRelease &&
1057                            pChannel->pScript->handlerNote->isPolyphonic() &&
1058                            pChannel->pScript->handlerRelease->isPolyphonic())
1059                        {
1060                            const int key = itEvent->Param.Note.Key;
1061                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1062                        } else {
1063                            // ... otherwise if no polyphonic data is passed and
1064                            // script's execution has finished without suspension
1065                            // status, then free the script event for a new future
1066                            // script event to be triggered from start
1067                            pChannel->pScript->pEvents->free(itScriptEvent);
1068                        }
1069                    }
1070                }
1071    
1072                /** @brief Resume execution of instrument script.
1073                 *
1074                 * Will be called to resume execution of a real-time instrument
1075                 * script event which has been suspended previously.
1076                 *
1077                 * Script execution might be suspended for various reasons. Usually
1078                 * a script will be suspended if the script called the built-in
1079                 * "wait()" function, but it might also be suspended automatically
1080                 * if the script took too much execution time in an audio fragment
1081                 * cycle. So in the latter case automatic suspension is performed in
1082                 * order to avoid harm for the sampler's overall real-time
1083                 * requirements.
1084                 *
1085                 * @param pChannel - engine channel this script is running for
1086                 * @param itScriptEvent - script execution that shall be resumed
1087                 */
1088                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1089                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1090    
1091                    // run script
1092                    VMExecStatus_t res = pScriptVM->exec(
1093                        pChannel->pScript->parserContext, &*itScriptEvent
1094                    );
1095    
1096                    // was the script suspended?
1097                    if (res & VM_EXEC_SUSPENDED) {
1098                        // in case the script was suspended, keep it on the allocated
1099                        // ScriptEvent list to be resume at the scheduled time in future,
1100                        // additionally insert it into a sorted time queue
1101                        pEventGenerator->scheduleAheadMicroSec(
1102                            pChannel->pScript->suspendedEvents, // scheduler queue
1103                            *itScriptEvent, // script event
1104                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1105                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1106                        );
1107                    } else { // script execution has finished without 'suspended' status ...
1108                        // if "polyphonic" variable data is passed from script's
1109                        // "note" event handler to its "release" event handler, then
1110                        // the script event must be kept and recycled for the later
1111                        // occuring "release" script event ...
1112                        if (handler && handler == pChannel->pScript->handlerNote &&
1113                            pChannel->pScript->handlerRelease &&
1114                            pChannel->pScript->handlerNote->isPolyphonic() &&
1115                            pChannel->pScript->handlerRelease->isPolyphonic())
1116                        {
1117                            const int key = itScriptEvent->cause.Param.Note.Key;
1118                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1119                        } else {
1120                            // ... otherwise if no polyphonic data is passed and
1121                            // script's execution has finished without suspension
1122                            // status, then free the script event for a new future
1123                            // script event to be triggered from start
1124                            pChannel->pScript->pEvents->free(itScriptEvent);
1125                        }
1126                    }
1127                }
1128    
1129                /**
1130               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1131               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1132               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1133               *  voice actually died.               *  voice actually died.
1134               *               *
1135               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1136               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1137               *  @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
1138               */               */
1139              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1140                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1141                      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"));
1142                      return -1;                      return -1;
# Line 676  namespace LinuxSampler { Line 1144  namespace LinuxSampler {
1144    
1145                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1146    
1147                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1148                        dmsg(1,("Event pool emtpy!\n"));
1149                        return -1;
1150                    }
1151    
1152                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1153                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1154                          return 0;                      return 0;
1155                      }                  }
1156    
1157                      // 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
1158                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1159                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1160                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1161                      int                       iChannelIndex;                  int                          iChannelIndex;
1162                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1163    
1164                      // select engine channel                  // select engine channel
1165                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1166                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1167                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1168                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1169                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1170                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1171                      }                  }
1172    
1173                      // 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
1174                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1175                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1176                          do {                      do {
1177                              ++itSelectedVoice;                          ++itSelectedVoice;
1178                          } 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
1179                    }
1180                    // did we find a 'stealable' voice?
1181                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1182                        // remember which voice we stole, so we can simply proceed on next voice stealing
1183                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1184                        // done
1185                        goto stealable_voice_found;
1186                    }
1187    
1188                    // get (next) oldest note
1189                    if (this->itLastStolenNoteGlobally) {
1190                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1191                             itNote; ++itNote)
1192                        {
1193                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1194                                // proceed iterating if voice was created in this audio fragment cycle
1195                                if (itSelectedVoice->IsStealable()) {
1196                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1197                                    this->itLastStolenNoteGlobally  = itNote;
1198                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1199                                    goto stealable_voice_found; // selection succeeded
1200                                }
1201                            }
1202                      }                      }
1203                    }
1204    
1205                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1206                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1207                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1208    
1209                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1210                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1211                          // 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();
1212                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1213                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1214                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1215                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1216                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1217                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1218                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1219                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1220                                itSelectedVoice = itNote->pActiveVoices->first();
1221                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1222                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1223                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1224                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1225                                  // 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
1226                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1227                                    this->itLastStolenNoteGlobally  = itNote;
1228                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1229                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1230                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1231                              }                              }
                             ++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);  
1232                          }                          }
1233                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1234                      }                      }
1235                        // get next engine channel
1236                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1237                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1238    
1239                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1240                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1241                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1242                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1243                            dmsg(1,("Exiting.\n"));
1244                            exit(-1);
1245                      }                      }
1246                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1247                    }
1248    
1249                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1250                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1251    
1252                      return 0; // success                  #if CONFIG_DEVMODE
1253                  }                  if (!itSelectedVoice->IsActive()) {
1254                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1255                      return -1;                      return -1;
1256                  }                  }
1257                    #endif // CONFIG_DEVMODE
1258    
1259                    // now kill the selected voice
1260                    itSelectedVoice->Kill(itNoteOnEvent);
1261    
1262                    --VoiceSpawnsLeft;
1263    
1264                    return 0; // success
1265              }              }
1266    
1267              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 790  namespace LinuxSampler { Line 1283  namespace LinuxSampler {
1283                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1284                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1285                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1286                            pEngineChannel->pScript =
1287                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1288                          instrumentChanged = true;                          instrumentChanged = true;
1289    
1290                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1291    
1292                            // the script's "init" event handler is only executed
1293                            // once (when the script is loaded or reloaded)
1294                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1295                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1296                                RTList<ScriptEvent>::Iterator itScriptEvent =
1297                                    pEngineChannel->pScript->pEvents->allocAppend();
1298    
1299                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1300                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1301                                itScriptEvent->handlers[1] = NULL;
1302                                itScriptEvent->currentHandler = 0;
1303                                itScriptEvent->executionSlices = 0;
1304                                itScriptEvent->ignoreAllWaitCalls = false;
1305                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1306    
1307                                /*VMExecStatus_t res = */ pScriptVM->exec(
1308                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
1309                                );
1310    
1311                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1312                            }
1313                      }                      }
1314                  }                  }
1315    
# Line 843  namespace LinuxSampler { Line 1360  namespace LinuxSampler {
1360                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1361                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1362                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1363                        
1364                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1365                          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);
1366                      if (itNewVoice) {                      if (itNewVoice) {
1367                            // usually there should already be a new Note object
1368                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1369                            if (!itNote) { // should not happen, but just to be sure ...
1370                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1371                                if (!noteID) {
1372                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1373                                    continue;
1374                                }
1375                                itNote = GetNotePool()->fromID(noteID);
1376                            }
1377                            // move voice from whereever it was, to the new note's list of active voices
1378                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1379                            // render audio of this new voice for the first time
1380                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1381                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1382                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 883  namespace LinuxSampler { Line 1414  namespace LinuxSampler {
1414                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1415    
1416                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1417                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1418                    pChannel->ClearEventListsOfCurrentFragment();
1419              }              }
1420    
1421              /**              /**
# Line 948  namespace LinuxSampler { Line 1480  namespace LinuxSampler {
1480                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1481                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1482                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1483                                      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));
1484                                      if (note < 128)                                      if (note < 128)
1485                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1486                                      break;                                      break;
# Line 956  namespace LinuxSampler { Line 1488  namespace LinuxSampler {
1488                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1489                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1490                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1491                                      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));
1492                                      if (note < 128)                                      if (note < 128)
1493                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1494                                      break;                                      break;
# Line 1109  namespace LinuxSampler { Line 1641  namespace LinuxSampler {
1641              /**              /**
1642               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1643               *               *
1644               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1645               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1646               */               */
1647              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1648                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1649                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1650    
                 //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;  
   
1651                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1652                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1653                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1654    
1655                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1656    
1657                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1658                    // programmatically spawned notes (Event::type_play_note). We have
1659                    // to distinguish between them, since certain processing below
1660                    // must only be done on real MIDI note-on events (i.e. for
1661                    // correctly updating which MIDI keys are currently pressed down).
1662                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1663    
1664                    if (isRealMIDINoteOnEvent)
1665                        pChannel->listeners.PreProcessNoteOn(key, vel);
1666    
1667                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1668                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1669                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1670                            pChannel->listeners.PostProcessNoteOn(key, vel);
1671                      return;                      return;
1672                  }                  }
1673                  #endif                  #endif
1674    
1675                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1676                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1677                            pChannel->listeners.PostProcessNoteOn(key, vel);
1678                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1679                  }                  }
1680    
# Line 1143  namespace LinuxSampler { Line 1682  namespace LinuxSampler {
1682                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1683    
1684                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1685                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1686                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1687                      if (itYoungestKey) {                      if (itYoungestKey) {
1688                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1151  namespace LinuxSampler { Line 1690  namespace LinuxSampler {
1690                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1691                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1692                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1693                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1694                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1695                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1696                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1697                                    }
1698                              }                              }
1699                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1700                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1701                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1702                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1703                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1704                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1705                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1706                                    }
1707                              }                              }
1708                          }                          }
1709                      }                      }
# Line 1167  namespace LinuxSampler { Line 1711  namespace LinuxSampler {
1711                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1712                  }                  }
1713    
1714                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1715                        pChannel->ProcessKeySwitchChange(key);
1716    
1717                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1718                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1719                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1720                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1721                    }
1722    
1723                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1724                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1725                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1726                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1727                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1728                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1729                      }                      }
1730                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1731                  }                  }
# Line 1189  namespace LinuxSampler { Line 1736  namespace LinuxSampler {
1736                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1737                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1738    
1739                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1740                        pChannel->PortamentoPos = (float) key;
1741    
1742                    //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?
1743                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1744                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1745                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1746                  }                  }
1747                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1748                    if (isRealMIDINoteOnEvent)
1749                        pChannel->listeners.PostProcessNoteOn(key, vel);
1750              }              }
1751    
1752              /**              /**
# Line 1220  namespace LinuxSampler { Line 1772  namespace LinuxSampler {
1772               *  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.
1773               *  due to completion of sample playback).               *  due to completion of sample playback).
1774               *               *
1775               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1776               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1777               */               */
1778              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1779                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1780    
                 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;  
   
1781                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1782                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1783                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1784    
1785                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1786    
1787                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1788                    // programmatically spawned notes (Event::type_stop_note). We have
1789                    // to distinguish between them, since certain processing below
1790                    // must only be done on real MIDI note-off events (i.e. for
1791                    // correctly updating which MIDI keys are currently pressed down),
1792                    // plus a stop-note event just releases voices of one particular
1793                    // note, whereas a note-off event releases all voices on a
1794                    // particular MIDI key instead.
1795                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1796    
1797                    if (isRealMIDINoteOffEvent)
1798                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1799    
1800                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1801                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1802                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1803                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1804                      return;                      return;
1805                  }                  }
1806                  #endif                  #endif
1807    
1808                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1809                        pKey->KeyPressed = false; // the MIDI key was now released
1810                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1811                    }
1812    
1813                  // move event to the key's own event list                  // move event to the key's own event list
1814                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1815    
1816                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1817                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1818    
1819                  // 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)
1820                  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
1821                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1822                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1823                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1824                          // 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
1825                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1826                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1827                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1828                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1829                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1830                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1831                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1832                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1833                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1834                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1835                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1836                                  // create a pseudo note on event                                      }
1837                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1838                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1839                                      // copy event                                      if (itPseudoNoteOnEvent) {
1840                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1841                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1842                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1843                                      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)
1844                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1845                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1846                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1847                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1848                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1849                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1850                                            }
1851                                            // if neither a voice was spawned or postponed then remove note on event from key again
1852                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1853                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1854    
1855                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1856                                  break; // done                                      break; // done
1857                                    }
1858                              }                              }
1859                          }                          }
1860                      }                          if (bOtherKeysPressed) {
1861                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1862                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1863                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1864                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1865                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1866                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1867                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1868                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1869                                        }
1870                                    }
1871                              }                              }
1872                          }                          } else pChannel->PortamentoPos = -1.0f;
1873                      } 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  
1874    
1875                      // 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
1876                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1877                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1878                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1879                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1880                        }
1881                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1882                        // This programmatically caused event is caused by a call to
1883                        // the built-in instrument script function note_off(). In
1884                        // contrast to a real MIDI note-off event the stop-note
1885                        // event just intends to release voices of one particular note.
1886                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1887                        if (pNote) { // the requested note is still alive ...
1888                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1889                        } else { // note is dead and gone ..
1890                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1891                            return; // prevent event to be removed a 2nd time below
1892                      }                      }
1893                  }                  }
1894    
# Line 1317  namespace LinuxSampler { Line 1896  namespace LinuxSampler {
1896                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1897                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1898    
1899                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1900                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1901                }
1902    
1903                /**
1904                 * Called on sustain pedal up events to check and if required,
1905                 * launch release trigger voices on the respective active key.
1906                 *
1907                 * @param pEngineChannel - engine channel on which this event occurred on
1908                 * @param itEvent - release trigger event (contains note number)
1909                 */
1910                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1911                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1912    
1913                    const int iKey = itEvent->Param.Note.Key;
1914                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1915    
1916                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1917    
1918                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1919                }
1920    
1921                /**
1922                 * Called on note-off and sustain pedal up events to check and if
1923                 * required, launch release trigger voices on the respective active
1924                 * key.
1925                 *
1926                 * @param pEngineChannel - engine channel on which this event occurred on
1927                 * @param itEvent - note off event / release trigger event
1928                 * @param pKey - key on which the release trigger voices shall be spawned
1929                 */
1930                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1931                    // spawn release triggered voice(s) if needed
1932                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1933                        // assign a new note to this release event
1934                        if (LaunchNewNote(pChannel, itEvent)) {
1935                            // allocate and trigger new release voice(s)
1936                            TriggerReleaseVoices(pChannel, itEvent);
1937                        }
1938                        pKey->ReleaseTrigger = false;
1939                    }
1940                }
1941    
1942                /**
1943                 * Called on "kill note" events, which currently only happens on
1944                 * built-in real-time instrument script function fade_out(). This
1945                 * method only fulfills one task: moving the even to the Note's own
1946                 * event list so that its voices can process the kill event sample
1947                 * accurately.
1948                 */
1949                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1950                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1951    
1952                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1953                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1954    
1955                    // move note kill event to its MIDI key
1956                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1957                    itEvent.moveToEndOf(pKey->pEvents);
1958                }
1959    
1960                /**
1961                 * Called on note synthesis parameter change events. These are
1962                 * internal events caused by calling built-in real-time instrument
1963                 * script functions like change_vol(), change_tune(), etc.
1964                 *
1965                 * This method performs two tasks:
1966                 *
1967                 * - It converts the event's relative values changes (Deltas) to
1968                 *   the respective final new synthesis parameter value (AbsValue),
1969                 *   for that particular moment of the event that is.
1970                 *
1971                 * - It moves the individual events to the Note's own event list
1972                 *   (or actually to the event list of the MIDI key), so that
1973                 *   voices can process those events sample accurately.
1974                 *
1975                 * @param pEngineChannel - engine channel on which this event occurred on
1976                 * @param itEvent - note synthesis parameter change event
1977                 */
1978                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1979                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1980    
1981                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1982                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1983    
1984                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1985    
1986                    switch (itEvent->Param.NoteSynthParam.Type) {
1987                        case Event::synth_param_volume:
1988                            if (relative)
1989                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1990                            else
1991                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1992                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1993                            break;
1994                        case Event::synth_param_volume_time:
1995                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1996                            break;
1997                        case Event::synth_param_pitch:
1998                            if (relative)
1999                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2000                            else
2001                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2002                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2003                            break;
2004                        case Event::synth_param_pitch_time:
2005                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2006                            break;
2007                        case Event::synth_param_pan:
2008                            if (relative) {
2009                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2010                            } else {
2011                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2012                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2013                            }
2014                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2015                            break;
2016                        case Event::synth_param_cutoff:
2017                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2018                            break;
2019                        case Event::synth_param_resonance:
2020                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2021                            break;
2022                        case Event::synth_param_attack:
2023                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2024                            break;
2025                        case Event::synth_param_decay:
2026                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2027                            break;
2028                        case Event::synth_param_release:
2029                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2030                            break;
2031                        case Event::synth_param_amp_lfo_depth:
2032                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2033                            break;
2034                        case Event::synth_param_amp_lfo_freq:
2035                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2036                            break;
2037                        case Event::synth_param_pitch_lfo_depth:
2038                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2039                            break;
2040                        case Event::synth_param_pitch_lfo_freq:
2041                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2042                            break;
2043                    }
2044    
2045                    // move note parameter event to its MIDI key
2046                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2047                    itEvent.moveToEndOf(pKey->pEvents);
2048              }              }
2049    
2050              /**              /**
2051               *  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
2052               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2053               */               */
2054              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2055                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
2056    
2057                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
2058                  // while it's reseting                  // while it's reseting
# Line 1337  namespace LinuxSampler { Line 2064  namespace LinuxSampler {
2064                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2065                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2066                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2067                    itLastStolenNote           = NoteIterator();
2068                    itLastStolenNoteGlobally   = NoteIterator();
2069                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2070                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2071                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2072    
2073                    // reset all notes
2074                    pNotePool->clear();
2075                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2076                         itNote = pNotePool->allocAppend())
2077                    {
2078                        itNote->reset();
2079                    }
2080                    pNotePool->clear();
2081    
2082                  // reset all voices                  // reset all voices
2083                    pVoicePool->clear();
2084                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2085                      iterVoice->Reset();                      iterVoice->Reset();
2086                  }                  }
2087                  pVoicePool->clear();                  pVoicePool->clear();
2088    
2089                    // reset all engine channels
2090                    for (int i = 0; i < engineChannels.size(); i++) {
2091                        AbstractEngineChannel* pEngineChannel =
2092                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2093                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2094                    }
2095    
2096                  // reset disk thread                  // reset disk thread
2097                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2098    
# Line 1354  namespace LinuxSampler { Line 2100  namespace LinuxSampler {
2100                  pEventQueue->init();                  pEventQueue->init();
2101                  pSysexBuffer->init();                  pSysexBuffer->init();
2102                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
2103              }              }
2104    
2105              /**              /**
# Line 1365  namespace LinuxSampler { Line 2110  namespace LinuxSampler {
2110               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2111               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2112               */               */
2113              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2114                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2115                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2116                  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 1376  namespace LinuxSampler { Line 2121  namespace LinuxSampler {
2121               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2122               *  (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).
2123               *               *
2124               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2125               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2126               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2127               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1400  namespace LinuxSampler { Line 2145  namespace LinuxSampler {
2145                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2146              ) = 0;              ) = 0;
2147    
2148              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2149    
2150              int InitNewVoice (              int InitNewVoice (
2151                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1419  namespace LinuxSampler { Line 2164  namespace LinuxSampler {
2164                      // launch the new voice                      // launch the new voice
2165                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2166                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2167                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2168                      }                      }
2169                      else { // on success                      else { // on success
2170                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1450  namespace LinuxSampler { Line 2195  namespace LinuxSampler {
2195    
2196                  return -1;                  return -1;
2197              }              }
2198                
2199                /**
2200                 * Checks whether scale tuning setting has been changed since last
2201                 * time this method was called, if yes, it recalculates the pitch
2202                 * for all active voices.
2203                 */
2204                void ProcessScaleTuningChange() {
2205                    const bool changed = ScaleTuningChanged.readAndReset();
2206                    if (!changed) return;
2207                    
2208                    for (int i = 0; i < engineChannels.size(); i++) {
2209                        EngineChannelBase<V, R, I>* channel =
2210                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2211                        channel->OnScaleTuningChanged();
2212                    }
2213                }
2214    
2215          private:          private:
2216                Pool< Note<V> >* pNotePool;
2217                Pool<note_id_t> noteIDPool;
2218              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2219              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2220              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2410  
changed lines
  Added in v.3207

  ViewVC Help
Powered by ViewVC