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

Legend:
Removed from v.2327  
changed lines
  Added in v.3706

  ViewVC Help
Powered by ViewVC