/[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 2244 by iliev, Thu Aug 18 11:32:33 2011 UTC revision 3704 by schoenebeck, Wed Jan 8 20:20:46 2020 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
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-2020 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2011 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Grigor Iliev                                  *
8     *   Copyright (C) 2012-2017 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);                  PostSetMaxVoices(iVoices);
304                  ResumeAll();                  ResumeAll();
305              }              }
# Line 250  namespace LinuxSampler { Line 307  namespace LinuxSampler {
307              /** Called after the new max number of voices is set and before resuming the engine. */              /** Called after the new max number of voices is set and before resuming the engine. */
308              virtual void PostSetMaxVoices(int iVoices) { }              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 269  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 282  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 311  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 331  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 360  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 413  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 429  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 538  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 557  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 586  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 609  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_rpn: // rpn handled in ProcessHardcodedControllers() instead ATM
828                                case Event::type_nrpn: // nrpn handled in ProcessHardcodedControllers() instead ATM
829                                case Event::type_cancel_release_key:
830                                case Event::type_release_key:
831                                case Event::type_release_note:
832                                case Event::type_play_note:
833                                case Event::type_stop_note:
834                                case Event::type_kill_note:
835                                case Event::type_note_synth_param:
836                                    break; // noop
837                            }
838    
839                            // see HACK comment above
840                            itEvent = itNext;
841                        }
842    
843                        // this has to be run again, since the newly spawned scripts
844                        // above may have cause suspended scripts that must be
845                        // resumed within this same audio fragment cycle
846                        //
847                        // FIXME: see FIXME comment above
848                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
849                    }
850    
851                    // if there are any delayed events scheduled for the current
852                    // audio fragment cycle, then move and sort them into the main
853                    // event list
854                    if (!pChannel->delayedEvents.queue.isEmpty()) {
855                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
856                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
857                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
858                        while (true) {
859                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
860                                pEventGenerator->popNextScheduledEvent(
861                                    pChannel->delayedEvents.queue,
862                                    pChannel->delayedEvents.schedulerNodes,
863                                    fragmentEndTime
864                                );
865                            if (!itDelayedEventNode) break;
866                            // get the actual delayed event object and free the used scheduler node
867                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
868                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
869                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
870                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
871                                continue;
872                            }
873                            // skip all events on main event list which have a time
874                            // before (or equal to) the delayed event to be inserted
875                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
876                                 ++itEvent);
877                            // now move delayed event from delayedEvents.pList to
878                            // the current position on the main event list
879                            itEvent = itDelayedEvent.moveBefore(itEvent);
880                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
881                        }
882                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
883                    }
884    
885                    // now process all events regularly
886                  {                  {
887                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
888                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
889                      for (; itEvent != end; ++itEvent) {                      for (; itEvent != end; ++itEvent) {
890                            bool bIsCC = false; // just for resetting RPN/NRPN below
891                          switch (itEvent->Type) {                          switch (itEvent->Type) {
892                              case Event::type_note_on:                              case Event::type_note_on:
893                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
894                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
895                                  break;                                  break;
896                                case Event::type_play_note:
897                                    dmsg(5,("Engine: Play Note received\n"));
898                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
899                                    break;
900                              case Event::type_note_off:                              case Event::type_note_off:
901                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
902                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
903                                  break;                                  break;
904                                case Event::type_stop_note:
905                                    dmsg(5,("Engine: Stop Note received\n"));
906                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
907                                    break;
908                                case Event::type_kill_note:
909                                    dmsg(5,("Engine: Kill Note received\n"));
910                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
911                                    break;
912                              case Event::type_control_change:                              case Event::type_control_change:
913                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
914                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
915                                    bIsCC = true;
916                                    break;
917                                case Event::type_rpn: // this can only be reached here by an instrument script having called set_rpn()
918                                    dmsg(5,("Engine: MIDI RPN received\n"));
919                                    ProcessHardcodedRpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
920                                    bIsCC = true;
921                                    break;
922                                case Event::type_nrpn: // this can only be reached here by an instrument script having called set_nrpn()
923                                    dmsg(5,("Engine: MIDI NRPN received\n"));
924                                    ProcessHardcodedNrpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
925                                    bIsCC = true;
926                                    break;
927                                case Event::type_channel_pressure:
928                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
929                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
930                                    break;
931                                case Event::type_note_pressure:
932                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
933                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
934                                  break;                                  break;
935                              case Event::type_pitchbend:                              case Event::type_pitchbend:
936                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
937                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
938                                  break;                                  break;
939                                case Event::type_note_synth_param:
940                                    dmsg(5,("Engine: Note Synth Param received\n"));
941                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
942                                    break;
943                                case Event::type_sysex:
944                                    break; // TODO ...
945    
946                                case Event::type_cancel_release_key:
947                                case Event::type_release_key:
948                                case Event::type_release_note:
949                                    break; // noop
950                            }
951                            // reset cached RPN/NRPN parameter number and data in
952                            // case this event was not a control change event
953                            if (!bIsCC) {
954                                if (pChannel->GetMidiRpnParameter() >= 0)
955                                    pChannel->ResetMidiRpnParameter();
956                                if (pChannel->GetMidiNrpnParameter() >= 0)
957                                    pChannel->ResetMidiNrpnParameter();
958                          }                          }
959                      }                      }
960                  }                  }
# Line 638  namespace LinuxSampler { Line 962  namespace LinuxSampler {
962                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
963                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
964                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
965                    itLastStolenNote          = NoteIterator();
966                    itLastStolenNoteGlobally  = NoteIterator();
967                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
968                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
969                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
970              }              }
971    
972              /**              /**
973                 * Run all suspended script execution instances which are scheduled
974                 * to be resumed for the current audio fragment cycle.
975                 *
976                 * @param pChannel - engine channel on which suspended events occurred
977                 */
978                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
979                    while (true) {
980                        RTList<ScriptEvent>::Iterator itEvent =
981                            pEventGenerator->popNextScheduledScriptEvent(
982                                pChannel->pScript->suspendedEvents,
983                                *pChannel->pScript->pEvents, fragmentEndTime
984                            );
985                        if (!itEvent) break;
986                        ResumeScriptEvent(pChannel, itEvent);
987                    }
988                }
989    
990                /** @brief Call instrument script's event handler for this event.
991                 *
992                 * Causes a new execution instance of the currently loaded real-time
993                 * instrument script's event handler (callback) to be spawned for
994                 * the given MIDI event.
995                 *
996                 * @param pChannel - engine channel on which the MIDI event occurred
997                 * @param itEvent - MIDI event that causes this new script execution
998                 * @param pEventHandler - script's event handler to be executed
999                 */
1000                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
1001                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
1002                    // check if polyphonic data is passed from "note" to "release"
1003                    // script event handlers
1004                    if (pEventHandler == pChannel->pScript->handlerRelease &&
1005                        pChannel->pScript->handlerNote &&
1006                        pChannel->pScript->handlerNote->isPolyphonic() &&
1007                        pChannel->pScript->handlerRelease->isPolyphonic() &&
1008                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
1009                    {
1010                        // polyphonic variable data is used/passed from "note" to
1011                        // "release" script callback, so we have to recycle the
1012                        // original "note on" script event(s)
1013                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
1014                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
1015                        for (; it != end; ++it) {
1016                            ProcessScriptEvent(
1017                                pChannel, itEvent, pEventHandler, it
1018                            );
1019                        }
1020                    } else {
1021                        // no polyphonic data is used/passed from "note" to
1022                        // "release" script callback, so just use a new fresh
1023                        // script event object
1024                        RTList<ScriptEvent>::Iterator itScriptEvent =
1025                            pChannel->pScript->pEvents->allocAppend();
1026                        // if event handler uses polyphonic variables, reset them
1027                        // to zero values before starting to execute the handler
1028                        if (pEventHandler->isPolyphonic())
1029                            itScriptEvent->execCtx->resetPolyphonicData();
1030                        ProcessScriptEvent(
1031                            pChannel, itEvent, pEventHandler, itScriptEvent
1032                        );
1033                    }
1034                }
1035    
1036                /** @brief Spawn new execution instance of an instrument script handler.
1037                 *
1038                 * Will be called to initiate a new execution of a real-time
1039                 * instrument script event right from the start of the script's
1040                 * respective handler. If script execution did not complete after
1041                 * calling this method, the respective script exeuction is then
1042                 * suspended and a call to ResumeScriptEvent() will be used next
1043                 * time to continue its execution.
1044                 *
1045                 * @param pChannel - engine channel this script is running for
1046                 * @param itEvent - event which caused execution of this script
1047                 *                  event handler
1048                 * @param pEventHandler - VM representation of event handler to be
1049                 *                        executed
1050                 * @param itScriptEvent - script event that shall be processed
1051                 */
1052                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1053                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1054    
1055                    // fill the list of script handlers to be executed by this event
1056                    int i = 0;
1057                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1058                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1059    
1060                    // initialize/reset other members
1061                    itScriptEvent->cause = *itEvent;
1062                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1063                    itScriptEvent->currentHandler = 0;
1064                    itScriptEvent->executionSlices = 0;
1065                    itScriptEvent->ignoreAllWaitCalls = false;
1066                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1067                    itScriptEvent->parentHandlerID = 0;
1068                    itScriptEvent->childHandlerID[0] = 0;
1069                    itScriptEvent->autoAbortByParent = false;
1070                    itScriptEvent->forkIndex = 0;
1071                    // this is the native representation of the $EVENT_ID script variable
1072                    itScriptEvent->id =
1073                        (itEvent->Type == Event::type_note_on)
1074                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1075                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1076    
1077                    // run script handler(s)
1078                    VMExecStatus_t res = pScriptVM->exec(
1079                        pChannel->pScript->parserContext, &*itScriptEvent
1080                    );
1081    
1082                    // was the script suspended?
1083                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1084                        // in case the script was suspended, keep it on the allocated
1085                        // ScriptEvent list to be resume at the scheduled time in future,
1086                        // additionally insert it into a sorted time queue
1087                        pEventGenerator->scheduleAheadMicroSec(
1088                            pChannel->pScript->suspendedEvents, // scheduler queue
1089                            *itScriptEvent, // script event
1090                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1091                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1092                        );
1093                    } else { // script execution has finished without 'suspended' status ...
1094                        // if "polyphonic" variable data is passed from script's
1095                        // "note" event handler to its "release" event handler, then
1096                        // the script event must be kept and recycled for the later
1097                        // occuring "release" script event ...
1098                        if (pEventHandler == pChannel->pScript->handlerNote &&
1099                            pChannel->pScript->handlerRelease &&
1100                            pChannel->pScript->handlerNote->isPolyphonic() &&
1101                            pChannel->pScript->handlerRelease->isPolyphonic())
1102                        {
1103                            const int key = itEvent->Param.Note.Key;
1104                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1105                        } else {
1106                            // ... otherwise if no polyphonic data is passed and
1107                            // script's execution has finished without suspension
1108                            // status, then free the script event for a new future
1109                            // script event to be triggered from start
1110                            pChannel->pScript->pEvents->free(itScriptEvent);
1111                        }
1112                    }
1113                }
1114    
1115                /** @brief Resume execution of instrument script.
1116                 *
1117                 * Will be called to resume execution of a real-time instrument
1118                 * script event which has been suspended previously.
1119                 *
1120                 * Script execution might be suspended for various reasons. Usually
1121                 * a script will be suspended if the script called the built-in
1122                 * "wait()" function, but it might also be suspended automatically
1123                 * if the script took too much execution time in an audio fragment
1124                 * cycle. So in the latter case automatic suspension is performed in
1125                 * order to avoid harm for the sampler's overall real-time
1126                 * requirements.
1127                 *
1128                 * @param pChannel - engine channel this script is running for
1129                 * @param itScriptEvent - script execution that shall be resumed
1130                 */
1131                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1132                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1133    
1134                    // run script
1135                    VMExecStatus_t res = pScriptVM->exec(
1136                        pChannel->pScript->parserContext, &*itScriptEvent
1137                    );
1138    
1139                    // was the script suspended?
1140                    if (res & VM_EXEC_SUSPENDED) {
1141                        // in case the script was suspended, keep it on the allocated
1142                        // ScriptEvent list to be resume at the scheduled time in future,
1143                        // additionally insert it into a sorted time queue
1144                        pEventGenerator->scheduleAheadMicroSec(
1145                            pChannel->pScript->suspendedEvents, // scheduler queue
1146                            *itScriptEvent, // script event
1147                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1148                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1149                        );
1150                    } else { // script execution has finished without 'suspended' status ...
1151                        // if "polyphonic" variable data is passed from script's
1152                        // "note" event handler to its "release" event handler, then
1153                        // the script event must be kept and recycled for the later
1154                        // occuring "release" script event ...
1155                        if (handler && handler == pChannel->pScript->handlerNote &&
1156                            pChannel->pScript->handlerRelease &&
1157                            pChannel->pScript->handlerNote->isPolyphonic() &&
1158                            pChannel->pScript->handlerRelease->isPolyphonic())
1159                        {
1160                            const int key = itScriptEvent->cause.Param.Note.Key;
1161                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1162                        } else {
1163                            // ... otherwise if no polyphonic data is passed and
1164                            // script's execution has finished without suspension
1165                            // status, then free the script event for a new future
1166                            // script event to be triggered from start
1167                            pChannel->pScript->pEvents->free(itScriptEvent);
1168                        }
1169                    }
1170                }
1171    
1172                /**
1173               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1174               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1175               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1176               *  voice actually died.               *  voice actually died.
1177               *               *
1178               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1179               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1180               *  @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
1181               */               */
1182              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1183                    dmsg(3,("StealVoice()\n"));
1184                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1185                      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"));
1186                      return -1;                      return -1;
# Line 661  namespace LinuxSampler { Line 1188  namespace LinuxSampler {
1188    
1189                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1190    
1191                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1192                        dmsg(1,("Event pool emtpy!\n"));
1193                        return -1;
1194                    }
1195    
1196                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1197                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1198                          return 0;                      return 0;
1199                      }                  }
1200    
1201                      // 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
1202                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1203                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1204                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1205                      int                       iChannelIndex;                  int                          iChannelIndex;
1206                      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  
                     }  
