/[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 2427 by persson, Sat Mar 2 07:03:04 2013 UTC revision 3188 by schoenebeck, Fri May 19 14:23:12 2017 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 32  Line 33 
33  #include "InstrumentManager.h"  #include "InstrumentManager.h"
34  #include "../common/global_private.h"  #include "../common/global_private.h"
35    
36    // a bit headroom over CONFIG_MAX_VOICES to avoid minor complications i.e. under voice stealing conditions
37    #define MAX_NOTES_HEADROOM  3
38    #define GLOBAL_MAX_NOTES    (GLOBAL_MAX_VOICES * MAX_NOTES_HEADROOM)
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
# Line 45  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49          class IM  /* Instrument Manager */,          class IM  /* Instrument Manager */,
50          class I   /* Instrument */          class I   /* Instrument */
51      >      >
52      class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {      class EngineBase: public AbstractEngine, public RegionPools<R>, public NotePool<V> {
53    
54          public:          public:
55                typedef typename RTList< Note<V> >::Iterator NoteIterator;
56              typedef typename RTList<V>::Iterator VoiceIterator;              typedef typename RTList<V>::Iterator VoiceIterator;
57              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 79  namespace LinuxSampler { Line 97  namespace LinuxSampler {
97                      dmsg(1,("OK\n"));                      dmsg(1,("OK\n"));
98                  }                  }
99    
100                    if (pNotePool) {
101                        pNotePool->clear();
102                        delete pNotePool;
103                    }
104    
105                  if (pVoicePool) {                  if (pVoicePool) {
106                      pVoicePool->clear();                      pVoicePool->clear();
107                      delete pVoicePool;                      delete pVoicePool;
# Line 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                  {                  {
475                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
476                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
477                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
478                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
479                  }                  }
480                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
481              }              }
482    
483              /**              /**
# Line 445  namespace LinuxSampler { Line 487  namespace LinuxSampler {
487               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
488               */               */
489              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
490                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
491                  {                  {
492                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
493                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
494                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
495                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
496                  }                  }
497                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
498              }              }
499    
500              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 555  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 574  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 603  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649    
650              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
651              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
652                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
653              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
654              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
655              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
656                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
657              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
658              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
659              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
660              int iMaxDiskStreams;              int iMaxDiskStreams;
661    
662                NoteBase* NoteByID(note_id_t id) OVERRIDE {
663                    NoteIterator itNote = GetNotePool()->fromID(id);
664                    if (!itNote) return NULL;
665                    return &*itNote;
666                }
667    
668                /**
669                 * Gets a new @c Note object from the note pool, initializes it
670                 * appropriately, links it with requested parent note (if
671                 * requested), moves it to the appropriate key's list of active
672                 * notes it, and sticks the new note's unique ID to the
673                 * passed @a pNoteOnEvent.
674                 *
675                 * @param pEngineChannel - engine channel on which this event happened
676                 * @param pNoteOnEvent - event which caused this
677                 * @returns new note's unique ID (or zero on error)
678                 */
679                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
680                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
681                    Pool< Note<V> >* pNotePool = GetNotePool();
682    
683                    if (pNotePool->poolIsEmpty()) {
684                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
685                        return 0; // error
686                    }
687    
688                    // create a new note (for new voices to be assigned to)
689                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
690                    NoteIterator itNewNote = pNotePool->allocAppend();
691                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
692    
693                    // remember the engine's time when this note was triggered exactly
694                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
695    
696                    // usually the new note (and its subsequent voices) will be
697                    // allocated on the key provided by the event's note number,
698                    // however if this new note is requested not to be a regular
699                    // note, but rather a child note, then this new note will be
700                    // allocated on the parent note's key instead in order to
701                    // release the child note simultaniously with its parent note
702                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
703    
704                    // in case this new note was requested to be a child note,
705                    // then retrieve its parent note and link them with each other
706                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
707                    if (parentNoteID) {
708                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
709                        if (itParentNote) {
710                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
711                            if (itChildNoteID) {
712                                // link parent and child note with each other
713                                *itChildNoteID = newNoteID;
714                                itNewNote->parentNoteID = parentNoteID;
715                                itNewNote->hostKey = itParentNote->hostKey;
716                            } else {    
717                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
718                                pNotePool->free(itNewNote);
719                                return 0; // error
720                            }
721                        } else {
722                            // the parent note was apparently released already, so
723                            // free the new note again and inform caller that it
724                            // should drop the event
725                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
726                            pNotePool->free(itNewNote);
727                            return 0; // error
728                        }
729                    }
730    
731                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
732    
733                    // copy event which caused this note
734                    itNewNote->cause = *pNoteOnEvent;
735                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
736    
737                    // move new note to its host key
738                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
739                    itNewNote.moveToEndOf(pKey->pActiveNotes);
740    
741                    // assign unique note ID of this new note to the original note on event
742                    pNoteOnEvent->Param.Note.ID = newNoteID;
743    
744                    return newNoteID; // success
745                }
746    
747              /**              /**
748               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
749               * engine channel.               * engine channel.
# Line 626  namespace LinuxSampler { Line 759  namespace LinuxSampler {
759                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
760                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
761    
762                  // process events                  // if a valid real-time instrument script is loaded, pre-process
763                    // the event list by running the script now, since the script
764                    // might filter events or add new ones for this cycle
765                    if (pChannel->pScript) {
766                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
767    
768                        // resume suspended script executions been scheduled for
769                        // this audio fragment cycle (which were suspended in a
770                        // previous audio fragment cycle)
771                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
772    
773                        // spawn new script executions for the new MIDI events of
774                        // this audio fragment cycle
775                        //
776                        // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
777                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
778                            end = pChannel->pEvents->end(); itEvent != end; )
779                        {
780                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
781                            RTList<Event>::Iterator itNext = itEvent;
782                            ++itNext;
783    
784                            switch (itEvent->Type) {
785                                case Event::type_note_on:
786                                    if (pChannel->pScript->handlerNote)
787                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
788                                    break;
789                                case Event::type_note_off:
790                                    if (pChannel->pScript->handlerRelease)
791                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
792                                    break;
793                                case Event::type_control_change:
794                                case Event::type_channel_pressure:
795                                case Event::type_pitchbend:
796                                    if (pChannel->pScript->handlerController)
797                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
798                                    break;
799                                case Event::type_note_pressure:
800                                    //TODO: ...
801                                    break;
802    
803                                case Event::type_sysex:
804                                    //TODO: ...
805                                    break;
806    
807                                case Event::type_cancel_release_key:
808                                case Event::type_release_key:
809                                case Event::type_release_note:
810                                case Event::type_play_note:
811                                case Event::type_stop_note:
812                                case Event::type_kill_note:
813                                case Event::type_note_synth_param:
814                                    break; // noop
815                            }
816    
817                            // see HACK comment above
818                            itEvent = itNext;
819                        }
820    
821                        // this has to be run again, since the newly spawned scripts
822                        // above may have cause suspended scripts that must be
823                        // resumed within this same audio fragment cycle
824                        //
825                        // FIXME: see FIXME comment above
826                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
827                    }
828    
829                    // if there are any delayed events scheduled for the current
830                    // audio fragment cycle, then move and sort them into the main
831                    // event list
832                    if (!pChannel->delayedEvents.queue.isEmpty()) {
833                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
834                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
835                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
836                        while (true) {
837                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
838                                pEventGenerator->popNextScheduledEvent(
839                                    pChannel->delayedEvents.queue,
840                                    pChannel->delayedEvents.schedulerNodes,
841                                    fragmentEndTime
842                                );
843                            if (!itDelayedEventNode) break;
844                            // get the actual delayed event object and free the used scheduler node
845                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
846                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
847                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
848                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
849                                continue;
850                            }
851                            // skip all events on main event list which have a time
852                            // before (or equal to) the delayed event to be inserted
853                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
854                                 ++itEvent);
855                            // now move delayed event from delayedEvents.pList to
856                            // the current position on the main event list
857                            itEvent = itDelayedEvent.moveBefore(itEvent);
858                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
859                        }
860                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
861                    }
862    
863                    // now process all events regularly
864                  {                  {
865                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
866                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 636  namespace LinuxSampler { Line 870  namespace LinuxSampler {
870                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
871                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
872                                  break;                                  break;
873                                case Event::type_play_note:
874                                    dmsg(5,("Engine: Play Note received\n"));
875                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
876                                    break;
877                              case Event::type_note_off:                              case Event::type_note_off:
878                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
879                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
880                                  break;                                  break;
881                                case Event::type_stop_note:
882                                    dmsg(5,("Engine: Stop Note received\n"));
883                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
884                                    break;
885                                case Event::type_kill_note:
886                                    dmsg(5,("Engine: Kill Note received\n"));
887                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
888                                    break;
889                              case Event::type_control_change:                              case Event::type_control_change:
890                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
891                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
892                                  break;                                  break;
893                                case Event::type_channel_pressure:
894                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
895                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
896                                    break;
897                                case Event::type_note_pressure:
898                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
899                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
900                                    break;
901                              case Event::type_pitchbend:                              case Event::type_pitchbend:
902                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
903                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
904                                  break;                                  break;
905                                case Event::type_note_synth_param:
906                                    dmsg(5,("Engine: Note Synth Param received\n"));
907                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
908                                    break;
909                                case Event::type_sysex:
910                                    break; // TODO ...
911    
912                                case Event::type_cancel_release_key:
913                                case Event::type_release_key:
914                                case Event::type_release_note:
915                                    break; // noop
916                          }                          }
917                      }                      }
918                  }                  }
# Line 655  namespace LinuxSampler { Line 920  namespace LinuxSampler {
920                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
921                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
922                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
923                    itLastStolenNote          = NoteIterator();
924                    itLastStolenNoteGlobally  = NoteIterator();
925                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
926                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
927                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
928              }              }
929    
930              /**              /**
931                 * Run all suspended script execution instances which are scheduled
932                 * to be resumed for the current audio fragment cycle.
933                 *
934                 * @param pChannel - engine channel on which suspended events occurred
935                 */
936                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
937                    while (true) {
938                        RTList<ScriptEvent>::Iterator itEvent =
939                            pEventGenerator->popNextScheduledScriptEvent(
940                                pChannel->pScript->suspendedEvents,
941                                *pChannel->pScript->pEvents, fragmentEndTime
942                            );
943                        if (!itEvent) break;
944                        ResumeScriptEvent(pChannel, itEvent);
945                    }
946                }
947    
948                /** @brief Call instrument script's event handler for this event.
949                 *
950                 * Causes a new execution instance of the currently loaded real-time
951                 * instrument script's event handler (callback) to be spawned for
952                 * the given MIDI event.
953                 *
954                 * @param pChannel - engine channel on which the MIDI event occurred
955                 * @param itEvent - MIDI event that causes this new script execution
956                 * @param pEventHandler - script's event handler to be executed
957                 */
958                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
959                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
960                    // check if polyphonic data is passed from "note" to "release"
961                    // script event handlers
962                    if (pEventHandler == pChannel->pScript->handlerRelease &&
963                        pChannel->pScript->handlerNote &&
964                        pChannel->pScript->handlerNote->isPolyphonic() &&
965                        pChannel->pScript->handlerRelease->isPolyphonic() &&
966                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
967                    {
968                        // polyphonic variable data is used/passed from "note" to
969                        // "release" script callback, so we have to recycle the
970                        // original "note on" script event(s)
971                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
972                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
973                        for (; it != end; ++it) {
974                            ProcessScriptEvent(
975                                pChannel, itEvent, pEventHandler, it
976                            );
977                        }
978                    } else {
979                        // no polyphonic data is used/passed from "note" to
980                        // "release" script callback, so just use a new fresh
981                        // script event object
982                        RTList<ScriptEvent>::Iterator itScriptEvent =
983                            pChannel->pScript->pEvents->allocAppend();
984                        ProcessScriptEvent(
985                            pChannel, itEvent, pEventHandler, itScriptEvent
986                        );
987                    }
988                }
989    
990                /** @brief Spawn new execution instance of an instrument script handler.
991                 *
992                 * Will be called to initiate a new execution of a real-time
993                 * instrument script event right from the start of the script's
994                 * respective handler. If script execution did not complete after
995                 * calling this method, the respective script exeuction is then
996                 * suspended and a call to ResumeScriptEvent() will be used next
997                 * time to continue its execution.
998                 *
999                 * @param pChannel - engine channel this script is running for
1000                 * @param itEvent - event which caused execution of this script
1001                 *                  event handler
1002                 * @param pEventHandler - VM representation of event handler to be
1003                 *                        executed
1004                 * @param itScriptEvent - script event that shall be processed
1005                 */
1006                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1007                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1008    
1009                    // fill the list of script handlers to be executed by this event
1010                    int i = 0;
1011                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1012                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1013    
1014                    // initialize/reset other members
1015                    itScriptEvent->cause = *itEvent;
1016                    itScriptEvent->currentHandler = 0;
1017                    itScriptEvent->executionSlices = 0;
1018                    itScriptEvent->ignoreAllWaitCalls = false;
1019                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1020                    // this is the native representation of the $EVENT_ID script variable
1021                    itScriptEvent->id =
1022                        (itEvent->Type == Event::type_note_on)
1023                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1024                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1025    
1026                    // run script handler(s)
1027                    VMExecStatus_t res = pScriptVM->exec(
1028                        pChannel->pScript->parserContext, &*itScriptEvent
1029                    );
1030    
1031                    // was the script suspended?
1032                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1033                        // in case the script was suspended, keep it on the allocated
1034                        // ScriptEvent list to be resume at the scheduled time in future,
1035                        // additionally insert it into a sorted time queue
1036                        pEventGenerator->scheduleAheadMicroSec(
1037                            pChannel->pScript->suspendedEvents, // scheduler queue
1038                            *itScriptEvent, // script event
1039                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1040                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1041                        );
1042                    } else { // script execution has finished without 'suspended' status ...
1043                        // if "polyphonic" variable data is passed from script's
1044                        // "note" event handler to its "release" event handler, then
1045                        // the script event must be kept and recycled for the later
1046                        // occuring "release" script event ...
1047                        if (pEventHandler == pChannel->pScript->handlerNote &&
1048                            pChannel->pScript->handlerRelease &&
1049                            pChannel->pScript->handlerNote->isPolyphonic() &&
1050                            pChannel->pScript->handlerRelease->isPolyphonic())
1051                        {
1052                            const int key = itEvent->Param.Note.Key;
1053                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1054                        } else {
1055                            // ... otherwise if no polyphonic data is passed and
1056                            // script's execution has finished without suspension
1057                            // status, then free the script event for a new future
1058                            // script event to be triggered from start
1059                            pChannel->pScript->pEvents->free(itScriptEvent);
1060                        }
1061                    }
1062                }
1063    
1064                /** @brief Resume execution of instrument script.
1065                 *
1066                 * Will be called to resume execution of a real-time instrument
1067                 * script event which has been suspended previously.
1068                 *
1069                 * Script execution might be suspended for various reasons. Usually
1070                 * a script will be suspended if the script called the built-in
1071                 * "wait()" function, but it might also be suspended automatically
1072                 * if the script took too much execution time in an audio fragment
1073                 * cycle. So in the latter case automatic suspension is performed in
1074                 * order to avoid harm for the sampler's overall real-time
1075                 * requirements.
1076                 *
1077                 * @param pChannel - engine channel this script is running for
1078                 * @param itScriptEvent - script execution that shall be resumed
1079                 */
1080                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1081                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1082    
1083                    // run script
1084                    VMExecStatus_t res = pScriptVM->exec(
1085                        pChannel->pScript->parserContext, &*itScriptEvent
1086                    );
1087    
1088                    // was the script suspended?
1089                    if (res & VM_EXEC_SUSPENDED) {
1090                        // in case the script was suspended, keep it on the allocated
1091                        // ScriptEvent list to be resume at the scheduled time in future,
1092                        // additionally insert it into a sorted time queue
1093                        pEventGenerator->scheduleAheadMicroSec(
1094                            pChannel->pScript->suspendedEvents, // scheduler queue
1095                            *itScriptEvent, // script event
1096                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1097                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1098                        );
1099                    } else { // script execution has finished without 'suspended' status ...
1100                        // if "polyphonic" variable data is passed from script's
1101                        // "note" event handler to its "release" event handler, then
1102                        // the script event must be kept and recycled for the later
1103                        // occuring "release" script event ...
1104                        if (handler && handler == pChannel->pScript->handlerNote &&
1105                            pChannel->pScript->handlerRelease &&
1106                            pChannel->pScript->handlerNote->isPolyphonic() &&
1107                            pChannel->pScript->handlerRelease->isPolyphonic())
1108                        {
1109                            const int key = itScriptEvent->cause.Param.Note.Key;
1110                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1111                        } else {
1112                            // ... otherwise if no polyphonic data is passed and
1113                            // script's execution has finished without suspension
1114                            // status, then free the script event for a new future
1115                            // script event to be triggered from start
1116                            pChannel->pScript->pEvents->free(itScriptEvent);
1117                        }
1118                    }
1119                }
1120    
1121                /**
1122               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1123               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1124               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1125               *  voice actually died.               *  voice actually died.
1126               *               *
1127               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1128               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1129               *  @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
1130               */               */
1131              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1132                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1133                      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"));
1134                      return -1;                      return -1;
# Line 678  namespace LinuxSampler { Line 1136  namespace LinuxSampler {
1136    
1137                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1138    
1139                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1140                        dmsg(1,("Event pool emtpy!\n"));
1141                        return -1;
1142                    }
1143    
1144                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1145                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1146                          return 0;                      return 0;
1147                      }                  }
1148    
1149                      // 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
1150                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1151                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1152                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1153                      int                       iChannelIndex;                  int                          iChannelIndex;
1154                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1155    
1156                      // select engine channel                  // select engine channel
1157                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1158                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1159                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1160                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1161                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1162                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1163                      }                  }
1164    
1165                      // 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
1166                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1167                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1168                          do {                      do {
1169                              ++itSelectedVoice;                          ++itSelectedVoice;
1170                          } 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
1171                    }
1172                    // did we find a 'stealable' voice?
1173                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1174                        // remember which voice we stole, so we can simply proceed on next voice stealing
1175                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1176                        // done
1177                        goto stealable_voice_found;
1178                    }
1179    
1180                    // get (next) oldest note
1181                    if (this->itLastStolenNoteGlobally) {
1182                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1183                             itNote; ++itNote)
1184                        {
1185                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1186                                // proceed iterating if voice was created in this audio fragment cycle
1187                                if (itSelectedVoice->IsStealable()) {
1188                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1189                                    this->itLastStolenNoteGlobally  = itNote;
1190                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1191                                    goto stealable_voice_found; // selection succeeded
1192                                }
1193                            }
1194                      }                      }
1195                    }
1196    
1197                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1198                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1199                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1200    
1201                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1202                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1203                          // 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();
1204                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1205                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1206                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1207                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1208                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1209                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1210                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1211                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1212                                itSelectedVoice = itNote->pActiveVoices->first();
1213                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1214                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1215                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1216                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1217                                  // 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
1218                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1219                                    this->itLastStolenNoteGlobally  = itNote;
1220                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1221                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1222                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1223                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1224                          }                          }
1225                          // get next engine channel                          ++iuiSelectedKey; // get next key on current engine channel
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
                         }  
                         #endif // CONFIG_DEVMODE  
