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

Legend:
Removed from v.2298  
changed lines
  Added in v.3696

  ViewVC Help
Powered by ViewVC