1207    
1208                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1209                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = NULL; // to detect endless loop
1210                      #endif // CONFIG_DEVMODE                  #endif
1211    
1212                    // select engine channel
1213                    if (pLastStolenChannel) {
1214                        pSelectedChannel = pLastStolenChannel;
1215                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1216                    } else { // pick the engine channel followed by this engine channel
1217                        iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1218                        pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1219                    }
1220    
1221                    // if we already stole in this fragment, try to proceed on same note
1222                    if (this->itLastStolenVoiceGlobally) {
1223                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1224                        do {
1225                            ++itSelectedVoice;
1226                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1227                    }
1228                    // did we find a 'stealable' voice?
1229                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1230                        // remember which voice we stole, so we can simply proceed on next voice stealing
1231                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1232                        // done
1233                        goto stealable_voice_found;
1234                    }
1235    
1236                    // get (next) oldest note
1237                    if (this->itLastStolenNoteGlobally) {
1238                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1239                             itNote; ++itNote)
1240                        {
1241                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1242                                // proceed iterating if voice was created in this audio fragment cycle
1243                                if (itSelectedVoice->IsStealable()) {
1244                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1245                                    this->itLastStolenNoteGlobally  = itNote;
1246                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1247                                    goto stealable_voice_found; // selection succeeded
1248                                }
1249                            }
1250                        }
1251                    }
1252    
1253                      // did we find a 'stealable' voice?                  #if CONFIG_DEVMODE
1254                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                  pBegin = pSelectedChannel; // to detect endless loop
1255                          // remember which voice we stole, so we can simply proceed on next voice stealing                  #endif // CONFIG_DEVMODE
1256                          this->itLastStolenVoiceGlobally = itSelectedVoice;  
1257                      } else while (true) { // iterate through engine channels                  while (true) { // iterate through engine channels                        
1258                          // get (next) oldest key                      // get (next) oldest key
1259                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1260                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1261                          while (iuiSelectedKey) {                      while (iuiSelectedKey) {
1262                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1263                              itSelectedVoice = pSelectedKey->pActiveVoices->first();  
1264                            for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1265                                 itNotesEnd = pSelectedKey->pActiveNotes->end();
1266                                 itNote != itNotesEnd; ++itNote)
1267                            {
1268                                itSelectedVoice = itNote->pActiveVoices->first();
1269                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1270                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1271                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1272                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1273                                  // 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
1274                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1275                                    this->itLastStolenNoteGlobally  = itNote;
1276                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1277                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1278                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1279                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1280                          }                          }
1281                          // 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  
1282                      }                      }
1283                        // get next engine channel
1284                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1285                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1286    
1287                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1288                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1289                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1290                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1291                            dmsg(1,("Exiting.\n"));
1292                            exit(-1);
1293                      }                      }
1294                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1295                    }
1296    
1297                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1298                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1299    
1300                      return 0; // success                  #if CONFIG_DEVMODE
1301                  }                  if (!itSelectedVoice->IsActive()) {
1302                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1303                      return -1;                      return -1;
1304                  }                  }
1305                    #endif // CONFIG_DEVMODE
1306    
1307                    // now kill the selected voice
1308                    itSelectedVoice->Kill(itNoteOnEvent);
1309    
1310                    --VoiceSpawnsLeft;
1311    
1312                    return 0; // success
1313              }              }
1314    
1315              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 775  namespace LinuxSampler { Line 1331  namespace LinuxSampler {
1331                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1332                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1333                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1334                            pEngineChannel->pScript =
1335                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1336                          instrumentChanged = true;                          instrumentChanged = true;
1337    
1338                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1339    
1340                            // the script's "init" event handler is only executed
1341                            // once (when the script is loaded or reloaded)
1342                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1343                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1344                                RTList<ScriptEvent>::Iterator itScriptEvent =
1345                                    pEngineChannel->pScript->pEvents->allocAppend();
1346    
1347                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1348                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1349                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1350                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1351                                itScriptEvent->id = 0;
1352                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1353                                itScriptEvent->handlers[1] = NULL;
1354                                itScriptEvent->currentHandler = 0;
1355                                itScriptEvent->executionSlices = 0;
1356                                itScriptEvent->ignoreAllWaitCalls = false;
1357                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1358                                itScriptEvent->parentHandlerID = 0;
1359                                itScriptEvent->childHandlerID[0] = 0;
1360                                itScriptEvent->autoAbortByParent = false;
1361                                itScriptEvent->forkIndex = 0;
1362    
1363                                VMExecStatus_t res;
1364                                size_t instructionsCount = 0;
1365                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1366                                bool bWarningShown = false;
1367                                do {
1368                                    res = pScriptVM->exec(
1369                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1370                                    );
1371                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1372                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1373                                        bWarningShown = true;
1374                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1375                                    }
1376                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1377    
1378                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1379                            }
1380                      }                      }
1381                  }                  }
1382    
# Line 828  namespace LinuxSampler { Line 1427  namespace LinuxSampler {
1427                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1428                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1429                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1430                        
1431                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1432                          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);
1433                      if (itNewVoice) {                      if (itNewVoice) {
1434                            // usually there should already be a new Note object
1435                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1436                            if (!itNote) { // should not happen, but just to be sure ...
1437                                dmsg(2,("Engine: No Note object for stolen voice!\n"));
1438                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1439                                if (!noteID) {
1440                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1441                                    continue;
1442                                }
1443                                itNote = GetNotePool()->fromID(noteID);
1444                            }
1445                            // move voice from whereever it was, to the new note's list of active voices
1446                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1447                            // render audio of this new voice for the first time
1448                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1449                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1450                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 865  namespace LinuxSampler { Line 1479  namespace LinuxSampler {
1479              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1480                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1481                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1482                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1483    
1484                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1485                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1486                    pChannel->ClearEventListsOfCurrentFragment();
1487              }              }
1488    
1489              /**              /**
# Line 886  namespace LinuxSampler { Line 1501  namespace LinuxSampler {
1501                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1502                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1503    
1504                    // will be set to true if this CC event has anything to do with RPN/NRPN
1505                    bool bIsRpn = false, bIsNrpn = false;
1506    
1507                  switch (itControlChangeEvent->Param.CC.Controller) {                  switch (itControlChangeEvent->Param.CC.Controller) {
1508                      case 5: { // portamento time                      case 5: { // portamento time
1509                          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;
1510                          break;                          break;
1511                      }                      }
1512                      case 6: { // data entry (currently only used for RPN and NRPN controllers)                      case 6: { // data entry (MSB)
1513                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));                          //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1514                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...                          if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1515                              dmsg(4,("Guess it's an RPN ...\n"));                              pChannel->SetMidiRpnDataMsb(
1516                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                                  itControlChangeEvent->Param.CC.Value
1517                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                              );
1518                                  // limit to +- two octaves for now                              bIsRpn = true;
1519                                  transpose = RTMath::Min(transpose,  24);  
1520                                  transpose = RTMath::Max(transpose, -24);                              // look-ahead: if next MIDI event is data entry LSB,
1521                                  pChannel->GlobalTranspose = transpose;                              // then skip this event here for now (to avoid double
1522                                  // workaround, so we won't have hanging notes                              // handling of what's supposed to be one RPN event)
1523                                  pChannel->ReleaseAllVoices(itControlChangeEvent);                              if (isNextEventCCNr(itControlChangeEvent, 38))
1524                              }                                  break;
1525                              // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data  
1526                              pChannel->ResetMidiRpnController();                              int ch = itControlChangeEvent->Param.CC.Channel;
1527                          } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...                              int param = pChannel->GetMidiRpnParameter();
1528                              dmsg(4,("Guess it's an NRPN ...\n"));                              int value = pChannel->GetMidiRpnData();
1529                              const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;  
1530                              const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;                              // transform event type: CC event -> RPN event
1531                              dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));                              itControlChangeEvent->Type = Event::type_rpn;
1532                              switch (NrpnCtrlMSB) {                              itControlChangeEvent->Param.RPN.Channel = ch;
1533                                  case 0x1a: { // volume level of note (Roland GS NRPN)                              itControlChangeEvent->Param.RPN.Parameter = param;
1534                                      const uint note = NrpnCtrlLSB;                              itControlChangeEvent->Param.RPN.Value = value;
1535                                      const uint vol  = itControlChangeEvent->Param.CC.Value;  
1536                                      dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));                              // if there's a RPN script handler, run it ...
1537                                      if (note < 128 && vol < 128)                              if (pChannel->pScript->handlerRpn) {
1538                                          pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];                                  const event_id_t eventID =
1539                                      break;                                      pEventPool->getID(itControlChangeEvent);
1540                                  }                                  // run the RPN script handler
1541                                  case 0x1c: { // panpot of note (Roland GS NRPN)                                  ProcessEventByScript(
1542                                      const uint note = NrpnCtrlLSB;                                      pChannel, itControlChangeEvent,
1543                                      const uint pan  = itControlChangeEvent->Param.CC.Value;                                      pChannel->pScript->handlerRpn
1544                                      dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));                                  );
1545                                      if (note < 128 && pan < 128) {                                  // if RPN event was dropped by script, abort
1546                                          pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];                                  // here to avoid hard coded RPN processing below
1547                                          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;  
1548                                      break;                                      break;
1549                                  }                              }
1550                                  case 0x1e: { // chorus send of note (Roland GS NRPN)  
1551                                      const uint note = NrpnCtrlLSB;                              // do the actual (hard-coded) RPN value change processing
1552                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                              ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1553                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));  
1554                                      if (note < 128)                          } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1555                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                              pChannel->SetMidiNrpnDataMsb(
1556                                    itControlChangeEvent->Param.CC.Value
1557                                );
1558                                bIsNrpn = true;
1559    
1560                                // look-ahead: if next MIDI event is data entry LSB,
1561                                // then skip this event here for now (to avoid double
1562                                // handling of what's supposed to be one NRPN event)
1563                                if (isNextEventCCNr(itControlChangeEvent, 38))
1564                                    break;
1565    
1566                                int ch = itControlChangeEvent->Param.CC.Channel;
1567                                int param = pChannel->GetMidiNrpnParameter();
1568                                int value = pChannel->GetMidiNrpnData();
1569    
1570                                // transform event type: CC event -> NRPN event
1571                                itControlChangeEvent->Type = Event::type_nrpn;
1572                                itControlChangeEvent->Param.NRPN.Channel = ch;
1573                                itControlChangeEvent->Param.NRPN.Parameter = param;
1574                                itControlChangeEvent->Param.NRPN.Value = value;
1575    
1576                                // if there's a NRPN script handler, run it ...
1577                                if (pChannel->pScript->handlerNrpn) {
1578                                    const event_id_t eventID =
1579                                        pEventPool->getID(itControlChangeEvent);
1580                                    // run the NRPN script handler
1581                                    ProcessEventByScript(
1582                                        pChannel, itControlChangeEvent,
1583                                        pChannel->pScript->handlerNrpn
1584                                    );
1585                                    // if NRPN event was dropped by script, abort
1586                                    // here to avoid hard coded NRPN processing below
1587                                    if (!pEventPool->fromID(eventID))
1588                                      break;                                      break;
                                 }  
1589                              }                              }
1590                              // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data  
1591                              pChannel->ResetMidiNrpnController();                              // do the actual (hard-coded) NRPN value change processing
1592                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1593                          }                          }
1594                          break;                          break;
1595                      }                      }
# Line 960  namespace LinuxSampler { Line 1601  namespace LinuxSampler {
1601                      }                      }
1602                      case 10: { // panpot                      case 10: { // panpot
1603                          //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];  
1604                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1605                          break;                          break;
1606                      }                      }
1607                        case 38: { // data entry (LSB)
1608                            //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1609                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1610                                pChannel->SetMidiRpnDataLsb(
1611                                    itControlChangeEvent->Param.CC.Value
1612                                );
1613                                bIsRpn = true;
1614    
1615                                int ch = itControlChangeEvent->Param.CC.Channel;
1616                                int param = pChannel->GetMidiRpnParameter();
1617                                int value = pChannel->GetMidiRpnData();
1618    
1619                                // transform event type: CC event -> RPN event
1620                                itControlChangeEvent->Type = Event::type_rpn;
1621                                itControlChangeEvent->Param.RPN.Channel = ch;
1622                                itControlChangeEvent->Param.RPN.Parameter = param;
1623                                itControlChangeEvent->Param.RPN.Value = value;
1624    
1625                                // if there's a RPN script handler, run it ...
1626                                if (pChannel->pScript->handlerRpn) {
1627                                    const event_id_t eventID =
1628                                        pEventPool->getID(itControlChangeEvent);
1629                                    // run the RPN script handler
1630                                    ProcessEventByScript(
1631                                        pChannel, itControlChangeEvent,
1632                                        pChannel->pScript->handlerRpn
1633                                    );
1634                                    // if RPN event was dropped by script, abort
1635                                    // here to avoid hard coded RPN processing below
1636                                    if (!pEventPool->fromID(eventID))
1637                                        break;
1638                                }
1639    
1640                                // do the actual (hard-coded) RPN value change processing
1641                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1642    
1643                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1644                                pChannel->SetMidiNrpnDataLsb(
1645                                    itControlChangeEvent->Param.CC.Value
1646                                );
1647                                bIsNrpn = true;
1648    
1649                                int ch = itControlChangeEvent->Param.CC.Channel;
1650                                int param = pChannel->GetMidiNrpnParameter();
1651                                int value = pChannel->GetMidiNrpnData();
1652    
1653                                // transform event type: CC event -> NRPN event
1654                                itControlChangeEvent->Type = Event::type_nrpn;
1655                                itControlChangeEvent->Param.NRPN.Channel = ch;
1656                                itControlChangeEvent->Param.NRPN.Parameter = param;
1657                                itControlChangeEvent->Param.NRPN.Value = value;
1658    
1659                                // if there's a NRPN script handler, run it ...
1660                                if (pChannel->pScript->handlerNrpn) {
1661                                    const event_id_t eventID =
1662                                        pEventPool->getID(itControlChangeEvent);
1663                                    // run the NRPN script handler
1664                                    ProcessEventByScript(
1665                                        pChannel, itControlChangeEvent,
1666                                        pChannel->pScript->handlerNrpn
1667                                    );
1668                                    // if NRPN event was dropped by script, abort
1669                                    // here to avoid hard coded NRPN processing below
1670                                    if (!pEventPool->fromID(eventID))
1671                                        break;
1672                                }
1673    
1674                                // do the actual (hard-coded) NRPN value change processing
1675                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1676                            }
1677                            break;
1678                        }
1679                      case 64: { // sustain                      case 64: { // sustain
1680                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1681                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
# Line 1038  namespace LinuxSampler { Line 1749  namespace LinuxSampler {
1749                          }                          }
1750                          break;                          break;
1751                      }                      }
1752                      case 98: { // NRPN controller LSB                      case 96: { // data increment (data entry +1)
1753                            //dmsg(1,("DATA INC\n"));
1754                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1755                                pChannel->SetMidiRpnData(
1756                                    pChannel->GetMidiRpnData() + 1
1757                                );
1758                                bIsRpn = true;
1759    
1760                                int ch = itControlChangeEvent->Param.CC.Channel;
1761                                int param = pChannel->GetMidiRpnParameter();
1762                                int value = pChannel->GetMidiRpnData();
1763    
1764                                // transform event type: CC event -> RPN event
1765                                itControlChangeEvent->Type = Event::type_rpn;
1766                                itControlChangeEvent->Param.RPN.Channel = ch;
1767                                itControlChangeEvent->Param.RPN.Parameter = param;
1768                                itControlChangeEvent->Param.RPN.Value = value;
1769    
1770                                // if there's a RPN script handler, run it ...
1771                                if (pChannel->pScript->handlerRpn) {
1772                                    const event_id_t eventID =
1773                                        pEventPool->getID(itControlChangeEvent);
1774                                    // run the RPN script handler
1775                                    ProcessEventByScript(
1776                                        pChannel, itControlChangeEvent,
1777                                        pChannel->pScript->handlerRpn
1778                                    );
1779                                    // if RPN event was dropped by script, abort
1780                                    // here to avoid hard coded RPN processing below
1781                                    if (!pEventPool->fromID(eventID))
1782                                        break;
1783                                }
1784    
1785                                // do the actual (hard-coded) RPN value change processing
1786                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1787    
1788                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1789                                pChannel->SetMidiNrpnData(
1790                                    pChannel->GetMidiNrpnData() + 1
1791                                );
1792                                bIsNrpn = true;
1793    
1794                                int ch = itControlChangeEvent->Param.CC.Channel;
1795                                int param = pChannel->GetMidiNrpnParameter();
1796                                int value = pChannel->GetMidiNrpnData();
1797    
1798                                // transform event type: CC event -> NRPN event
1799                                itControlChangeEvent->Type = Event::type_nrpn;
1800                                itControlChangeEvent->Param.NRPN.Channel = ch;
1801                                itControlChangeEvent->Param.NRPN.Parameter = param;
1802                                itControlChangeEvent->Param.NRPN.Value = value;
1803    
1804                                // if there's a NRPN script handler, run it ...
1805                                if (pChannel->pScript->handlerNrpn) {
1806                                    const event_id_t eventID =
1807                                        pEventPool->getID(itControlChangeEvent);
1808                                    // run the NRPN script handler
1809                                    ProcessEventByScript(
1810                                        pChannel, itControlChangeEvent,
1811                                        pChannel->pScript->handlerNrpn
1812                                    );
1813                                    // if NRPN event was dropped by script, abort
1814                                    // here to avoid hard coded NRPN processing below
1815                                    if (!pEventPool->fromID(eventID))
1816                                        break;
1817                                }
1818    
1819                                // do the actual (hard-coded) NRPN value change processing
1820                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1821                            }
1822                            break;
1823                        }
1824                        case 97: { // data decrement (data entry -1)
1825                            //dmsg(1,("DATA DEC\n"));
1826                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1827                                pChannel->SetMidiRpnData(
1828                                    pChannel->GetMidiRpnData() - 1
1829                                );
1830                                bIsRpn = true;
1831    
1832                                int ch = itControlChangeEvent->Param.CC.Channel;
1833                                int param = pChannel->GetMidiRpnParameter();
1834                                int value = pChannel->GetMidiRpnData();
1835    
1836                                // transform event type: CC event -> RPN event
1837                                itControlChangeEvent->Type = Event::type_rpn;
1838                                itControlChangeEvent->Param.RPN.Channel = ch;
1839                                itControlChangeEvent->Param.RPN.Parameter = param;
1840                                itControlChangeEvent->Param.RPN.Value = value;
1841    
1842                                // if there's a RPN script handler, run it ...
1843                                if (pChannel->pScript->handlerRpn) {
1844                                    const event_id_t eventID =
1845                                        pEventPool->getID(itControlChangeEvent);
1846                                    // run the RPN script handler
1847                                    ProcessEventByScript(
1848                                        pChannel, itControlChangeEvent,
1849                                        pChannel->pScript->handlerRpn
1850                                    );
1851                                    // if RPN event was dropped by script, abort
1852                                    // here to avoid hard coded RPN processing below
1853                                    if (!pEventPool->fromID(eventID))
1854                                        break;
1855                                }
1856    
1857                                // do the actual (hard-coded) RPN value change processing
1858                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1859    
1860                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1861                                pChannel->SetMidiNrpnData(
1862                                    pChannel->GetMidiNrpnData() - 1
1863                                );
1864                                bIsNrpn = true;
1865    
1866                                int ch = itControlChangeEvent->Param.CC.Channel;
1867                                int param = pChannel->GetMidiNrpnParameter();
1868                                int value = pChannel->GetMidiNrpnData();
1869    
1870                                // transform event type: CC event -> NRPN event
1871                                itControlChangeEvent->Type = Event::type_nrpn;
1872                                itControlChangeEvent->Param.NRPN.Channel = ch;
1873                                itControlChangeEvent->Param.NRPN.Parameter = param;
1874                                itControlChangeEvent->Param.NRPN.Value = value;
1875    
1876                                // if there's a NRPN script handler, run it ...
1877                                if (pChannel->pScript->handlerNrpn) {
1878                                    const event_id_t eventID =
1879                                        pEventPool->getID(itControlChangeEvent);
1880                                    // run the NRPN script handler
1881                                    ProcessEventByScript(
1882                                        pChannel, itControlChangeEvent,
1883                                        pChannel->pScript->handlerNrpn
1884                                    );
1885                                    // if NRPN event was dropped by script, abort
1886                                    // here to avoid hard coded NRPN processing below
1887                                    if (!pEventPool->fromID(eventID))
1888                                        break;
1889                                }
1890    
1891                                // do the actual (hard-coded) NRPN value change processing
1892                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1893                            }
1894                            break;
1895                        }
1896                        case 98: { // NRPN parameter LSB
1897                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1898                          pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1899                            pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1900                          break;                          break;
1901                      }                      }
1902                      case 99: { // NRPN controller MSB                      case 99: { // NRPN parameter MSB
1903                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1904                          pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1905                            pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1906                          break;                          break;
1907                      }                      }
1908                      case 100: { // RPN controller LSB                      case 100: { // RPN parameter LSB
1909                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1910                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1911                            pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1912                          break;                          break;
1913                      }                      }
1914                      case 101: { // RPN controller MSB                      case 101: { // RPN parameter MSB
1915                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1916                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1917                            pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1918                          break;                          break;
1919                      }                      }
1920    
# Line 1089  namespace LinuxSampler { Line 1948  namespace LinuxSampler {
1948                          break;                          break;
1949                      }                      }
1950                  }                  }
1951    
1952                    // reset cached RPN/NRPN parameter number and data in case this
1953                    // CC event had nothing to do with RPN/NRPN
1954                    if (!bIsRpn && pChannel->GetMidiRpnParameter() >= 0)
1955                        pChannel->ResetMidiRpnParameter();
1956                    if (!bIsNrpn && pChannel->GetMidiNrpnParameter() >= 0)
1957                        pChannel->ResetMidiNrpnParameter();
1958                }
1959    
1960                /**
1961                 * Process MIDI RPN events with hard coded behavior.
1962                 *
1963                 * @param pEngineChannel - engine channel on which the MIDI RPN
1964                 *                         event was received
1965                 * @param itRpnEvent - the actual MIDI RPN event
1966                 */
1967                void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1968                                         Pool<Event>::Iterator& itRpnEvent)
1969                {
1970                    EngineChannelBase<V, R, I>* pChannel =
1971                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1972    
1973                    if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1974                        int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1975                        // limit to +- two octaves for now
1976                        transpose = RTMath::Min(transpose,  24);
1977                        transpose = RTMath::Max(transpose, -24);
1978                        pChannel->GlobalTranspose = transpose;
1979                        // workaround, so we won't have hanging notes
1980                        pChannel->ReleaseAllVoices(itRpnEvent);
1981                    } else if (itRpnEvent->Param.RPN.Parameter == 16383) { // null function RPN
1982                        // disable subsequent data entry/increment/decrement processing
1983                        pChannel->ResetMidiRpnParameter();
1984                    }
1985                }
1986    
1987                /**
1988                 * Process MIDI NRPN events with hard coded behavior.
1989                 *
1990                 * @param pEngineChannel - engine channel on which the MIDI NRPN
1991                 *                         event was received
1992                 * @param itRpnEvent - the actual MIDI NRPN event
1993                 */
1994                void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1995                                          Pool<Event>::Iterator& itNrpnEvent)
1996                {
1997                    EngineChannelBase<V, R, I>* pChannel =
1998                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1999    
2000                    switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
2001                        case 0x1a: { // volume level of note (Roland GS NRPN)
2002                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2003                            const uint vol  = itNrpnEvent->Param.NRPN.ValueMSB();
2004                            dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
2005                            if (note < 128 && vol < 128)
2006                                pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
2007                            break;
2008                        }
2009                        case 0x1c: { // panpot of note (Roland GS NRPN)
2010                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2011                            const uint pan  = itNrpnEvent->Param.NRPN.ValueMSB();
2012                            dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
2013                            if (note < 128 && pan < 128) {
2014                                pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
2015                                pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
2016                            }
2017                            break;
2018                        }
2019                        case 0x1d: { // reverb send of note (Roland GS NRPN)
2020                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2021                            const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2022                            dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
2023                            if (note < 128)
2024                                pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
2025                            break;
2026                        }
2027                        case 0x1e: { // chorus send of note (Roland GS NRPN)
2028                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2029                            const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2030                            dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
2031                            if (note < 128)
2032                                pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
2033                            break;
2034                        }
2035                        case 0x7f: {
2036                            if (itNrpnEvent->Param.NRPN.ParameterLSB() == 0x7f) { // null function NRPN
2037                                // disable subsequent data entry/increment/decrement processing
2038                                pChannel->ResetMidiNrpnParameter();
2039                            }
2040                            break;
2041                        }
2042                    }
2043              }              }
2044    
2045              virtual D* CreateDiskThread() = 0;              virtual D* CreateDiskThread() = 0;
# Line 1096  namespace LinuxSampler { Line 2047  namespace LinuxSampler {
2047              /**              /**
2048               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
2049               *               *
2050               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
2051               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
2052               */               */
2053              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
2054                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
2055                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2056    
                 //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;  
   
