/[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 2162 by persson, Tue Feb 8 18:22:50 2011 UTC revision 3697 by schoenebeck, Sat Jan 4 12:09:45 2020 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-2011 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 174  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202                      PostProcess(engineChannels[i]);                      PostProcess(engineChannels[i]);
203                  }                  }
204    
205                    // Just for debugging: dump the amount of free Note objects to
206                    // the terminal (note due to the static variables being used,
207                    // this is currently just intended for debugging with only one
208                    // engine channel).
209                    #if (CONFIG_DEBUG_LEVEL >= 3)
210                    {
211                        static int slice = 0;
212                        static int noteCount = -1;
213                        if (slice++ % 10 == 0) {
214                            int n = pNotePool->countFreeElements();
215                            if (n != noteCount) {
216                                noteCount = n;
217                                dmsg(1,("[%d] free Note objects count = %d\n", slice / 10, n));
218                            }
219                        }
220                    }
221                    #endif
222    
223                  // empty the engine's event list for the next audio fragment                  // empty the engine's event list for the next audio fragment
224                  ClearEventLists();                  ClearEventLists();
# Line 205  namespace LinuxSampler { Line 250  namespace LinuxSampler {
250                  return 0;                  return 0;
251              }              }
252    
253              virtual int MaxVoices() { return pVoicePool->poolSize(); }              virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
254    
255              virtual void SetMaxVoices(int iVoices) throw (Exception) {              virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
256                  if (iVoices < 1)                  if (iVoices < 1)
257                      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");
258    
# Line 231  namespace LinuxSampler { Line 276  namespace LinuxSampler {
276                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
277                  }                  }
278    
279                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
280                  try {                  try {
281                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
282                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
283                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
284                  } catch (...) {                  } catch (...) {
285                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
286                  }                  }
287    
288                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
289                         iterVoice; iterVoice = pVoicePool->allocAppend())
290                    {
291                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
292                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
293                  }                  }
294                  pVoicePool->clear();                  pVoicePool->clear();
295    
296                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
297                         itNote = pNotePool->allocAppend())
298                    {
299                        itNote->init(pVoicePool, &noteIDPool);
300                    }
301                    pNotePool->clear();
302    
303                    PostSetMaxVoices(iVoices);
304                  ResumeAll();                  ResumeAll();
305              }              }
306                
307                /** Called after the new max number of voices is set and before resuming the engine. */
308                virtual void PostSetMaxVoices(int iVoices) { }
309    
310              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
311              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
312              virtual int  MaxDiskStreams() { return iMaxDiskStreams; }              virtual int  MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
313    
314              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
315                  if (iStreams < 0)                  if (iStreams < 0)
316                      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");
317    
# Line 265  namespace LinuxSampler { Line 326  namespace LinuxSampler {
326                  ResumeAll();                  ResumeAll();
327              }              }
328    
329              virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }              virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
330              virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }              virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
331              virtual InstrumentManager* GetInstrumentManager() { return &instruments; }              virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
332    
333              /**              /**
334               * Connect this engine instance with the given audio output device.               * Connect this engine instance with the given audio output device.
# Line 278  namespace LinuxSampler { Line 339  namespace LinuxSampler {
339               *               *
340               * @param pAudioOut - audio output device to connect to               * @param pAudioOut - audio output device to connect to
341               */               */
342              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
343                  // caution: don't ignore if connecting to the same device here,                  // caution: don't ignore if connecting to the same device here,
344                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!
345    
# Line 307  namespace LinuxSampler { Line 368  namespace LinuxSampler {
368                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
369                      // lower minimum release time                      // lower minimum release time
370                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
371                        pVoicePool->clear();
372                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
373                          iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
374                      }                      }
375                      pVoicePool->clear();                      pVoicePool->clear();
376                  }                  }
# Line 327  namespace LinuxSampler { Line 389  namespace LinuxSampler {
389                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
390                  }                  }
391    
392                    pVoicePool->clear();
393                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
394                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
395                      dmsg(3,("d"));                      dmsg(3,("d"));
396                  }                  }
397                  pVoicePool->clear();                  pVoicePool->clear();
398    
399                  // (re)create event generator                  // update event generator
400                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
401    
402                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
403                  pDiskThread->StartThread();                  pDiskThread->StartThread();
404                  dmsg(1,("OK\n"));                  dmsg(1,("OK\n"));
405    
406                    bool printEqInfo = true;
407                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
408                      if (!iterVoice->pDiskThread) {                      if (!iterVoice->pDiskThread) {
409                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
410                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
411                      }                      }
412                        
413                        iterVoice->CreateEq();
414                        
415                        if(printEqInfo) {
416                            iterVoice->PrintEqInfo();
417                            printEqInfo = false;
418                        }
419                  }                  }
420                  pVoicePool->clear();                  pVoicePool->clear();
421                                    
# Line 356  namespace LinuxSampler { Line 426  namespace LinuxSampler {
426                  pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);                  pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
427                  pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);                  pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
428              }              }
429            
430                // Implementattion for abstract method derived from Engine.
431                virtual void ReconnectAudioOutputDevice() OVERRIDE {
432                    SuspendAll();
433                    if (pAudioOutputDevice) Connect(pAudioOutputDevice);
434                    ResumeAll();
435                }
436    
437              /**              /**
438               * Similar to @c Disable() but this method additionally kills all voices               * Similar to @c Disable() but this method additionally kills all voices
# Line 409  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
487               */               */
488              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
489                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
490                  SuspendedRegionsMutex.Lock();                  {
491                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
492                  pPendingRegionSuspension = pRegion;                      SuspensionChangeOngoing.Set(true);
493                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionSuspension = pRegion;
494                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  }
496                    dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
497              }              }
498    
499              /**              /**
# Line 425  namespace LinuxSampler { Line 503  namespace LinuxSampler {
503               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
504               */               */
505              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
506                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
507                  SuspendedRegionsMutex.Lock();                  {
508                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
509                  pPendingRegionResumption = pRegion;                      SuspensionChangeOngoing.Set(true);
510                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionResumption = pRegion;
511                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
512                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  }
513                    dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
514              }              }
515    
516              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 534  namespace LinuxSampler { Line 613  namespace LinuxSampler {
613              }              }
614    
615              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
616              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
617                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
618                  return pRegionPool[index];                  return pRegionPool[index];
619              }              }
620    
621              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
622              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
623                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
624                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
625    
626              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
627    
# Line 553  namespace LinuxSampler { Line 634  namespace LinuxSampler {
634              public:              public:
635                  int PendingStreamDeletions;                  int PendingStreamDeletions;
636                  RR* pPendingRegionSuspension;                  RR* pPendingRegionSuspension;
637    
638                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
639                      PendingStreamDeletions = 0;                      PendingStreamDeletions = 0;
640                      this->pPendingRegionSuspension = pPendingRegionSuspension;                      this->pPendingRegionSuspension = pPendingRegionSuspension;
641                  }                  }
642    
643                  virtual bool Process(MidiKey* pMidiKey) {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
644                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
645                        VoiceIterator itVoice = itNote->pActiveVoices->first();
646                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
647                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
648    
649                      return true;                      return true;
650                  }                  }
651    
652                  virtual void Process(VoiceIterator& itVoice) {                  virtual void Process(VoiceIterator& itVoice) OVERRIDE {
653                      // request a notification from disk thread side for stream deletion                      // request a notification from disk thread side for stream deletion
654                      const Stream::Handle hStream = itVoice->KillImmediately(true);                      const Stream::Handle hStream = itVoice->KillImmediately(true);
655                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
# Line 582  namespace LinuxSampler { Line 665  namespace LinuxSampler {
665    
666              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
667              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
668                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
669              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
670              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
671              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
672                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
673              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
674              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
675              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
676              int iMaxDiskStreams;              int iMaxDiskStreams;
677    
678                NoteBase* NoteByID(note_id_t id) OVERRIDE {
679                    NoteIterator itNote = GetNotePool()->fromID(id);
680                    if (!itNote) return NULL;
681                    return &*itNote;
682                }
683    
684                /**
685                 * Gets a new @c Note object from the note pool, initializes it
686                 * appropriately, links it with requested parent note (if
687                 * requested), moves it to the appropriate key's list of active
688                 * notes it, and sticks the new note's unique ID to the
689                 * passed @a pNoteOnEvent.
690                 *
691                 * @param pEngineChannel - engine channel on which this event happened
692                 * @param pNoteOnEvent - event which caused this
693                 * @returns new note's unique ID (or zero on error)
694                 */
695                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
696                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
697                    Pool< Note<V> >* pNotePool = GetNotePool();
698    
699                    if (pNotePool->poolIsEmpty()) {
700                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
701                        return 0; // error
702                    }
703    
704                    // create a new note (for new voices to be assigned to)
705                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
706                    NoteIterator itNewNote = pNotePool->allocAppend();
707                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
708    
709                    // remember the engine's time when this note was triggered exactly
710                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
711    
712                    // usually the new note (and its subsequent voices) will be
713                    // allocated on the key provided by the event's note number,
714                    // however if this new note is requested not to be a regular
715                    // note, but rather a child note, then this new note will be
716                    // allocated on the parent note's key instead in order to
717                    // release the child note simultaniously with its parent note
718                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
719    
720                    // in case this new note was requested to be a child note,
721                    // then retrieve its parent note and link them with each other
722                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
723                    if (parentNoteID) {
724                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
725                        if (itParentNote) {
726                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
727                            if (itChildNoteID) {
728                                // link parent and child note with each other
729                                *itChildNoteID = newNoteID;
730                                itNewNote->parentNoteID = parentNoteID;
731                                itNewNote->hostKey = itParentNote->hostKey;
732                            } else {    
733                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
734                                pNotePool->free(itNewNote);
735                                return 0; // error
736                            }
737                        } else {
738                            // the parent note was apparently released already, so
739                            // free the new note again and inform caller that it
740                            // should drop the event
741                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
742                            pNotePool->free(itNewNote);
743                            return 0; // error
744                        }
745                    }
746    
747                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
748    
749                    // copy event which caused this note
750                    itNewNote->cause = *itNoteOnEvent;
751                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
752                    if (!itNewNote->eventID) {
753                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
754                    }
755    
756                    // move new note to its host key
757                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
758                    itNewNote.moveToEndOf(pKey->pActiveNotes);
759                    pChannel->markKeyAsActive(pKey);
760    
761                    // assign unique note ID of this new note to the original note on event
762                    itNoteOnEvent->Param.Note.ID = newNoteID;
763    
764                    return newNoteID; // success
765                }
766    
767              /**              /**
768               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
769               * engine channel.               * engine channel.
# Line 605  namespace LinuxSampler { Line 779  namespace LinuxSampler {
779                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
780                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
781    
782                  // process events                  // if a valid real-time instrument script is loaded, pre-process
783                    // the event list by running the script now, since the script
784                    // might filter events or add new ones for this cycle
785                    if (pChannel->pScript) {
786                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
787    
788                        // resume suspended script executions been scheduled for
789                        // this audio fragment cycle (which were suspended in a
790                        // previous audio fragment cycle)
791                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
792    
793                        // spawn new script executions for the new MIDI events of
794                        // this audio fragment cycle
795                        //
796                        // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
797                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
798                            end = pChannel->pEvents->end(); itEvent != end; )
799                        {
800                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
801                            RTList<Event>::Iterator itNext = itEvent;
802                            ++itNext;
803    
804                            switch (itEvent->Type) {
805                                case Event::type_note_on:
806                                    if (pChannel->pScript->handlerNote)
807                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
808                                    break;
809                                case Event::type_note_off:
810                                    if (pChannel->pScript->handlerRelease)
811                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
812                                    break;
813                                case Event::type_control_change:
814                                case Event::type_channel_pressure:
815                                case Event::type_pitchbend:
816                                    if (pChannel->pScript->handlerController)
817                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
818                                    break;
819                                case Event::type_note_pressure:
820                                    //TODO: ...
821                                    break;
822    
823                                case Event::type_sysex:
824                                    //TODO: ...
825                                    break;
826    
827                                case Event::type_cancel_release_key:
828                                case Event::type_release_key:
829                                case Event::type_release_note:
830                                case Event::type_play_note:
831                                case Event::type_stop_note:
832                                case Event::type_kill_note:
833                                case Event::type_note_synth_param:
834                                    break; // noop
835                            }
836    
837                            // see HACK comment above
838                            itEvent = itNext;
839                        }
840    
841                        // this has to be run again, since the newly spawned scripts
842                        // above may have cause suspended scripts that must be
843                        // resumed within this same audio fragment cycle
844                        //
845                        // FIXME: see FIXME comment above
846                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
847                    }
848    
849                    // if there are any delayed events scheduled for the current
850                    // audio fragment cycle, then move and sort them into the main
851                    // event list
852                    if (!pChannel->delayedEvents.queue.isEmpty()) {
853                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
854                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
855                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
856                        while (true) {
857                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
858                                pEventGenerator->popNextScheduledEvent(
859                                    pChannel->delayedEvents.queue,
860                                    pChannel->delayedEvents.schedulerNodes,
861                                    fragmentEndTime
862                                );
863                            if (!itDelayedEventNode) break;
864                            // get the actual delayed event object and free the used scheduler node
865                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
866                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
867                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
868                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
869                                continue;
870                            }
871                            // skip all events on main event list which have a time
872                            // before (or equal to) the delayed event to be inserted
873                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
874                                 ++itEvent);
875                            // now move delayed event from delayedEvents.pList to
876                            // the current position on the main event list
877                            itEvent = itDelayedEvent.moveBefore(itEvent);
878                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
879                        }
880                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
881                    }
882    
883                    // now process all events regularly
884                  {                  {
885                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
886                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
887                      for (; itEvent != end; ++itEvent) {                      for (; itEvent != end; ++itEvent) {
888                            bool bIsCC = false; // just for resetting RPN/NRPN below
889                          switch (itEvent->Type) {                          switch (itEvent->Type) {
890                              case Event::type_note_on:                              case Event::type_note_on:
891                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
892                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
893                                  break;                                  break;
894                                case Event::type_play_note:
895                                    dmsg(5,("Engine: Play Note received\n"));
896                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
897                                    break;
898                              case Event::type_note_off:                              case Event::type_note_off:
899                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
900                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
901                                  break;                                  break;
902                                case Event::type_stop_note:
903                                    dmsg(5,("Engine: Stop Note received\n"));
904                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
905                                    break;
906                                case Event::type_kill_note:
907                                    dmsg(5,("Engine: Kill Note received\n"));
908                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
909                                    break;
910                              case Event::type_control_change:                              case Event::type_control_change:
911                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
912                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
913                                    bIsCC = true;
914                                    break;
915                                case Event::type_rpn: // this can only be reached here by an instrument script having called set_rpn()
916                                    dmsg(5,("Engine: MIDI RPN received\n"));
917                                    ProcessHardcodedRpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
918                                    bIsCC = true;
919                                    break;
920                                case Event::type_nrpn: // this can only be reached here by an instrument script having called set_nrpn()
921                                    dmsg(5,("Engine: MIDI NRPN received\n"));
922                                    ProcessHardcodedNrpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
923                                    bIsCC = true;
924                                    break;
925                                case Event::type_channel_pressure:
926                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
927                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
928                                    break;
929                                case Event::type_note_pressure:
930                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
931                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
932                                  break;                                  break;
933                              case Event::type_pitchbend:                              case Event::type_pitchbend:
934                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
935                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
936                                  break;                                  break;
937                                case Event::type_note_synth_param:
938                                    dmsg(5,("Engine: Note Synth Param received\n"));
939                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
940                                    break;
941                                case Event::type_sysex:
942                                    break; // TODO ...
943    
944                                case Event::type_cancel_release_key:
945                                case Event::type_release_key:
946                                case Event::type_release_note:
947                                    break; // noop
948                            }
949                            // reset cached RPN/NRPN parameter number and data in
950                            // case this event was not a control change event
951                            if (!bIsCC) {
952                                if (pChannel->GetMidiRpnParameter() >= 0)
953                                    pChannel->ResetMidiRpnParameter();
954                                if (pChannel->GetMidiNrpnParameter() >= 0)
955                                    pChannel->ResetMidiNrpnParameter();
956                          }                          }
957                      }                      }
958                  }                  }
# Line 634  namespace LinuxSampler { Line 960  namespace LinuxSampler {
960                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
961                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
962                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
963                    itLastStolenNote          = NoteIterator();
964                    itLastStolenNoteGlobally  = NoteIterator();
965                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
966                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
967                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
968              }              }
969    
970              /**              /**
971                 * Run all suspended script execution instances which are scheduled
972                 * to be resumed for the current audio fragment cycle.
973                 *
974                 * @param pChannel - engine channel on which suspended events occurred
975                 */
976                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
977                    while (true) {
978                        RTList<ScriptEvent>::Iterator itEvent =
979                            pEventGenerator->popNextScheduledScriptEvent(
980                                pChannel->pScript->suspendedEvents,
981                                *pChannel->pScript->pEvents, fragmentEndTime
982                            );
983                        if (!itEvent) break;
984                        ResumeScriptEvent(pChannel, itEvent);
985                    }
986                }
987    
988                /** @brief Call instrument script's event handler for this event.
989                 *
990                 * Causes a new execution instance of the currently loaded real-time
991                 * instrument script's event handler (callback) to be spawned for
992                 * the given MIDI event.
993                 *
994                 * @param pChannel - engine channel on which the MIDI event occurred
995                 * @param itEvent - MIDI event that causes this new script execution
996                 * @param pEventHandler - script's event handler to be executed
997                 */
998                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
999                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
1000                    // check if polyphonic data is passed from "note" to "release"
1001                    // script event handlers
1002                    if (pEventHandler == pChannel->pScript->handlerRelease &&
1003                        pChannel->pScript->handlerNote &&
1004                        pChannel->pScript->handlerNote->isPolyphonic() &&
1005                        pChannel->pScript->handlerRelease->isPolyphonic() &&
1006                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
1007                    {
1008                        // polyphonic variable data is used/passed from "note" to
1009                        // "release" script callback, so we have to recycle the
1010                        // original "note on" script event(s)
1011                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
1012                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
1013                        for (; it != end; ++it) {
1014                            ProcessScriptEvent(
1015                                pChannel, itEvent, pEventHandler, it
1016                            );
1017                        }
1018                    } else {
1019                        // no polyphonic data is used/passed from "note" to
1020                        // "release" script callback, so just use a new fresh
1021                        // script event object
1022                        RTList<ScriptEvent>::Iterator itScriptEvent =
1023                            pChannel->pScript->pEvents->allocAppend();
1024                        // if event handler uses polyphonic variables, reset them
1025                        // to zero values before starting to execute the handler
1026                        if (pEventHandler->isPolyphonic())
1027                            itScriptEvent->execCtx->resetPolyphonicData();
1028                        ProcessScriptEvent(
1029                            pChannel, itEvent, pEventHandler, itScriptEvent
1030                        );
1031                    }
1032                }
1033    
1034                /** @brief Spawn new execution instance of an instrument script handler.
1035                 *
1036                 * Will be called to initiate a new execution of a real-time
1037                 * instrument script event right from the start of the script's
1038                 * respective handler. If script execution did not complete after
1039                 * calling this method, the respective script exeuction is then
1040                 * suspended and a call to ResumeScriptEvent() will be used next
1041                 * time to continue its execution.
1042                 *
1043                 * @param pChannel - engine channel this script is running for
1044                 * @param itEvent - event which caused execution of this script
1045                 *                  event handler
1046                 * @param pEventHandler - VM representation of event handler to be
1047                 *                        executed
1048                 * @param itScriptEvent - script event that shall be processed
1049                 */
1050                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1051                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1052    
1053                    // fill the list of script handlers to be executed by this event
1054                    int i = 0;
1055                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1056                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1057    
1058                    // initialize/reset other members
1059                    itScriptEvent->cause = *itEvent;
1060                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1061                    itScriptEvent->currentHandler = 0;
1062                    itScriptEvent->executionSlices = 0;
1063                    itScriptEvent->ignoreAllWaitCalls = false;
1064                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1065                    itScriptEvent->parentHandlerID = 0;
1066                    itScriptEvent->childHandlerID[0] = 0;
1067                    itScriptEvent->autoAbortByParent = false;
1068                    itScriptEvent->forkIndex = 0;
1069                    // this is the native representation of the $EVENT_ID script variable
1070                    itScriptEvent->id =
1071                        (itEvent->Type == Event::type_note_on)
1072                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1073                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1074    
1075                    // run script handler(s)
1076                    VMExecStatus_t res = pScriptVM->exec(
1077                        pChannel->pScript->parserContext, &*itScriptEvent
1078                    );
1079    
1080                    // was the script suspended?
1081                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1082                        // in case the script was suspended, keep it on the allocated
1083                        // ScriptEvent list to be resume at the scheduled time in future,
1084                        // additionally insert it into a sorted time queue
1085                        pEventGenerator->scheduleAheadMicroSec(
1086                            pChannel->pScript->suspendedEvents, // scheduler queue
1087                            *itScriptEvent, // script event
1088                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1089                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1090                        );
1091                    } else { // script execution has finished without 'suspended' status ...
1092                        // if "polyphonic" variable data is passed from script's
1093                        // "note" event handler to its "release" event handler, then
1094                        // the script event must be kept and recycled for the later
1095                        // occuring "release" script event ...
1096                        if (pEventHandler == pChannel->pScript->handlerNote &&
1097                            pChannel->pScript->handlerRelease &&
1098                            pChannel->pScript->handlerNote->isPolyphonic() &&
1099                            pChannel->pScript->handlerRelease->isPolyphonic())
1100                        {
1101                            const int key = itEvent->Param.Note.Key;
1102                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1103                        } else {
1104                            // ... otherwise if no polyphonic data is passed and
1105                            // script's execution has finished without suspension
1106                            // status, then free the script event for a new future
1107                            // script event to be triggered from start
1108                            pChannel->pScript->pEvents->free(itScriptEvent);
1109                        }
1110                    }
1111                }
1112    
1113                /** @brief Resume execution of instrument script.
1114                 *
1115                 * Will be called to resume execution of a real-time instrument
1116                 * script event which has been suspended previously.
1117                 *
1118                 * Script execution might be suspended for various reasons. Usually
1119                 * a script will be suspended if the script called the built-in
1120                 * "wait()" function, but it might also be suspended automatically
1121                 * if the script took too much execution time in an audio fragment
1122                 * cycle. So in the latter case automatic suspension is performed in
1123                 * order to avoid harm for the sampler's overall real-time
1124                 * requirements.
1125                 *
1126                 * @param pChannel - engine channel this script is running for
1127                 * @param itScriptEvent - script execution that shall be resumed
1128                 */
1129                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1130                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1131    
1132                    // run script
1133                    VMExecStatus_t res = pScriptVM->exec(
1134                        pChannel->pScript->parserContext, &*itScriptEvent
1135                    );
1136    
1137                    // was the script suspended?
1138                    if (res & VM_EXEC_SUSPENDED) {
1139                        // in case the script was suspended, keep it on the allocated
1140                        // ScriptEvent list to be resume at the scheduled time in future,
1141                        // additionally insert it into a sorted time queue
1142                        pEventGenerator->scheduleAheadMicroSec(
1143                            pChannel->pScript->suspendedEvents, // scheduler queue
1144                            *itScriptEvent, // script event
1145                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1146                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1147                        );
1148                    } else { // script execution has finished without 'suspended' status ...
1149                        // if "polyphonic" variable data is passed from script's
1150                        // "note" event handler to its "release" event handler, then
1151                        // the script event must be kept and recycled for the later
1152                        // occuring "release" script event ...
1153                        if (handler && handler == pChannel->pScript->handlerNote &&
1154                            pChannel->pScript->handlerRelease &&
1155                            pChannel->pScript->handlerNote->isPolyphonic() &&
1156                            pChannel->pScript->handlerRelease->isPolyphonic())
1157                        {
1158                            const int key = itScriptEvent->cause.Param.Note.Key;
1159                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1160                        } else {
1161                            // ... otherwise if no polyphonic data is passed and
1162                            // script's execution has finished without suspension
1163                            // status, then free the script event for a new future
1164                            // script event to be triggered from start
1165                            pChannel->pScript->pEvents->free(itScriptEvent);
1166                        }
1167                    }
1168                }
1169    
1170                /**
1171               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1172               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1173               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1174               *  voice actually died.               *  voice actually died.
1175               *               *
1176               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1177               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1178               *  @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
1179               */               */
1180              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1181                    dmsg(3,("StealVoice()\n"));
1182                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1183                      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"));
1184                      return -1;                      return -1;
# Line 657  namespace LinuxSampler { Line 1186  namespace LinuxSampler {
1186    
1187                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1188    
1189                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1190                        dmsg(1,("Event pool emtpy!\n"));
1191                        return -1;
1192                    }
1193    
1194                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1195                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1196                          return 0;                      return 0;
1197                      }                  }
1198    
1199                      // 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
1200                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1201                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1202                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1203                      int                       iChannelIndex;                  int                          iChannelIndex;
1204                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
   
                     // select engine channel  
                     if (pLastStolenChannel) {  
                         pSelectedChannel = pLastStolenChannel;  
                         iChannelIndex    = pSelectedChannel->iEngineIndexSelf;  
                     } else { // pick the engine channel followed by this engine channel  
                         iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
                     }  
   
                     // if we already stole in this fragment, try to proceed on same key  
                     if (this->itLastStolenVoiceGlobally) {  
                         itSelectedVoice = this->itLastStolenVoiceGlobally;  
                         do {  
                             ++itSelectedVoice;  
                         } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle  
                     }  