1226                      }                      }
1227                        // get next engine channel
1228                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1229                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1230    
1231                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1232                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1233                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1234                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1235                            dmsg(1,("Exiting.\n"));
1236                            exit(-1);
1237                      }                      }
1238                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1239                    }
1240    
1241                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1242                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1243    
1244                      return 0; // success                  #if CONFIG_DEVMODE
1245                  }                  if (!itSelectedVoice->IsActive()) {
1246                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1247                      return -1;                      return -1;
1248                  }                  }
1249                    #endif // CONFIG_DEVMODE
1250    
1251                    // now kill the selected voice
1252                    itSelectedVoice->Kill(itNoteOnEvent);
1253    
1254                    --VoiceSpawnsLeft;
1255    
1256                    return 0; // success
1257              }              }
1258    
1259              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 792  namespace LinuxSampler { Line 1275  namespace LinuxSampler {
1275                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1276                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1277                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1278                            pEngineChannel->pScript =
1279                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1280                          instrumentChanged = true;                          instrumentChanged = true;
1281    
1282                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1283    
1284                            // the script's "init" event handler is only executed
1285                            // once (when the script is loaded or reloaded)
1286                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1287                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1288                                RTList<ScriptEvent>::Iterator itScriptEvent =
1289                                    pEngineChannel->pScript->pEvents->allocAppend();
1290    
1291                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1292                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1293                                itScriptEvent->handlers[1] = NULL;
1294                                itScriptEvent->currentHandler = 0;
1295                                itScriptEvent->executionSlices = 0;
1296                                itScriptEvent->ignoreAllWaitCalls = false;
1297                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1298    
1299                                /*VMExecStatus_t res = */ pScriptVM->exec(
1300                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
1301                                );
1302    
1303                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1304                            }
1305                      }                      }
1306                  }                  }
1307    
# Line 845  namespace LinuxSampler { Line 1352  namespace LinuxSampler {
1352                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1353                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1354                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1355                        
1356                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1357                          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);
1358                      if (itNewVoice) {                      if (itNewVoice) {
1359                            // usually there should already be a new Note object
1360                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1361                            if (!itNote) { // should not happen, but just to be sure ...
1362                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1363                                if (!noteID) {
1364                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1365                                    continue;
1366                                }
1367                                itNote = GetNotePool()->fromID(noteID);
1368                            }
1369                            // move voice from whereever it was, to the new note's list of active voices
1370                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1371                            // render audio of this new voice for the first time
1372                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1373                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1374                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 885  namespace LinuxSampler { Line 1406  namespace LinuxSampler {
1406                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1407    
1408                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1409                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1410                    pChannel->ClearEventListsOfCurrentFragment();
1411              }              }
1412    
1413              /**              /**
# Line 950  namespace LinuxSampler { Line 1472  namespace LinuxSampler {
1472                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1473                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1474                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1475                                      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));
1476                                      if (note < 128)                                      if (note < 128)
1477                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1478                                      break;                                      break;
# Line 958  namespace LinuxSampler { Line 1480  namespace LinuxSampler {
1480                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1481                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1482                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1483                                      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));
1484                                      if (note < 128)                                      if (note < 128)
1485                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1486                                      break;                                      break;
# Line 1111  namespace LinuxSampler { Line 1633  namespace LinuxSampler {
1633              /**              /**
1634               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1635               *               *
1636               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1637               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1638               */               */
1639              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1640                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1641                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1642    
                 //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;  
   
1643                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1644                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1645                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1646    
1647                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1648    
1649                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1650                    // programmatically spawned notes (Event::type_play_note). We have
1651                    // to distinguish between them, since certain processing below
1652                    // must only be done on real MIDI note-on events (i.e. for
1653                    // correctly updating which MIDI keys are currently pressed down).
1654                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1655    
1656                    if (isRealMIDINoteOnEvent)
1657                        pChannel->listeners.PreProcessNoteOn(key, vel);
1658    
1659                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1660                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1661                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1662                            pChannel->listeners.PostProcessNoteOn(key, vel);
1663                      return;                      return;
1664                  }                  }
1665                  #endif                  #endif
1666    
1667                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1668                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1669                            pChannel->listeners.PostProcessNoteOn(key, vel);
1670                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1671                  }                  }
1672    
# Line 1145  namespace LinuxSampler { Line 1674  namespace LinuxSampler {
1674                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1675    
1676                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1677                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1678                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1679                      if (itYoungestKey) {                      if (itYoungestKey) {
1680                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1153  namespace LinuxSampler { Line 1682  namespace LinuxSampler {
1682                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1683                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1684                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1685                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1686                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1687                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1688                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1689                                    }
1690                              }                              }
1691                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1692                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1693                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1694                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1695                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1696                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1697                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1698                                    }
1699                              }                              }
1700                          }                          }
1701                      }                      }
# Line 1169  namespace LinuxSampler { Line 1703  namespace LinuxSampler {
1703                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1704                  }                  }
1705    
1706                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1707                        pChannel->ProcessKeySwitchChange(key);
1708    
1709                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1710                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1711                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1712                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1713                    }
1714    
1715                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1716                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1717                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1718                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1719                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1720                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1721                      }                      }
1722                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1723                  }                  }
# Line 1191  namespace LinuxSampler { Line 1728  namespace LinuxSampler {
1728                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1729                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1730    
1731                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1732                        pChannel->PortamentoPos = (float) key;
1733    
1734                    //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?
1735                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1736                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1737                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1738                  }                  }
1739                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1740                    if (isRealMIDINoteOnEvent)
1741                        pChannel->listeners.PostProcessNoteOn(key, vel);
1742              }              }
1743    
1744              /**              /**
# Line 1222  namespace LinuxSampler { Line 1764  namespace LinuxSampler {
1764               *  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.
1765               *  due to completion of sample playback).               *  due to completion of sample playback).
1766               *               *
1767               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1768               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1769               */               */
1770              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1771                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1772    
                 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;  
   