2057                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
2058                    const int vel = itNoteOnEvent->Param.Note.Velocity;
2059                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
2060    
2061                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2062    
2063                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
2064                    // programmatically spawned notes (Event::type_play_note). We have
2065                    // to distinguish between them, since certain processing below
2066                    // must only be done on real MIDI note-on events (i.e. for
2067                    // correctly updating which MIDI keys are currently pressed down).
2068                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
2069    
2070                    if (isRealMIDINoteOnEvent)
2071                        pChannel->listeners.PreProcessNoteOn(key, vel);
2072    
2073                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2074                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2075                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
2076                            pChannel->listeners.PostProcessNoteOn(key, vel);
2077                      return;                      return;
2078                  }                  }
2079                  #endif                  #endif
2080    
2081                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
2082                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
2083                            pChannel->listeners.PostProcessNoteOn(key, vel);
2084                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
2085                  }                  }
2086    
# Line 1130  namespace LinuxSampler { Line 2088  namespace LinuxSampler {
2088                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
2089    
2090                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
2091                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
2092                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
2093                      if (itYoungestKey) {                      if (itYoungestKey) {
2094                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1138  namespace LinuxSampler { Line 2096  namespace LinuxSampler {
2096                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
2097                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
2098                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
2099                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
2100                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
2101                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
2102                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
2103                                    }
2104                              }                              }
2105                              // kill all voices on the (other) key                              // kill all voices on the (other) key
2106                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
2107                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2108                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
2109                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2110                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2111                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
2112                                    }
2113                              }                              }
2114                          }                          }
2115                      }                      }
# Line 1154  namespace LinuxSampler { Line 2117  namespace LinuxSampler {
2117                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
2118                  }                  }
2119    
2120                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
2121                        pChannel->ProcessKeySwitchChange(key);
2122    
2123                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
2124                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
2125                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
2126                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
2127                    }
2128    
2129                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
2130                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
2131                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
2132                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
2133                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
2134                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
2135                      }                      }
2136                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
2137                  }                  }
# Line 1176  namespace LinuxSampler { Line 2142  namespace LinuxSampler {
2142                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2143                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
2144    
2145                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
2146                        pChannel->PortamentoPos = (float) key;
2147    
2148                    //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?
2149                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
2150                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
2151                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
2152                  }                  }
2153                  pChannel->listeners.PostProcessNoteOn(key, vel);  
2154                    if (isRealMIDINoteOnEvent)
2155                        pChannel->listeners.PostProcessNoteOn(key, vel);
2156              }              }
2157    
2158              /**              /**
# Line 1207  namespace LinuxSampler { Line 2178  namespace LinuxSampler {
2178               *  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.
2179               *  due to completion of sample playback).               *  due to completion of sample playback).
2180               *               *
2181               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
2182               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
2183               */               */
2184              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
2185                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2186    
                 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;  
   