1205    
1206                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1207                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = NULL; // to detect endless loop
1208                      #endif // CONFIG_DEVMODE                  #endif
1209    
1210                    // select engine channel
1211                    if (pLastStolenChannel) {
1212                        pSelectedChannel = pLastStolenChannel;
1213                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1214                    } else { // pick the engine channel followed by this engine channel
1215                        iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1216                        pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1217                    }
1218    
1219                    // if we already stole in this fragment, try to proceed on same note
1220                    if (this->itLastStolenVoiceGlobally) {
1221                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1222                        do {
1223                            ++itSelectedVoice;
1224                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1225                    }
1226                    // did we find a 'stealable' voice?
1227                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1228                        // remember which voice we stole, so we can simply proceed on next voice stealing
1229                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1230                        // done
1231                        goto stealable_voice_found;
1232                    }
1233    
1234                    // get (next) oldest note
1235                    if (this->itLastStolenNoteGlobally) {
1236                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1237                             itNote; ++itNote)
1238                        {
1239                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1240                                // proceed iterating if voice was created in this audio fragment cycle
1241                                if (itSelectedVoice->IsStealable()) {
1242                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1243                                    this->itLastStolenNoteGlobally  = itNote;
1244                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1245                                    goto stealable_voice_found; // selection succeeded
1246                                }
1247                            }
1248                        }
1249                    }
1250    
1251                      // did we find a 'stealable' voice?                  #if CONFIG_DEVMODE
1252                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                  pBegin = pSelectedChannel; // to detect endless loop
1253                          // remember which voice we stole, so we can simply proceed on next voice stealing                  #endif // CONFIG_DEVMODE
1254                          this->itLastStolenVoiceGlobally = itSelectedVoice;  
1255                      } else while (true) { // iterate through engine channels                  while (true) { // iterate through engine channels                        
1256                          // get (next) oldest key                      // get (next) oldest key
1257                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1258                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1259                          while (iuiSelectedKey) {                      while (iuiSelectedKey) {
1260                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1261                              itSelectedVoice = pSelectedKey->pActiveVoices->first();  
1262                            for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1263                                 itNotesEnd = pSelectedKey->pActiveNotes->end();
1264                                 itNote != itNotesEnd; ++itNote)
1265                            {
1266                                itSelectedVoice = itNote->pActiveVoices->first();
1267                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1268                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1269                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1270                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1271                                  // 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
1272                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1273                                    this->itLastStolenNoteGlobally  = itNote;
1274                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1275                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1276                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1277                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1278                          }                          }
1279                          // 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  
1280                      }                      }
1281                        // get next engine channel
1282                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1283                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1284    
1285                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1286                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1287                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1288                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1289                            dmsg(1,("Exiting.\n"));
1290                            exit(-1);
1291                      }                      }
1292                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1293                    }
1294    
1295                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1296                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1297    
1298                      return 0; // success                  #if CONFIG_DEVMODE
1299                  }                  if (!itSelectedVoice->IsActive()) {
1300                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1301                      return -1;                      return -1;
1302                  }                  }
1303                    #endif // CONFIG_DEVMODE
1304    
1305                    // now kill the selected voice
1306                    itSelectedVoice->Kill(itNoteOnEvent);
1307    
1308                    --VoiceSpawnsLeft;
1309    
1310                    return 0; // success
1311              }              }
1312    
1313              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 771  namespace LinuxSampler { Line 1329  namespace LinuxSampler {
1329                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1330                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1331                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1332                            pEngineChannel->pScript =
1333                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1334                          instrumentChanged = true;                          instrumentChanged = true;
1335    
1336                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1337    
1338                            // the script's "init" event handler is only executed
1339                            // once (when the script is loaded or reloaded)
1340                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1341                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1342                                RTList<ScriptEvent>::Iterator itScriptEvent =
1343                                    pEngineChannel->pScript->pEvents->allocAppend();
1344    
1345                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1346                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1347                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1348                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1349                                itScriptEvent->id = 0;
1350                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1351                                itScriptEvent->handlers[1] = NULL;
1352                                itScriptEvent->currentHandler = 0;
1353                                itScriptEvent->executionSlices = 0;
1354                                itScriptEvent->ignoreAllWaitCalls = false;
1355                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1356                                itScriptEvent->parentHandlerID = 0;
1357                                itScriptEvent->childHandlerID[0] = 0;
1358                                itScriptEvent->autoAbortByParent = false;
1359                                itScriptEvent->forkIndex = 0;
1360    
1361                                VMExecStatus_t res;
1362                                size_t instructionsCount = 0;
1363                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1364                                bool bWarningShown = false;
1365                                do {
1366                                    res = pScriptVM->exec(
1367                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1368                                    );
1369                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1370                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1371                                        bWarningShown = true;
1372                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1373                                    }
1374                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1375    
1376                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1377                            }
1378                      }                      }
1379                  }                  }
1380    
# Line 824  namespace LinuxSampler { Line 1425  namespace LinuxSampler {
1425                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1426                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1427                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1428                        
1429                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1430                          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);
1431                      if (itNewVoice) {                      if (itNewVoice) {
1432                            // usually there should already be a new Note object
1433                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1434                            if (!itNote) { // should not happen, but just to be sure ...
1435                                dmsg(2,("Engine: No Note object for stolen voice!\n"));
1436                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1437                                if (!noteID) {
1438                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1439                                    continue;
1440                                }
1441                                itNote = GetNotePool()->fromID(noteID);
1442                            }
1443                            // move voice from whereever it was, to the new note's list of active voices
1444                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1445                            // render audio of this new voice for the first time
1446                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1447                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1448                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 861  namespace LinuxSampler { Line 1477  namespace LinuxSampler {
1477              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1478                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1479                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1480                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1481    
1482                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1483                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1484                    pChannel->ClearEventListsOfCurrentFragment();
1485              }              }
1486    
1487              /**              /**
# Line 882  namespace LinuxSampler { Line 1499  namespace LinuxSampler {
1499                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1500                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1501    
1502                    // will be set to true if this CC event has anything to do with RPN/NRPN
1503                    bool bIsRpn = false, bIsNrpn = false;
1504    
1505                  switch (itControlChangeEvent->Param.CC.Controller) {                  switch (itControlChangeEvent->Param.CC.Controller) {
1506                      case 5: { // portamento time                      case 5: { // portamento time
1507                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1508                          break;                          break;
1509                      }                      }
1510                      case 6: { // data entry (currently only used for RPN and NRPN controllers)                      case 6: { // data entry (MSB)
1511                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));                          //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1512                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...                          if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1513                              dmsg(4,("Guess it's an RPN ...\n"));                              pChannel->SetMidiRpnDataMsb(
1514                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                                  itControlChangeEvent->Param.CC.Value
1515                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                              );
1516                                  // limit to +- two octaves for now                              bIsRpn = true;
1517                                  transpose = RTMath::Min(transpose,  24);  
1518                                  transpose = RTMath::Max(transpose, -24);                              // look-ahead: if next MIDI event is data entry LSB,
1519                                  pChannel->GlobalTranspose = transpose;                              // then skip this event here for now (to avoid double
1520                                  // workaround, so we won't have hanging notes                              // handling of what's supposed to be one RPN event)
1521                                  pChannel->ReleaseAllVoices(itControlChangeEvent);                              if (isNextEventCCNr(itControlChangeEvent, 38))
1522                              }                                  break;
1523                              // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data  
1524                              pChannel->ResetMidiRpnController();                              int ch = itControlChangeEvent->Param.CC.Channel;
1525                          } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...                              int param = pChannel->GetMidiRpnParameter();
1526                              dmsg(4,("Guess it's an NRPN ...\n"));                              int value = pChannel->GetMidiRpnData();
1527                              const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;  
1528                              const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;                              // transform event type: CC event -> RPN event
1529                              dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));                              itControlChangeEvent->Type = Event::type_rpn;
1530                              switch (NrpnCtrlMSB) {                              itControlChangeEvent->Param.RPN.Channel = ch;
1531                                  case 0x1a: { // volume level of note (Roland GS NRPN)                              itControlChangeEvent->Param.RPN.Parameter = param;
1532                                      const uint note = NrpnCtrlLSB;                              itControlChangeEvent->Param.RPN.Value = value;
1533                                      const uint vol  = itControlChangeEvent->Param.CC.Value;  
1534                                      dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));                              // if there's a RPN script handler, run it ...
1535                                      if (note < 128 && vol < 128)                              if (pChannel->pScript->handlerRpn) {
1536                                          pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];                                  const event_id_t eventID =
1537                                      break;                                      pEventPool->getID(itControlChangeEvent);
1538                                  }                                  // run the RPN script handler
1539                                  case 0x1c: { // panpot of note (Roland GS NRPN)                                  ProcessEventByScript(
1540                                      const uint note = NrpnCtrlLSB;                                      pChannel, itControlChangeEvent,
1541                                      const uint pan  = itControlChangeEvent->Param.CC.Value;                                      pChannel->pScript->handlerRpn
1542                                      dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));                                  );
1543                                      if (note < 128 && pan < 128) {                                  // if RPN event was dropped by script, abort
1544                                          pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];                                  // here to avoid hard coded RPN processing below
1545                                          pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];                                  if (!pEventPool->fromID(eventID))
                                     }  
                                     break;  
                                 }  
                                 case 0x1d: { // reverb send of note (Roland GS NRPN)  
                                     const uint note = NrpnCtrlLSB;  
                                     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;  
                                     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));  
                                     if (note < 128)  
                                         pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;  
1546                                      break;                                      break;
1547                                  }                              }
1548                                  case 0x1e: { // chorus send of note (Roland GS NRPN)  
1549                                      const uint note = NrpnCtrlLSB;                              // do the actual (hard-coded) RPN value change processing
1550                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                              ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1551                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));  
1552                                      if (note < 128)                          } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1553                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                              pChannel->SetMidiNrpnDataMsb(
1554                                    itControlChangeEvent->Param.CC.Value
1555                                );
1556                                bIsNrpn = true;
1557    
1558                                // look-ahead: if next MIDI event is data entry LSB,
1559                                // then skip this event here for now (to avoid double
1560                                // handling of what's supposed to be one NRPN event)
1561                                if (isNextEventCCNr(itControlChangeEvent, 38))
1562                                    break;
1563    
1564                                int ch = itControlChangeEvent->Param.CC.Channel;
1565                                int param = pChannel->GetMidiNrpnParameter();
1566                                int value = pChannel->GetMidiNrpnData();
1567    
1568                                // transform event type: CC event -> NRPN event
1569                                itControlChangeEvent->Type = Event::type_nrpn;
1570                                itControlChangeEvent->Param.NRPN.Channel = ch;
1571                                itControlChangeEvent->Param.NRPN.Parameter = param;
1572                                itControlChangeEvent->Param.NRPN.Value = value;
1573    
1574                                // if there's a NRPN script handler, run it ...
1575                                if (pChannel->pScript->handlerNrpn) {
1576                                    const event_id_t eventID =
1577                                        pEventPool->getID(itControlChangeEvent);
1578                                    // run the NRPN script handler
1579                                    ProcessEventByScript(
1580                                        pChannel, itControlChangeEvent,
1581                                        pChannel->pScript->handlerNrpn
1582                                    );
1583                                    // if NRPN event was dropped by script, abort
1584                                    // here to avoid hard coded NRPN processing below
1585                                    if (!pEventPool->fromID(eventID))
1586                                      break;                                      break;
                                 }  
1587                              }                              }
1588                              // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data  
1589                              pChannel->ResetMidiNrpnController();                              // do the actual (hard-coded) NRPN value change processing
1590                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1591                          }                          }
1592                          break;                          break;
1593                      }                      }
# Line 956  namespace LinuxSampler { Line 1599  namespace LinuxSampler {
1599                      }                      }
1600                      case 10: { // panpot                      case 10: { // panpot
1601                          //TODO: not sample accurate yet                          //TODO: not sample accurate yet
                         pChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];  
                         pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];  
1602                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1603                          break;                          break;
1604                      }                      }
1605                        case 38: { // data entry (LSB)
1606                            //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1607                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1608                                pChannel->SetMidiRpnDataLsb(
1609                                    itControlChangeEvent->Param.CC.Value
1610                                );
1611                                bIsRpn = true;
1612    
1613                                int ch = itControlChangeEvent->Param.CC.Channel;
1614                                int param = pChannel->GetMidiRpnParameter();
1615                                int value = pChannel->GetMidiRpnData();
1616    
1617                                // transform event type: CC event -> RPN event
1618                                itControlChangeEvent->Type = Event::type_rpn;
1619                                itControlChangeEvent->Param.RPN.Channel = ch;
1620                                itControlChangeEvent->Param.RPN.Parameter = param;
1621                                itControlChangeEvent->Param.RPN.Value = value;
1622    
1623                                // if there's a RPN script handler, run it ...
1624                                if (pChannel->pScript->handlerRpn) {
1625                                    const event_id_t eventID =
1626                                        pEventPool->getID(itControlChangeEvent);
1627                                    // run the RPN script handler
1628                                    ProcessEventByScript(
1629                                        pChannel, itControlChangeEvent,
1630                                        pChannel->pScript->handlerRpn
1631                                    );
1632                                    // if RPN event was dropped by script, abort
1633                                    // here to avoid hard coded RPN processing below
1634                                    if (!pEventPool->fromID(eventID))
1635                                        break;
1636                                }
1637    
1638                                // do the actual (hard-coded) RPN value change processing
1639                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1640    
1641                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1642                                pChannel->SetMidiNrpnDataLsb(
1643                                    itControlChangeEvent->Param.CC.Value
1644                                );
1645                                bIsNrpn = true;
1646    
1647                                int ch = itControlChangeEvent->Param.CC.Channel;
1648                                int param = pChannel->GetMidiNrpnParameter();
1649                                int value = pChannel->GetMidiNrpnData();
1650    
1651                                // transform event type: CC event -> NRPN event
1652                                itControlChangeEvent->Type = Event::type_nrpn;
1653                                itControlChangeEvent->Param.NRPN.Channel = ch;
1654                                itControlChangeEvent->Param.NRPN.Parameter = param;
1655                                itControlChangeEvent->Param.NRPN.Value = value;
1656    
1657                                // if there's a NRPN script handler, run it ...
1658                                if (pChannel->pScript->handlerNrpn) {
1659                                    const event_id_t eventID =
1660                                        pEventPool->getID(itControlChangeEvent);
1661                                    // run the NRPN script handler
1662                                    ProcessEventByScript(
1663                                        pChannel, itControlChangeEvent,
1664                                        pChannel->pScript->handlerNrpn
1665                                    );
1666                                    // if NRPN event was dropped by script, abort
1667                                    // here to avoid hard coded NRPN processing below
1668                                    if (!pEventPool->fromID(eventID))
1669                                        break;
1670                                }
1671    
1672                                // do the actual (hard-coded) NRPN value change processing
1673                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1674                            }
1675                            break;
1676                        }
1677                      case 64: { // sustain                      case 64: { // sustain
1678                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1679                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
# Line 1034  namespace LinuxSampler { Line 1747  namespace LinuxSampler {
1747                          }                          }
1748                          break;                          break;
1749                      }                      }
1750                      case 98: { // NRPN controller LSB                      case 98: { // NRPN parameter LSB
1751                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1752                          pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1753                            pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1754                          break;                          break;
1755                      }                      }
1756                      case 99: { // NRPN controller MSB                      case 99: { // NRPN parameter MSB
1757                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1758                          pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1759                            pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1760                          break;                          break;
1761                      }                      }
1762                      case 100: { // RPN controller LSB                      case 100: { // RPN parameter LSB
1763                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1764                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1765                            pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1766                          break;                          break;
1767                      }                      }
1768                      case 101: { // RPN controller MSB                      case 101: { // RPN parameter MSB
1769                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1770                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1771                            pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1772                          break;                          break;
1773                      }                      }
1774    
# Line 1085  namespace LinuxSampler { Line 1802  namespace LinuxSampler {
1802                          break;                          break;
1803                      }                      }
1804                  }                  }
1805    
1806                    // reset cached RPN/NRPN parameter number and data in case this
1807                    // CC event had nothing to do with RPN/NRPN
1808                    if (!bIsRpn && pChannel->GetMidiRpnParameter() >= 0)
1809                        pChannel->ResetMidiRpnParameter();
1810                    if (!bIsNrpn && pChannel->GetMidiNrpnParameter() >= 0)
1811                        pChannel->ResetMidiNrpnParameter();
1812                }
1813    
1814                /**
1815                 * Process MIDI RPN events with hard coded behavior.
1816                 *
1817                 * @param pEngineChannel - engine channel on which the MIDI RPN
1818                 *                         event was received
1819                 * @param itRpnEvent - the actual MIDI RPN event
1820                 */
1821                void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1822                                         Pool<Event>::Iterator& itRpnEvent)
1823                {
1824                    EngineChannelBase<V, R, I>* pChannel =
1825                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1826    
1827                    if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1828                        int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1829                        // limit to +- two octaves for now
1830                        transpose = RTMath::Min(transpose,  24);
1831                        transpose = RTMath::Max(transpose, -24);
1832                        pChannel->GlobalTranspose = transpose;
1833                        // workaround, so we won't have hanging notes
1834                        pChannel->ReleaseAllVoices(itRpnEvent);
1835                    }
1836                }
1837    
1838                /**
1839                 * Process MIDI NRPN events with hard coded behavior.
1840                 *
1841                 * @param pEngineChannel - engine channel on which the MIDI NRPN
1842                 *                         event was received
1843                 * @param itRpnEvent - the actual MIDI NRPN event
1844                 */
1845                void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1846                                          Pool<Event>::Iterator& itNrpnEvent)
1847                {
1848                    EngineChannelBase<V, R, I>* pChannel =
1849                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1850    
1851                    switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
1852                        case 0x1a: { // volume level of note (Roland GS NRPN)
1853                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1854                            const uint vol  = itNrpnEvent->Param.NRPN.ValueMSB();
1855                            dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1856                            if (note < 128 && vol < 128)
1857                                pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1858                            break;
1859                        }
1860                        case 0x1c: { // panpot of note (Roland GS NRPN)
1861                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1862                            const uint pan  = itNrpnEvent->Param.NRPN.ValueMSB();
1863                            dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1864                            if (note < 128 && pan < 128) {
1865                                pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
1866                                pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1867                            }
1868                            break;
1869                        }
1870                        case 0x1d: { // reverb send of note (Roland GS NRPN)
1871                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1872                            const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1873                            dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1874                            if (note < 128)
1875                                pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1876                            break;
1877                        }
1878                        case 0x1e: { // chorus send of note (Roland GS NRPN)
1879                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1880                            const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1881                            dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1882                            if (note < 128)
1883                                pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1884                            break;
1885                        }
1886                    }
1887              }              }
1888    
1889              virtual D* CreateDiskThread() = 0;              virtual D* CreateDiskThread() = 0;
# Line 1092  namespace LinuxSampler { Line 1891  namespace LinuxSampler {
1891              /**              /**
1892               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1893               *               *
1894               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1895               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1896               */               */
1897              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1898                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1899                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1900    
                 //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;  
   