1773                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1774                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1775                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1776    
1777                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1778    
1779                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1780                    // programmatically spawned notes (Event::type_stop_note). We have
1781                    // to distinguish between them, since certain processing below
1782                    // must only be done on real MIDI note-off events (i.e. for
1783                    // correctly updating which MIDI keys are currently pressed down),
1784                    // plus a stop-note event just releases voices of one particular
1785                    // note, whereas a note-off event releases all voices on a
1786                    // particular MIDI key instead.
1787                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1788    
1789                    if (isRealMIDINoteOffEvent)
1790                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1791    
1792                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1793                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1794                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1795                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1796                      return;                      return;
1797                  }                  }
1798                  #endif                  #endif
1799    
1800                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1801                        pKey->KeyPressed = false; // the MIDI key was now released
1802                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1803                    }
1804    
1805                  // move event to the key's own event list                  // move event to the key's own event list
1806                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1807    
1808                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1809                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1810    
1811                  // 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)
1812                  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
1813                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1814                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1815                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1816                          // 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
1817                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1818                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1819                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1820                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1821                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1822                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1823                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1824                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1825                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1826                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1827                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1828                                  // create a pseudo note on event                                      }
1829                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1830                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1831                                      // copy event                                      if (itPseudoNoteOnEvent) {
1832                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1833                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1834                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1835                                      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)
1836                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1837                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1838                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1839                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1840                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1841                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1842                                            }
1843                                            // if neither a voice was spawned or postponed then remove note on event from key again
1844                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1845                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1846    
1847                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1848                                  break; // done                                      break; // done
1849                                    }
1850                              }                              }
1851                          }                          }
1852                      }                          if (bOtherKeysPressed) {
1853                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1854                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1855                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1856                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1857                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1858                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1859                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1860                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1861                                        }
1862                                    }
1863                              }                              }
1864                          }                          } else pChannel->PortamentoPos = -1.0f;
1865                      } 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  
1866    
1867                      // 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
1868                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1869                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1870                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1871                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1872                        }
1873                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1874                        // This programmatically caused event is caused by a call to
1875                        // the built-in instrument script function note_off(). In
1876                        // contrast to a real MIDI note-off event the stop-note
1877                        // event just intends to release voices of one particular note.
1878                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1879                        if (pNote) { // the requested note is still alive ...
1880                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1881                        } else { // note is dead and gone ..
1882                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1883                            return; // prevent event to be removed a 2nd time below
1884                      }                      }
1885                  }                  }
1886    
# Line 1319  namespace LinuxSampler { Line 1888  namespace LinuxSampler {
1888                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1889                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1890    
1891                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1892                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1893                }
1894    
1895                /**
1896                 * Called on sustain pedal up events to check and if required,
1897                 * launch release trigger voices on the respective active key.
1898                 *
1899                 * @param pEngineChannel - engine channel on which this event occurred on
1900                 * @param itEvent - release trigger event (contains note number)
1901                 */
1902                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1903                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1904    
1905                    const int iKey = itEvent->Param.Note.Key;
1906                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1907    
1908                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1909    
1910                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1911                }
1912    
1913                /**
1914                 * Called on note-off and sustain pedal up events to check and if
1915                 * required, launch release trigger voices on the respective active
1916                 * key.
1917                 *
1918                 * @param pEngineChannel - engine channel on which this event occurred on
1919                 * @param itEvent - note off event / release trigger event
1920                 * @param pKey - key on which the release trigger voices shall be spawned
1921                 */
1922                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1923                    // spawn release triggered voice(s) if needed
1924                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1925                        // assign a new note to this release event
1926                        if (LaunchNewNote(pChannel, &*itEvent)) {
1927                            // allocate and trigger new release voice(s)
1928                            TriggerReleaseVoices(pChannel, itEvent);
1929                        }
1930                        pKey->ReleaseTrigger = false;
1931                    }
1932                }
1933    
1934                /**
1935                 * Called on "kill note" events, which currently only happens on
1936                 * built-in real-time instrument script function fade_out(). This
1937                 * method only fulfills one task: moving the even to the Note's own
1938                 * event list so that its voices can process the kill event sample
1939                 * accurately.
1940                 */
1941                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1942                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1943    
1944                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1945                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1946    
1947                    // move note kill event to its MIDI key
1948                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1949                    itEvent.moveToEndOf(pKey->pEvents);
1950                }
1951    
1952                /**
1953                 * Called on note synthesis parameter change events. These are
1954                 * internal events caused by calling built-in real-time instrument
1955                 * script functions like change_vol(), change_tune(), etc.
1956                 *
1957                 * This method performs two tasks:
1958                 *
1959                 * - It converts the event's relative values changes (Deltas) to
1960                 *   the respective final new synthesis parameter value (AbsValue),
1961                 *   for that particular moment of the event that is.
1962                 *
1963                 * - It moves the individual events to the Note's own event list
1964                 *   (or actually to the event list of the MIDI key), so that
1965                 *   voices can process those events sample accurately.
1966                 *
1967                 * @param pEngineChannel - engine channel on which this event occurred on
1968                 * @param itEvent - note synthesis parameter change event
1969                 */
1970                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1971                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1972    
1973                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1974                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1975    
1976                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1977    
1978                    switch (itEvent->Param.NoteSynthParam.Type) {
1979                        case Event::synth_param_volume:
1980                            if (relative)
1981                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1982                            else
1983                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1984                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1985                            break;
1986                        case Event::synth_param_volume_time:
1987                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1988                            break;
1989                        case Event::synth_param_pitch:
1990                            if (relative)
1991                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1992                            else
1993                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1994                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1995                            break;
1996                        case Event::synth_param_pitch_time:
1997                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1998                            break;
1999                        case Event::synth_param_pan:
2000                            if (relative) {
2001                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2002                            } else {
2003                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2004                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2005                            }
2006                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2007                            break;
2008                        case Event::synth_param_cutoff:
2009                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2010                            break;
2011                        case Event::synth_param_resonance:
2012                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2013                            break;
2014                        case Event::synth_param_attack:
2015                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2016                            break;
2017                        case Event::synth_param_decay:
2018                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2019                            break;
2020                        case Event::synth_param_release:
2021                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2022                            break;
2023                        case Event::synth_param_amp_lfo_depth:
2024                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2025                            break;
2026                        case Event::synth_param_amp_lfo_freq:
2027                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2028                            break;
2029                        case Event::synth_param_pitch_lfo_depth:
2030                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2031                            break;
2032                        case Event::synth_param_pitch_lfo_freq:
2033                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2034                            break;
2035                    }
2036    
2037                    // move note parameter event to its MIDI key
2038                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2039                    itEvent.moveToEndOf(pKey->pEvents);
2040              }              }
2041    
2042              /**              /**
2043               *  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
2044               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2045               */               */
2046              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2047                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2048    
2049                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1339  namespace LinuxSampler { Line 2056  namespace LinuxSampler {
2056                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2057                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2058                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2059                    itLastStolenNote           = NoteIterator();
2060                    itLastStolenNoteGlobally   = NoteIterator();
2061                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2062                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2063                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2064    
2065                    // reset all notes
2066                    pNotePool->clear();
2067                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2068                         itNote = pNotePool->allocAppend())
2069                    {
2070                        itNote->reset();
2071                    }
2072                    pNotePool->clear();
2073    
2074                  // reset all voices                  // reset all voices
2075                    pVoicePool->clear();
2076                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2077                      iterVoice->Reset();                      iterVoice->Reset();
2078                  }                  }
2079                  pVoicePool->clear();                  pVoicePool->clear();
2080    
2081                    // reset all engine channels
2082                    for (int i = 0; i < engineChannels.size(); i++) {
2083                        AbstractEngineChannel* pEngineChannel =
2084                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2085                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2086                    }
2087    
2088                  // reset disk thread                  // reset disk thread
2089                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2090    
# Line 1366  namespace LinuxSampler { Line 2102  namespace LinuxSampler {
2102               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2103               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2104               */               */
2105              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2106                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2107                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2108                  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 1377  namespace LinuxSampler { Line 2113  namespace LinuxSampler {
2113               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2114               *  (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).
2115               *               *
2116               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2117               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2118               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2119               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1401  namespace LinuxSampler { Line 2137  namespace LinuxSampler {
2137                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2138              ) = 0;              ) = 0;
2139    
2140              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2141    
2142              int InitNewVoice (              int InitNewVoice (
2143                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1420  namespace LinuxSampler { Line 2156  namespace LinuxSampler {
2156                      // launch the new voice                      // launch the new voice
2157                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2158                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2159                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2160                      }                      }
2161                      else { // on success                      else { // on success
2162                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1451  namespace LinuxSampler { Line 2187  namespace LinuxSampler {
2187    
2188                  return -1;                  return -1;
2189              }              }
2190                
2191                /**
2192                 * Checks whether scale tuning setting has been changed since last
2193                 * time this method was called, if yes, it recalculates the pitch
2194                 * for all active voices.
2195                 */
2196                void ProcessScaleTuningChange() {
2197                    const bool changed = ScaleTuningChanged.readAndReset();
2198                    if (!changed) return;
2199                    
2200                    for (int i = 0; i < engineChannels.size(); i++) {
2201                        EngineChannelBase<V, R, I>* channel =
2202                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2203                        channel->OnScaleTuningChanged();
2204                    }
2205                }
2206    
2207          private:          private:
2208                Pool< Note<V> >* pNotePool;
2209                Pool<note_id_t> noteIDPool;
2210              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2211              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2212              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2427  
changed lines
  Added in v.3188

  ViewVC Help
Powered by ViewVC