2187                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
2188                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
2189                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2190    
2191                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2192    
2193                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
2194                    // programmatically spawned notes (Event::type_stop_note). We have
2195                    // to distinguish between them, since certain processing below
2196                    // must only be done on real MIDI note-off events (i.e. for
2197                    // correctly updating which MIDI keys are currently pressed down),
2198                    // plus a stop-note event just releases voices of one particular
2199                    // note, whereas a note-off event releases all voices on a
2200                    // particular MIDI key instead.
2201                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2202    
2203                    if (isRealMIDINoteOffEvent)
2204                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
2205    
2206                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2207                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2208                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
2209                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
2210                      return;                      return;
2211                  }                  }
2212                  #endif                  #endif
2213    
2214                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
2215                        pKey->KeyPressed = false; // the MIDI key was now released
2216                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2217                    }
2218    
2219                  // move event to the key's own event list                  // move event to the key's own event list
2220                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2221    
2222                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
2223                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2224    
2225                  // 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)
2226                  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
2227                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
2228                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
2229                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
2230                          // 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
2231                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
2232                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2233                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
2234                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
2235                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
2236                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
2237                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
2238                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
2239                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
2240                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
2241                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
2242                                  // create a pseudo note on event                                      }
2243                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
2244                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2245                                      // copy event                                      if (itPseudoNoteOnEvent) {
2246                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
2247                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2248                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
2249                                      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)
2250                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
2251                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2252                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
2253                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2254                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
2255                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2256                                            }
2257                                            // if neither a voice was spawned or postponed then remove note on event from key again
2258                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2259                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2260    
2261                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
2262                                  break; // done                                      break; // done
2263                                    }
2264                              }                              }
2265                          }                          }
2266                      }                          if (bOtherKeysPressed) {
2267                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
2268                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
2269                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2270                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2271                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
2272                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2273                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2274                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2275                                        }
2276                                    }
2277                              }                              }
2278                          }                          } else pChannel->PortamentoPos = -1.0f;
2279                      } 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  
2280    
2281                      // 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
2282                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
2283                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2284                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
2285                            if (pKey->ReleaseTrigger & release_trigger_noteoff)
2286                                ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2287                        }
2288                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2289                        // This programmatically caused event is caused by a call to
2290                        // the built-in instrument script function note_off(). In
2291                        // contrast to a real MIDI note-off event the stop-note
2292                        // event just intends to release voices of one particular note.
2293                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2294                        if (pNote) { // the requested note is still alive ...
2295                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2296                        } else { // note is dead and gone ..
2297                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2298                            return; // prevent event to be removed a 2nd time below
2299                      }                      }
2300                  }                  }
2301    
# Line 1304  namespace LinuxSampler { Line 2303  namespace LinuxSampler {
2303                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2304                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
2305    
2306                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
2307                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
2308                }
2309    
2310                /**
2311                 * Called on sustain pedal up events to check and if required,
2312                 * launch release trigger voices on the respective active key.
2313                 *
2314                 * @param pEngineChannel - engine channel on which this event occurred on
2315                 * @param itEvent - release trigger event (contains note number)
2316                 */
2317                virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2318                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2319    
2320                    const int iKey = itEvent->Param.Note.Key;
2321                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2322    
2323                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2324    
2325                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
2326                }
2327    
2328                /**
2329                 * Called on note-off and sustain pedal up events to check and if
2330                 * required, launch release trigger voices on the respective active
2331                 * key.
2332                 *
2333                 * @param pEngineChannel - engine channel on which this event occurred on
2334                 * @param itEvent - note off event / release trigger event
2335                 * @param pKey - key on which the release trigger voices shall be spawned
2336                 */
2337                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2338                    // spawn release triggered voice(s) if needed
2339                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2340                        // assign a new note to this release event
2341                        if (LaunchNewNote(pChannel, itEvent)) {
2342                            // allocate and trigger new release voice(s)
2343                            TriggerReleaseVoices(pChannel, itEvent);
2344                        }
2345                        pKey->ReleaseTrigger = release_trigger_none;
2346                    }
2347                }
2348    
2349                /**
2350                 * Called on "kill note" events, which currently only happens on
2351                 * built-in real-time instrument script function fade_out(). This
2352                 * method only fulfills one task: moving the even to the Note's own
2353                 * event list so that its voices can process the kill event sample
2354                 * accurately.
2355                 */
2356                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2357                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2358    
2359                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2360                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2361    
2362                    // move note kill event to its MIDI key
2363                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2364                    itEvent.moveToEndOf(pKey->pEvents);
2365                }
2366    
2367                /**
2368                 * Called on note synthesis parameter change events. These are
2369                 * internal events caused by calling built-in real-time instrument
2370                 * script functions like change_vol(), change_tune(), etc.
2371                 *
2372                 * This method performs two tasks:
2373                 *
2374                 * - It converts the event's relative values changes (Deltas) to
2375                 *   the respective final new synthesis parameter value (AbsValue),
2376                 *   for that particular moment of the event that is.
2377                 *
2378                 * - It moves the individual events to the Note's own event list
2379                 *   (or actually to the event list of the MIDI key), so that
2380                 *   voices can process those events sample accurately.
2381                 *
2382                 * @param pEngineChannel - engine channel on which this event occurred on
2383                 * @param itEvent - note synthesis parameter change event
2384                 */
2385                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2386                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2387    
2388                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2389                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2390    
2391                    switch (itEvent->Param.NoteSynthParam.Type) {
2392                        case Event::synth_param_volume:
2393                            pNote->apply(itEvent, &NoteBase::_Override::Volume);
2394                            break;
2395                        case Event::synth_param_volume_time:
2396                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2397                            break;
2398                        case Event::synth_param_volume_curve:
2399                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2400                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2401                            break;
2402                        case Event::synth_param_pitch:
2403                            pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2404                            break;
2405                        case Event::synth_param_pitch_time:
2406                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2407                            break;
2408                        case Event::synth_param_pitch_curve:
2409                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2410                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2411                            break;
2412                        case Event::synth_param_pan:
2413                            pNote->apply(itEvent, &NoteBase::_Override::Pan);
2414                            break;
2415                        case Event::synth_param_pan_time:
2416                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2417                            break;
2418                        case Event::synth_param_pan_curve:
2419                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2420                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2421                            break;
2422                        case Event::synth_param_cutoff:
2423                            pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2424                            break;
2425                        case Event::synth_param_resonance:
2426                            pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2427                            break;
2428                        case Event::synth_param_attack:
2429                            pNote->apply(itEvent, &NoteBase::_Override::Attack);
2430                            break;
2431                        case Event::synth_param_decay:
2432                            pNote->apply(itEvent, &NoteBase::_Override::Decay);
2433                            break;
2434                        case Event::synth_param_sustain:
2435                            pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2436                            break;
2437                        case Event::synth_param_release:
2438                            pNote->apply(itEvent, &NoteBase::_Override::Release);
2439                            break;
2440    
2441                        case Event::synth_param_cutoff_attack:
2442                            pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2443                            break;
2444                        case Event::synth_param_cutoff_decay:
2445                            pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2446                            break;
2447                        case Event::synth_param_cutoff_sustain:
2448                            pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2449                            break;
2450                        case Event::synth_param_cutoff_release:
2451                            pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2452                            break;
2453    
2454                        case Event::synth_param_amp_lfo_depth:
2455                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2456                            break;
2457                        case Event::synth_param_amp_lfo_freq:
2458                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2459                            break;
2460                        case Event::synth_param_cutoff_lfo_depth:
2461                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2462                            break;
2463                        case Event::synth_param_cutoff_lfo_freq:
2464                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2465                            break;
2466                        case Event::synth_param_pitch_lfo_depth:
2467                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2468                            break;
2469                        case Event::synth_param_pitch_lfo_freq:
2470                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2471                            break;
2472                    }
2473    
2474                    // move note parameter event to its MIDI key
2475                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2476                    itEvent.moveToEndOf(pKey->pEvents);
2477              }              }
2478    
2479              /**              /**
2480               *  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
2481               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2482               */               */
2483              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2484                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
2485    
2486                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
2487                  // while it's reseting                  // while it's reseting
# Line 1324  namespace LinuxSampler { Line 2493  namespace LinuxSampler {
2493                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2494                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2495                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2496                    itLastStolenNote           = NoteIterator();
2497                    itLastStolenNoteGlobally   = NoteIterator();
2498                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2499                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2500                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2501    
2502                    // reset all notes
2503                    pNotePool->clear();
2504                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2505                         itNote = pNotePool->allocAppend())
2506                    {
2507                        itNote->reset();
2508                    }
2509                    pNotePool->clear();
2510    
2511                  // reset all voices                  // reset all voices
2512                    pVoicePool->clear();
2513                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2514                      iterVoice->Reset();                      iterVoice->Reset();
2515                  }                  }
2516                  pVoicePool->clear();                  pVoicePool->clear();
2517    
2518                    // reset all engine channels
2519                    for (int i = 0; i < engineChannels.size(); i++) {
2520                        AbstractEngineChannel* pEngineChannel =
2521                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2522                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2523                    }
2524    
2525                  // reset disk thread                  // reset disk thread
2526                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2527    
# Line 1341  namespace LinuxSampler { Line 2529  namespace LinuxSampler {
2529                  pEventQueue->init();                  pEventQueue->init();
2530                  pSysexBuffer->init();                  pSysexBuffer->init();
2531                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
2532              }              }
2533    
2534              /**              /**
# Line 1352  namespace LinuxSampler { Line 2539  namespace LinuxSampler {
2539               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2540               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2541               */               */
2542              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2543                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2544                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2545                  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 1363  namespace LinuxSampler { Line 2550  namespace LinuxSampler {
2550               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2551               *  (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).
2552               *               *
2553               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2554               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2555               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2556               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1387  namespace LinuxSampler { Line 2574  namespace LinuxSampler {
2574                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2575              ) = 0;              ) = 0;
2576    
2577              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2578    
2579              int InitNewVoice (              int InitNewVoice (
2580                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1406  namespace LinuxSampler { Line 2593  namespace LinuxSampler {
2593                      // launch the new voice                      // launch the new voice
2594                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2595                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2596                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2597                      }                      }
2598                      else { // on success                      else { // on success
2599                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2600                          if (!pKey->Active) { // mark as active key  
2601                              pKey->Active = true;                          // should actually be superfluous now, since this is
2602                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2603                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2604                          }  
2605                          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)
2606                                pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2607                          return 0; // success                          return 0; // success
2608                      }                      }
2609                  }                  }
# Line 1437  namespace LinuxSampler { Line 2625  namespace LinuxSampler {
2625    
2626                  return -1;                  return -1;
2627              }              }
2628                
2629                /**
2630                 * Checks whether scale tuning setting has been changed since last
2631                 * time this method was called, if yes, it recalculates the pitch
2632                 * for all active voices.
2633                 */
2634                void ProcessScaleTuningChange() {
2635                    const bool changed = ScaleTuningChanged.readAndReset();
2636                    if (!changed) return;
2637                    
2638                    for (int i = 0; i < engineChannels.size(); i++) {
2639                        EngineChannelBase<V, R, I>* channel =
2640                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2641                        channel->OnScaleTuningChanged();
2642                    }
2643                }
2644    
2645          private:          private:
2646                Pool< Note<V> >* pNotePool;
2647                Pool<note_id_t> noteIDPool;
2648              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2649              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2650              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2244  
changed lines
  Added in v.3704

  ViewVC Help
Powered by ViewVC