1901                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1902                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1903                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1904    
1905                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1906    
1907                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1908                    // programmatically spawned notes (Event::type_play_note). We have
1909                    // to distinguish between them, since certain processing below
1910                    // must only be done on real MIDI note-on events (i.e. for
1911                    // correctly updating which MIDI keys are currently pressed down).
1912                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1913    
1914                    if (isRealMIDINoteOnEvent)
1915                        pChannel->listeners.PreProcessNoteOn(key, vel);
1916    
1917                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1918                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1919                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1920                            pChannel->listeners.PostProcessNoteOn(key, vel);
1921                      return;                      return;
1922                  }                  }
1923                  #endif                  #endif
1924    
1925                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1926                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1927                            pChannel->listeners.PostProcessNoteOn(key, vel);
1928                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1929                  }                  }
1930    
# Line 1126  namespace LinuxSampler { Line 1932  namespace LinuxSampler {
1932                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1933    
1934                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1935                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1936                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1937                      if (itYoungestKey) {                      if (itYoungestKey) {
1938                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1134  namespace LinuxSampler { Line 1940  namespace LinuxSampler {
1940                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1941                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1942                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1943                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1944                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1945                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1946                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1947                                    }
1948                              }                              }
1949                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1950                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1951                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1952                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1953                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1954                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1955                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1956                                    }
1957                              }                              }
1958                          }                          }
1959                      }                      }
# Line 1150  namespace LinuxSampler { Line 1961  namespace LinuxSampler {
1961                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1962                  }                  }
1963    
1964                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1965                        pChannel->ProcessKeySwitchChange(key);
1966    
1967                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1968                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1969                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1970                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1971                    }
1972    
1973                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1974                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1975                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1976                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1977                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1978                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1979                      }                      }
1980                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1981                  }                  }
# Line 1172  namespace LinuxSampler { Line 1986  namespace LinuxSampler {
1986                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1987                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1988    
1989                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1990                        pChannel->PortamentoPos = (float) key;
1991    
1992                    //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?
1993                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1994                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1995                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1996                  }                  }
1997                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1998                    if (isRealMIDINoteOnEvent)
1999                        pChannel->listeners.PostProcessNoteOn(key, vel);
2000              }              }
2001    
2002              /**              /**
# Line 1203  namespace LinuxSampler { Line 2022  namespace LinuxSampler {
2022               *  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.
2023               *  due to completion of sample playback).               *  due to completion of sample playback).
2024               *               *
2025               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
2026               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
2027               */               */
2028              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
2029                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2030    
                 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;  
   
2031                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
2032                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
2033                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2034    
2035                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2036    
2037                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
2038                    // programmatically spawned notes (Event::type_stop_note). We have
2039                    // to distinguish between them, since certain processing below
2040                    // must only be done on real MIDI note-off events (i.e. for
2041                    // correctly updating which MIDI keys are currently pressed down),
2042                    // plus a stop-note event just releases voices of one particular
2043                    // note, whereas a note-off event releases all voices on a
2044                    // particular MIDI key instead.
2045                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2046    
2047                    if (isRealMIDINoteOffEvent)
2048                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
2049    
2050                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2051                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2052                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
2053                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
2054                      return;                      return;
2055                  }                  }
2056                  #endif                  #endif
2057    
2058                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
2059                        pKey->KeyPressed = false; // the MIDI key was now released
2060                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2061                    }
2062    
2063                  // move event to the key's own event list                  // move event to the key's own event list
2064                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2065    
2066                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
2067                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2068    
2069                  // 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)
2070                  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
2071                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
2072                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
2073                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
2074                          // 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
2075                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
2076                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2077                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
2078                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
2079                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
2080                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
2081                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
2082                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
2083                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
2084                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
2085                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
2086                                  // create a pseudo note on event                                      }
2087                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
2088                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2089                                      // copy event                                      if (itPseudoNoteOnEvent) {
2090                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
2091                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2092                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
2093                                      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)
2094                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
2095                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2096                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
2097                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2098                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
2099                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2100                                            }
2101                                            // if neither a voice was spawned or postponed then remove note on event from key again
2102                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2103                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2104    
2105                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
2106                                  break; // done                                      break; // done
2107                                    }
2108                              }                              }
2109                          }                          }
2110                      }                          if (bOtherKeysPressed) {
2111                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
2112                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
2113                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2114                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2115                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
2116                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2117                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2118                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2119                                        }
2120                                    }
2121                              }                              }
2122                          }                          } else pChannel->PortamentoPos = -1.0f;
2123                      } 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  
2124    
2125                      // 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
2126                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
2127                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2128                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
2129                            if (pKey->ReleaseTrigger & release_trigger_noteoff)
2130                                ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2131                        }
2132                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2133                        // This programmatically caused event is caused by a call to
2134                        // the built-in instrument script function note_off(). In
2135                        // contrast to a real MIDI note-off event the stop-note
2136                        // event just intends to release voices of one particular note.
2137                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2138                        if (pNote) { // the requested note is still alive ...
2139                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2140                        } else { // note is dead and gone ..
2141                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2142                            return; // prevent event to be removed a 2nd time below
2143                      }                      }
2144                  }                  }
2145    
# Line 1300  namespace LinuxSampler { Line 2147  namespace LinuxSampler {
2147                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2148                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
2149    
2150                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
2151                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
2152                }
2153    
2154                /**
2155                 * Called on sustain pedal up events to check and if required,
2156                 * launch release trigger voices on the respective active key.
2157                 *
2158                 * @param pEngineChannel - engine channel on which this event occurred on
2159                 * @param itEvent - release trigger event (contains note number)
2160                 */
2161                virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2162                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2163    
2164                    const int iKey = itEvent->Param.Note.Key;
2165                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2166    
2167                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2168    
2169                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
2170                }
2171    
2172                /**
2173                 * Called on note-off and sustain pedal up events to check and if
2174                 * required, launch release trigger voices on the respective active
2175                 * key.
2176                 *
2177                 * @param pEngineChannel - engine channel on which this event occurred on
2178                 * @param itEvent - note off event / release trigger event
2179                 * @param pKey - key on which the release trigger voices shall be spawned
2180                 */
2181                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2182                    // spawn release triggered voice(s) if needed
2183                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2184                        // assign a new note to this release event
2185                        if (LaunchNewNote(pChannel, itEvent)) {
2186                            // allocate and trigger new release voice(s)
2187                            TriggerReleaseVoices(pChannel, itEvent);
2188                        }
2189                        pKey->ReleaseTrigger = release_trigger_none;
2190                    }
2191                }
2192    
2193                /**
2194                 * Called on "kill note" events, which currently only happens on
2195                 * built-in real-time instrument script function fade_out(). This
2196                 * method only fulfills one task: moving the even to the Note's own
2197                 * event list so that its voices can process the kill event sample
2198                 * accurately.
2199                 */
2200                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2201                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2202    
2203                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2204                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2205    
2206                    // move note kill event to its MIDI key
2207                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2208                    itEvent.moveToEndOf(pKey->pEvents);
2209                }
2210    
2211                /**
2212                 * Called on note synthesis parameter change events. These are
2213                 * internal events caused by calling built-in real-time instrument
2214                 * script functions like change_vol(), change_tune(), etc.
2215                 *
2216                 * This method performs two tasks:
2217                 *
2218                 * - It converts the event's relative values changes (Deltas) to
2219                 *   the respective final new synthesis parameter value (AbsValue),
2220                 *   for that particular moment of the event that is.
2221                 *
2222                 * - It moves the individual events to the Note's own event list
2223                 *   (or actually to the event list of the MIDI key), so that
2224                 *   voices can process those events sample accurately.
2225                 *
2226                 * @param pEngineChannel - engine channel on which this event occurred on
2227                 * @param itEvent - note synthesis parameter change event
2228                 */
2229                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2230                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2231    
2232                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2233                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2234    
2235                    switch (itEvent->Param.NoteSynthParam.Type) {
2236                        case Event::synth_param_volume:
2237                            pNote->apply(itEvent, &NoteBase::_Override::Volume);
2238                            break;
2239                        case Event::synth_param_volume_time:
2240                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2241                            break;
2242                        case Event::synth_param_volume_curve:
2243                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2244                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2245                            break;
2246                        case Event::synth_param_pitch:
2247                            pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2248                            break;
2249                        case Event::synth_param_pitch_time:
2250                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2251                            break;
2252                        case Event::synth_param_pitch_curve:
2253                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2254                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2255                            break;
2256                        case Event::synth_param_pan:
2257                            pNote->apply(itEvent, &NoteBase::_Override::Pan);
2258                            break;
2259                        case Event::synth_param_pan_time:
2260                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2261                            break;
2262                        case Event::synth_param_pan_curve:
2263                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2264                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2265                            break;
2266                        case Event::synth_param_cutoff:
2267                            pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2268                            break;
2269                        case Event::synth_param_resonance:
2270                            pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2271                            break;
2272                        case Event::synth_param_attack:
2273                            pNote->apply(itEvent, &NoteBase::_Override::Attack);
2274                            break;
2275                        case Event::synth_param_decay:
2276                            pNote->apply(itEvent, &NoteBase::_Override::Decay);
2277                            break;
2278                        case Event::synth_param_sustain:
2279                            pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2280                            break;
2281                        case Event::synth_param_release:
2282                            pNote->apply(itEvent, &NoteBase::_Override::Release);
2283                            break;
2284    
2285                        case Event::synth_param_cutoff_attack:
2286                            pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2287                            break;
2288                        case Event::synth_param_cutoff_decay:
2289                            pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2290                            break;
2291                        case Event::synth_param_cutoff_sustain:
2292                            pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2293                            break;
2294                        case Event::synth_param_cutoff_release:
2295                            pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2296                            break;
2297    
2298                        case Event::synth_param_amp_lfo_depth:
2299                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2300                            break;
2301                        case Event::synth_param_amp_lfo_freq:
2302                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2303                            break;
2304                        case Event::synth_param_cutoff_lfo_depth:
2305                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2306                            break;
2307                        case Event::synth_param_cutoff_lfo_freq:
2308                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2309                            break;
2310                        case Event::synth_param_pitch_lfo_depth:
2311                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2312                            break;
2313                        case Event::synth_param_pitch_lfo_freq:
2314                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2315                            break;
2316                    }
2317    
2318                    // move note parameter event to its MIDI key
2319                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2320                    itEvent.moveToEndOf(pKey->pEvents);
2321              }              }
2322    
2323              /**              /**
2324               *  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
2325               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2326               */               */
2327              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2328                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
2329    
2330                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
2331                  // while it's reseting                  // while it's reseting
# Line 1320  namespace LinuxSampler { Line 2337  namespace LinuxSampler {
2337                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2338                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2339                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2340                    itLastStolenNote           = NoteIterator();
2341                    itLastStolenNoteGlobally   = NoteIterator();
2342                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2343                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2344                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2345    
2346                    // reset all notes
2347                    pNotePool->clear();
2348                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2349                         itNote = pNotePool->allocAppend())
2350                    {
2351                        itNote->reset();
2352                    }
2353                    pNotePool->clear();
2354    
2355                  // reset all voices                  // reset all voices
2356                    pVoicePool->clear();
2357                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2358                      iterVoice->Reset();                      iterVoice->Reset();
2359                  }                  }
2360                  pVoicePool->clear();                  pVoicePool->clear();
2361    
2362                    // reset all engine channels
2363                    for (int i = 0; i < engineChannels.size(); i++) {
2364                        AbstractEngineChannel* pEngineChannel =
2365                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2366                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2367                    }
2368    
2369                  // reset disk thread                  // reset disk thread
2370                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2371    
# Line 1337  namespace LinuxSampler { Line 2373  namespace LinuxSampler {
2373                  pEventQueue->init();                  pEventQueue->init();
2374                  pSysexBuffer->init();                  pSysexBuffer->init();
2375                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
2376              }              }
2377    
2378              /**              /**
# Line 1348  namespace LinuxSampler { Line 2383  namespace LinuxSampler {
2383               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2384               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2385               */               */
2386              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2387                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2388                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2389                  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 1359  namespace LinuxSampler { Line 2394  namespace LinuxSampler {
2394               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2395               *  (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).
2396               *               *
2397               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2398               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2399               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2400               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1383  namespace LinuxSampler { Line 2418  namespace LinuxSampler {
2418                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2419              ) = 0;              ) = 0;
2420    
2421              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2422    
2423              int InitNewVoice (              int InitNewVoice (
2424                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1402  namespace LinuxSampler { Line 2437  namespace LinuxSampler {
2437                      // launch the new voice                      // launch the new voice
2438                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2439                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2440                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2441                      }                      }
2442                      else { // on success                      else { // on success
2443                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2444                          if (!pKey->Active) { // mark as active key  
2445                              pKey->Active = true;                          // should actually be superfluous now, since this is
2446                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2447                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2448                          }  
2449                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)                          if (itNewVoice->Type & Voice::type_release_trigger_required)
2450                                pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2451                          return 0; // success                          return 0; // success
2452                      }                      }
2453                  }                  }
# Line 1433  namespace LinuxSampler { Line 2469  namespace LinuxSampler {
2469    
2470                  return -1;                  return -1;
2471              }              }
2472                
2473                /**
2474                 * Checks whether scale tuning setting has been changed since last
2475                 * time this method was called, if yes, it recalculates the pitch
2476                 * for all active voices.
2477                 */
2478                void ProcessScaleTuningChange() {
2479                    const bool changed = ScaleTuningChanged.readAndReset();
2480                    if (!changed) return;
2481                    
2482                    for (int i = 0; i < engineChannels.size(); i++) {
2483                        EngineChannelBase<V, R, I>* channel =
2484                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2485                        channel->OnScaleTuningChanged();
2486                    }
2487                }
2488    
2489          private:          private:
2490                Pool< Note<V> >* pNotePool;
2491                Pool<note_id_t> noteIDPool;
2492              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2493              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2494              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2162  
changed lines
  Added in v.3697

  ViewVC Help
Powered by ViewVC