/[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 2015 by iliev, Sun Oct 25 22:22:52 2009 UTC revision 2938 by schoenebeck, Mon Jul 11 17:10:40 2016 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2016 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() : SuspendedRegions(128), noteIDPool(GLOBAL_MAX_NOTES) {
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 143  namespace LinuxSampler { Line 166  namespace LinuxSampler {
166                          }                          }
167                      }                      }
168                  }                  }
169                    
170                    // In case scale tuning has been changed, recalculate pitch for
171                    // all active voices.
172                    ProcessScaleTuningChange();
173    
174                  // reset internal voice counter (just for statistic of active voices)                  // reset internal voice counter (just for statistic of active voices)
175                  ActiveVoiceCountTemp = 0;                  ActiveVoiceCountTemp = 0;
# Line 190  namespace LinuxSampler { Line 217  namespace LinuxSampler {
217                  // been deleted by the disk thread                  // been deleted by the disk thread
218                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
219    
220                    // Release the instrument change command. (This has to
221                    // be done after all voices have been rendered and not
222                    // in HandleInstrumentChanges, as the RegionsInUse
223                    // list has been built up by the voice renderers.)
224                    for (int i = 0; i < engineChannels.size(); i++) {
225                        EngineChannelBase<V, R, I>* channel =
226                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
227                        channel->InstrumentChangeCommandReader.Unlock();
228                    }
229                  FrameTime += Samples;                  FrameTime += Samples;
230    
231                  EngineDisabled.RttDone();                  EngineDisabled.RttDone();
232                  return 0;                  return 0;
233              }              }
234    
235              virtual int MaxVoices() { return pVoicePool->poolSize(); }              virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
236    
237              virtual void SetMaxVoices(int iVoices) throw (Exception) {              virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
238                  if (iVoices < 1)                  if (iVoices < 1)
239                      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");
240    
# Line 222  namespace LinuxSampler { Line 258  namespace LinuxSampler {
258                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
259                  }                  }
260    
261                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
262                  try {                  try {
263                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
264                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
265                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
266                  } catch (...) {                  } catch (...) {
267                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
268                  }                  }
269    
270                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
271                         iterVoice; iterVoice = pVoicePool->allocAppend())
272                    {
273                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
274                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
275                  }                  }
276                  pVoicePool->clear();                  pVoicePool->clear();
277    
278                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
279                         itNote = pNotePool->allocAppend())
280                    {
281                        itNote->init(pVoicePool, &noteIDPool);
282                    }
283                    pNotePool->clear();
284    
285                    PostSetMaxVoices(iVoices);
286                  ResumeAll();                  ResumeAll();
287              }              }
288                
289                /** Called after the new max number of voices is set and before resuming the engine. */
290                virtual void PostSetMaxVoices(int iVoices) { }
291    
292              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
293              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
294              virtual int  MaxDiskStreams() { return iMaxDiskStreams; }              virtual int  MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
295    
296              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
297                  if (iStreams < 0)                  if (iStreams < 0)
298                      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");
299    
# Line 256  namespace LinuxSampler { Line 308  namespace LinuxSampler {
308                  ResumeAll();                  ResumeAll();
309              }              }
310    
311              virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }              virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
312              virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }              virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
313              virtual InstrumentManager* GetInstrumentManager() { return &instruments; }              virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
314    
315              /**              /**
316               * Connect this engine instance with the given audio output device.               * Connect this engine instance with the given audio output device.
# Line 269  namespace LinuxSampler { Line 321  namespace LinuxSampler {
321               *               *
322               * @param pAudioOut - audio output device to connect to               * @param pAudioOut - audio output device to connect to
323               */               */
324              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
325                  // caution: don't ignore if connecting to the same device here,                  // caution: don't ignore if connecting to the same device here,
326                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!
327    
# Line 298  namespace LinuxSampler { Line 350  namespace LinuxSampler {
350                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
351                      // lower minimum release time                      // lower minimum release time
352                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
353                        pVoicePool->clear();
354                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
355                          iterVoice->EG1.CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
356                      }                      }
357                      pVoicePool->clear();                      pVoicePool->clear();
358                  }                  }
# Line 318  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
372                  }                  }
373    
374                    pVoicePool->clear();
375                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
376                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
377                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 332  namespace LinuxSampler { Line 386  namespace LinuxSampler {
386                  pDiskThread->StartThread();                  pDiskThread->StartThread();
387                  dmsg(1,("OK\n"));                  dmsg(1,("OK\n"));
388    
389                    bool printEqInfo = true;
390                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
391                      if (!iterVoice->pDiskThread) {                      if (!iterVoice->pDiskThread) {
392                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
393                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
394                      }                      }
395                        
396                        iterVoice->CreateEq();
397                        
398                        if(printEqInfo) {
399                            iterVoice->PrintEqInfo();
400                            printEqInfo = false;
401                        }
402                  }                  }
403                  pVoicePool->clear();                  pVoicePool->clear();
404                    
405                    // (re)create dedicated voice audio buffers
406                    //TODO: we could optimize resource usage a bit by just allocating these dedicated voice buffers when there is at least one engine channel with FX sends, because only in this case those special buffers are used actually, but since it would usually only save couple bytes in total, its probably not worth it
407                    if (pDedicatedVoiceChannelLeft)  delete pDedicatedVoiceChannelLeft;
408                    if (pDedicatedVoiceChannelRight) delete pDedicatedVoiceChannelRight;
409                    pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
410                    pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
411                }
412            
413                // Implementattion for abstract method derived from Engine.
414                virtual void ReconnectAudioOutputDevice() OVERRIDE {
415                    SuspendAll();
416                    if (pAudioOutputDevice) Connect(pAudioOutputDevice);
417                    ResumeAll();
418              }              }
419    
420              /**              /**
# Line 393  namespace LinuxSampler { Line 469  namespace LinuxSampler {
469               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
470               */               */
471              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
472                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
473                  SuspendedRegionsMutex.Lock();                  {
474                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
475                  pPendingRegionSuspension = pRegion;                      SuspensionChangeOngoing.Set(true);
476                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionSuspension = pRegion;
477                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
478                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  }
479                    dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
480              }              }
481    
482              /**              /**
# Line 409  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
487               */               */
488              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
489                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
490                  SuspendedRegionsMutex.Lock();                  {
491                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
492                  pPendingRegionResumption = pRegion;                      SuspensionChangeOngoing.Set(true);
493                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionResumption = pRegion;
494                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  }
496                    dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
497              }              }
498    
499              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 523  namespace LinuxSampler { Line 601  namespace LinuxSampler {
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
611              //friend class EngineChannelBase<V, R, I>;              //friend class EngineChannelBase<V, R, I>;
612    
613                static IM instruments;
614    
615          protected:          protected:
616              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
617              public:              public:
618                  int PendingStreamDeletions;                  int PendingStreamDeletions;
619                  RR* pPendingRegionSuspension;                  RR* pPendingRegionSuspension;
620    
621                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
622                      PendingStreamDeletions = 0;                      PendingStreamDeletions = 0;
623                      this->pPendingRegionSuspension = pPendingRegionSuspension;                      this->pPendingRegionSuspension = pPendingRegionSuspension;
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
632                      return true;                      return true;
633                  }                  }
634    
635                  virtual void Process(VoiceIterator& itVoice) {                  virtual void Process(VoiceIterator& itVoice) OVERRIDE {
636                      // request a notification from disk thread side for stream deletion                      // request a notification from disk thread side for stream deletion
637                      const Stream::Handle hStream = itVoice->KillImmediately(true);                      const Stream::Handle hStream = itVoice->KillImmediately(true);
638                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
# Line 558  namespace LinuxSampler { Line 642  namespace LinuxSampler {
642                  }                  }
643              };              };
644    
             static IM instruments;  
   
645              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
646              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
647              D*        pDiskThread;              D*        pDiskThread;
648    
             int                          VoiceSpawnsLeft;       ///< We only allow CONFIG_MAX_VOICES voices to be spawned per audio fragment, we use this variable to ensure this limit.  
649              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)
650              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.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              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.
653              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.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              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.
658              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).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // usually the new note (and its subsequent voices) will be
693                    // allocated on the key provided by the event's note number,
694                    // however if this new note is requested not to be a regular
695                    // note, but rather a child note, then this new note will be
696                    // allocated on the parent note's key instead in order to
697                    // release the child note simultaniously with its parent note
698                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
699    
700                    // in case this new note was requested to be a child note,
701                    // then retrieve its parent note and link them with each other
702                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
703                    if (parentNoteID) {
704                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
705                        if (itParentNote) {
706                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
707                            if (itChildNoteID) {
708                                // link parent and child note with each other
709                                *itChildNoteID = newNoteID;
710                                itNewNote->parentNoteID = parentNoteID;
711                                itNewNote->hostKey = itParentNote->hostKey;
712                            } else {    
713                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
714                                pNotePool->free(itNewNote);
715                                return 0; // error
716                            }
717                        } else {
718                            // the parent note was apparently released already, so
719                            // free the new note again and inform caller that it
720                            // should drop the event
721                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
722                            pNotePool->free(itNewNote);
723                            return 0; // error
724                        }
725                    }
726    
727                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
728    
729                    // copy event which caused this note
730                    itNewNote->cause = *pNoteOnEvent;
731                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
732    
733                    // move new note to its host key
734                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
735                    itNewNote.moveToEndOf(pKey->pActiveNotes);
736    
737                    // assign unique note ID of this new note to the original note on event
738                    pNoteOnEvent->Param.Note.ID = newNoteID;
739    
740                    return newNoteID; // success
741                }
742    
743              /**              /**
744               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
745               * engine channel.               * engine channel.
# Line 590  namespace LinuxSampler { Line 755  namespace LinuxSampler {
755                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
756                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
757    
758                  // process events                  // if a valid real-time instrument script is loaded, pre-process
759                    // the event list by running the script now, since the script
760                    // might filter events or add new ones for this cycle
761                    if (pChannel->pScript) {
762                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
763    
764                        // resume suspended script executions been scheduled for
765                        // this audio fragment cycle (which were suspended in a
766                        // previous audio fragment cycle)
767                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
768    
769                        // spawn new script executions for the new MIDI events of
770                        // this audio fragment cycle
771                        //
772                        // 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
773                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
774                            end = pChannel->pEvents->end(); itEvent != end; )
775                        {
776                            //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).
777                            RTList<Event>::Iterator itNext = itEvent;
778                            ++itNext;
779    
780                            switch (itEvent->Type) {
781                                case Event::type_note_on:
782                                    if (pChannel->pScript->handlerNote)
783                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
784                                    break;
785                                case Event::type_note_off:
786                                    if (pChannel->pScript->handlerRelease)
787                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
788                                    break;
789                                case Event::type_control_change:
790                                case Event::type_channel_pressure:
791                                case Event::type_pitchbend:
792                                    if (pChannel->pScript->handlerController)
793                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
794                                    break;
795                                case Event::type_note_pressure:
796                                    //TODO: ...
797                                    break;
798                            }
799    
800                            // see HACK comment above
801                            itEvent = itNext;
802                        }
803    
804                        // this has to be run again, since the newly spawned scripts
805                        // above may have cause suspended scripts that must be
806                        // resumed within this same audio fragment cycle
807                        //
808                        // FIXME: see FIXME comment above
809                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
810                    }
811    
812                    // if there are any delayed events scheduled for the current
813                    // audio fragment cycle, then move and sort them into the main
814                    // event list
815                    if (!pChannel->delayedEvents.queue.isEmpty()) {
816                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
817                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
818                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
819                        while (true) {
820                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
821                                pEventGenerator->popNextScheduledEvent(
822                                    pChannel->delayedEvents.queue,
823                                    pChannel->delayedEvents.schedulerNodes,
824                                    fragmentEndTime
825                                );
826                            if (!itDelayedEventNode) break;
827                            // get the actual delayed event object and free the used scheduler node
828                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
829                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
830                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
831                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
832                                continue;
833                            }
834                            // skip all events on main event list which have a time
835                            // before (or equal to) the delayed event to be inserted
836                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
837                                 ++itEvent);
838                            // now move delayed event from delayedEvents.pList to
839                            // the current position on the main event list
840                            itEvent = itDelayedEvent.moveBefore(itEvent);
841                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
842                        }
843                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
844                    }
845    
846                    // now process all events regularly
847                  {                  {
848                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
849                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 600  namespace LinuxSampler { Line 853  namespace LinuxSampler {
853                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
854                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
855                                  break;                                  break;
856                                case Event::type_play_note:
857                                    dmsg(5,("Engine: Play Note received\n"));
858                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
859                                    break;
860                              case Event::type_note_off:                              case Event::type_note_off:
861                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
862                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
863                                  break;                                  break;
864                                case Event::type_stop_note:
865                                    dmsg(5,("Engine: Stop Note received\n"));
866                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
867                                    break;
868                              case Event::type_control_change:                              case Event::type_control_change:
869                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
870                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
871                                  break;                                  break;
872                                case Event::type_channel_pressure:
873                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
874                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
875                                    break;
876                                case Event::type_note_pressure:
877                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
878                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
879                                    break;
880                              case Event::type_pitchbend:                              case Event::type_pitchbend:
881                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
882                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
883                                  break;                                  break;
884                                case Event::type_note_synth_param:
885                                    dmsg(5,("Engine: Note Synth Param received\n"));
886                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
887                                    break;
888                          }                          }
889                      }                      }
890                  }                  }
# Line 619  namespace LinuxSampler { Line 892  namespace LinuxSampler {
892                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
893                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
894                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
895                    itLastStolenNote          = NoteIterator();
896                    itLastStolenNoteGlobally  = NoteIterator();
897                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
898                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
899                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
900              }              }
901    
902              /**              /**
903                 * Run all suspended script execution instances which are scheduled
904                 * to be resumed for the current audio fragment cycle.
905                 *
906                 * @param pChannel - engine channel on which suspended events occurred
907                 */
908                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
909                    while (true) {
910                        RTList<ScriptEvent>::Iterator itEvent =
911                            pEventGenerator->popNextScheduledScriptEvent(
912                                pChannel->pScript->suspendedEvents,
913                                *pChannel->pScript->pEvents, fragmentEndTime
914                            );
915                        if (!itEvent) break;
916                        ResumeScriptEvent(pChannel, itEvent);
917                    }
918                }
919    
920                /** @brief Call instrument script's event handler for this event.
921                 *
922                 * Causes a new execution instance of the currently loaded real-time
923                 * instrument script's event handler (callback) to be spawned for
924                 * the given MIDI event.
925                 *
926                 * @param pChannel - engine channel on which the MIDI event occurred
927                 * @param itEvent - MIDI event that causes this new script execution
928                 * @param pEventHandler - script's event handler to be executed
929                 */
930                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
931                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
932                    // check if polyphonic data is passed from "note" to "release"
933                    // script event handlers
934                    if (pEventHandler == pChannel->pScript->handlerRelease &&
935                        pChannel->pScript->handlerNote &&
936                        pChannel->pScript->handlerNote->isPolyphonic() &&
937                        pChannel->pScript->handlerRelease->isPolyphonic() &&
938                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
939                    {
940                        // polyphonic variable data is used/passed from "note" to
941                        // "release" script callback, so we have to recycle the
942                        // original "note on" script event(s)
943                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
944                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
945                        for (; it != end; ++it) {
946                            ProcessScriptEvent(
947                                pChannel, itEvent, pEventHandler, it
948                            );
949                        }
950                    } else {
951                        // no polyphonic data is used/passed from "note" to
952                        // "release" script callback, so just use a new fresh
953                        // script event object
954                        RTList<ScriptEvent>::Iterator itScriptEvent =
955                            pChannel->pScript->pEvents->allocAppend();
956                        ProcessScriptEvent(
957                            pChannel, itEvent, pEventHandler, itScriptEvent
958                        );
959                    }
960                }
961    
962                /** @brief Spawn new execution instance of an instrument script handler.
963                 *
964                 * Will be called to initiate a new execution of a real-time
965                 * instrument script event right from the start of the script's
966                 * respective handler. If script execution did not complete after
967                 * calling this method, the respective script exeuction is then
968                 * suspended and a call to ResumeScriptEvent() will be used next
969                 * time to continue its execution.
970                 *
971                 * @param pChannel - engine channel this script is running for
972                 * @param itEvent - event which caused execution of this script
973                 *                  event handler
974                 * @param pEventHandler - VM representation of event handler to be
975                 *                        executed
976                 * @param itScriptEvent - script event that shall be processed
977                 */
978                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
979                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
980    
981                    // fill the list of script handlers to be executed by this event
982                    int i = 0;
983                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
984                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
985    
986                    // initialize/reset other members
987                    itScriptEvent->cause = *itEvent;
988                    itScriptEvent->currentHandler = 0;
989                    itScriptEvent->executionSlices = 0;
990                    // this is the native representation of the $EVENT_ID script variable
991                    itScriptEvent->id =
992                        (itEvent->Type == Event::type_note_on)
993                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
994                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
995    
996                    // run script handler(s)
997                    VMExecStatus_t res = pScriptVM->exec(
998                        pChannel->pScript->parserContext, &*itScriptEvent
999                    );
1000    
1001                    // was the script suspended?
1002                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1003                        // in case the script was suspended, keep it on the allocated
1004                        // ScriptEvent list to be resume at the scheduled time in future,
1005                        // additionally insert it into a sorted time queue
1006                        pEventGenerator->scheduleAheadMicroSec(
1007                            pChannel->pScript->suspendedEvents, // scheduler queue
1008                            *itScriptEvent, // script event
1009                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1010                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1011                        );
1012                    } else { // script execution has finished without 'suspended' status ...
1013                        // if "polyphonic" variable data is passed from script's
1014                        // "note" event handler to its "release" event handler, then
1015                        // the script event must be kept and recycled for the later
1016                        // occuring "release" script event ...
1017                        if (pEventHandler == pChannel->pScript->handlerNote &&
1018                            pChannel->pScript->handlerRelease &&
1019                            pChannel->pScript->handlerNote->isPolyphonic() &&
1020                            pChannel->pScript->handlerRelease->isPolyphonic())
1021                        {
1022                            const int key = itEvent->Param.Note.Key;
1023                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1024                        } else {
1025                            // ... otherwise if no polyphonic data is passed and
1026                            // script's execution has finished without suspension
1027                            // status, then free the script event for a new future
1028                            // script event to be triggered from start
1029                            pChannel->pScript->pEvents->free(itScriptEvent);
1030                        }
1031                    }
1032                }
1033    
1034                /** @brief Resume execution of instrument script.
1035                 *
1036                 * Will be called to resume execution of a real-time instrument
1037                 * script event which has been suspended previously.
1038                 *
1039                 * Script execution might be suspended for various reasons. Usually
1040                 * a script will be suspended if the script called the built-in
1041                 * "wait()" function, but it might also be suspended automatically
1042                 * if the script took too much execution time in an audio fragment
1043                 * cycle. So in the latter case automatic suspension is performed in
1044                 * order to avoid harm for the sampler's overall real-time
1045                 * requirements.
1046                 *
1047                 * @param pChannel - engine channel this script is running for
1048                 * @param itScriptEvent - script execution that shall be resumed
1049                 */
1050                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1051                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1052    
1053                    // run script
1054                    VMExecStatus_t res = pScriptVM->exec(
1055                        pChannel->pScript->parserContext, &*itScriptEvent
1056                    );
1057    
1058                    // was the script suspended?
1059                    if (res & VM_EXEC_SUSPENDED) {
1060                        // in case the script was suspended, keep it on the allocated
1061                        // ScriptEvent list to be resume at the scheduled time in future,
1062                        // additionally insert it into a sorted time queue
1063                        pEventGenerator->scheduleAheadMicroSec(
1064                            pChannel->pScript->suspendedEvents, // scheduler queue
1065                            *itScriptEvent, // script event
1066                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1067                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1068                        );
1069                    } else { // script execution has finished without 'suspended' status ...
1070                        // if "polyphonic" variable data is passed from script's
1071                        // "note" event handler to its "release" event handler, then
1072                        // the script event must be kept and recycled for the later
1073                        // occuring "release" script event ...
1074                        if (handler && handler == pChannel->pScript->handlerNote &&
1075                            pChannel->pScript->handlerRelease &&
1076                            pChannel->pScript->handlerNote->isPolyphonic() &&
1077                            pChannel->pScript->handlerRelease->isPolyphonic())
1078                        {
1079                            const int key = itScriptEvent->cause.Param.Note.Key;
1080                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1081                        } else {
1082                            // ... otherwise if no polyphonic data is passed and
1083                            // script's execution has finished without suspension
1084                            // status, then free the script event for a new future
1085                            // script event to be triggered from start
1086                            pChannel->pScript->pEvents->free(itScriptEvent);
1087                        }
1088                    }
1089                }
1090    
1091                /**
1092               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1093               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1094               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1095               *  voice actually died.               *  voice actually died.
1096               *               *
1097               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1098               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1099               *  @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
1100               */               */
1101              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1102                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1103                      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"));
1104                      return -1;                      return -1;
# Line 642  namespace LinuxSampler { Line 1106  namespace LinuxSampler {
1106    
1107                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1108    
1109                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1110                        dmsg(1,("Event pool emtpy!\n"));
1111                        return -1;
1112                    }
1113    
1114                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1115                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1116                          return 0;                      return 0;
1117                      }                  }
1118    
1119                      // 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
1120                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1121                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1122                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1123                      int                       iChannelIndex;                  int                          iChannelIndex;
1124                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1125    
1126                      // select engine channel                  // select engine channel
1127                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1128                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1129                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1130                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1131                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1132                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1133                      }                  }
1134    
1135                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1136                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1137                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1138                          do {                      do {
1139                              ++itSelectedVoice;                          ++itSelectedVoice;
1140                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1141                    }
1142                    // did we find a 'stealable' voice?
1143                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1144                        // remember which voice we stole, so we can simply proceed on next voice stealing
1145                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1146                        // done
1147                        goto stealable_voice_found;
1148                    }
1149    
1150                    // get (next) oldest note
1151                    if (this->itLastStolenNoteGlobally) {
1152                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1153                             itNote; ++itNote)
1154                        {
1155                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1156                                // proceed iterating if voice was created in this audio fragment cycle
1157                                if (itSelectedVoice->IsStealable()) {
1158                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1159                                    this->itLastStolenNoteGlobally  = itNote;
1160                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1161                                    goto stealable_voice_found; // selection succeeded
1162                                }
1163                            }
1164                      }                      }
1165                    }
1166    
1167                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1168                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1169                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1170    
1171                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1172                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1173                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1174                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1175                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1176                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1177                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1178                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1179                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1180                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1181                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1182                                itSelectedVoice = itNote->pActiveVoices->first();
1183                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1184                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1185                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1186                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1187                                  // 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
1188                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1189                                    this->itLastStolenNoteGlobally  = itNote;
1190                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1191                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1192                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1193                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1194                          }                          }
1195                          // 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  
1196                      }                      }
1197                        // get next engine channel
1198                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1199                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1200    
1201                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1202                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1203                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1204                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1205                            dmsg(1,("Exiting.\n"));
1206                            exit(-1);
1207                      }                      }
1208                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1209                    }
1210    
1211                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1212                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
1213    
1214                      --VoiceSpawnsLeft;                  #if CONFIG_DEVMODE
1215                    if (!itSelectedVoice->IsActive()) {
1216                      return 0; // success                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                 }  
                 else {  
                     dmsg(1,("Event pool emtpy!\n"));  
1217                      return -1;                      return -1;
1218                  }                  }
1219                    #endif // CONFIG_DEVMODE
1220    
1221                    // now kill the selected voice
1222                    itSelectedVoice->Kill(itNoteOnEvent);
1223    
1224                    --VoiceSpawnsLeft;
1225    
1226                    return 0; // success
1227              }              }
1228    
1229              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 756  namespace LinuxSampler { Line 1245  namespace LinuxSampler {
1245                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1246                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1247                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1248                            pEngineChannel->pScript =
1249                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1250                          instrumentChanged = true;                          instrumentChanged = true;
1251    
1252                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1253    
1254                            // the script's "init" event handler is only executed
1255                            // once (when the script is loaded or reloaded)
1256                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1257                                RTList<ScriptEvent>::Iterator itScriptEvent =
1258                                    pEngineChannel->pScript->pEvents->allocAppend();
1259    
1260                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1261                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1262                                itScriptEvent->handlers[1] = NULL;
1263    
1264                                VMExecStatus_t res = pScriptVM->exec(
1265                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
1266                                );
1267    
1268                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1269                            }
1270                      }                      }
1271                  }                  }
1272    
# Line 766  namespace LinuxSampler { Line 1274  namespace LinuxSampler {
1274                      //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions                      //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
1275                      ResetSuspendedRegions();                      ResetSuspendedRegions();
1276                  }                  }
   
                 for (int i = 0; i < engineChannels.size(); i++) {  
                     EngineChannelBase<V, R, I>* channel =  
                         static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);  
                     channel->InstrumentChangeCommandReader.Unlock();  
                 }  
1277              }              }
1278    
1279              /**              /**
# Line 815  namespace LinuxSampler { Line 1317  namespace LinuxSampler {
1317                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1318                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1319                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1320                        
1321                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1322                          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);
1323                      if (itNewVoice) {                      if (itNewVoice) {
1324                            // usually there should already be a new Note object
1325                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1326                            if (!itNote) { // should not happen, but just to be sure ...
1327                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1328                                if (!noteID) {
1329                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1330                                    continue;
1331                                }
1332                                itNote = GetNotePool()->fromID(noteID);
1333                            }
1334                            // move voice from whereever it was, to the new note's list of active voices
1335                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1336                            // render audio of this new voice for the first time
1337                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1338                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1339                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 855  namespace LinuxSampler { Line 1371  namespace LinuxSampler {
1371                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1372    
1373                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1374                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1375                    pChannel->ClearEventListsOfCurrentFragment();
1376              }              }
1377    
1378                /**
1379                 * Process MIDI control change events with hard coded behavior,
1380                 * that is controllers whose behavior is defined independently
1381                 * of the actual sampler engine type and instrument.
1382                 *
1383                 * @param pEngineChannel - engine channel on which the MIDI CC event was received
1384                 * @param itControlChangeEvent - the actual MIDI CC event
1385                 */
1386              void ProcessHardcodedControllers (              void ProcessHardcodedControllers (
1387                  EngineChannel*          pEngineChannel,                  EngineChannel*          pEngineChannel,
1388                  Pool<Event>::Iterator&  itControlChangeEvent                  Pool<Event>::Iterator&  itControlChangeEvent
# Line 870  namespace LinuxSampler { Line 1395  namespace LinuxSampler {
1395                          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;
1396                          break;                          break;
1397                      }                      }
1398                      case 6: { // data entry (currently only used for RPN controllers)                      case 6: { // data entry (currently only used for RPN and NRPN controllers)
1399                          if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));
1400                              int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...
1401                              // limit to +- two octaves for now                              dmsg(4,("Guess it's an RPN ...\n"));
1402                              transpose = RTMath::Min(transpose,  24);                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1403                              transpose = RTMath::Max(transpose, -24);                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1404                              pChannel->GlobalTranspose = transpose;                                  // limit to +- two octaves for now
1405                              // workaround, so we won't have hanging notes                                  transpose = RTMath::Min(transpose,  24);
1406                              pChannel->ReleaseAllVoices(itControlChangeEvent);                                  transpose = RTMath::Max(transpose, -24);
1407                                    pChannel->GlobalTranspose = transpose;
1408                                    // workaround, so we won't have hanging notes
1409                                    pChannel->ReleaseAllVoices(itControlChangeEvent);
1410                                }
1411                                // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data
1412                                pChannel->ResetMidiRpnController();
1413                            } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...
1414                                dmsg(4,("Guess it's an NRPN ...\n"));
1415                                const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;
1416                                const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;
1417                                dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));
1418                                switch (NrpnCtrlMSB) {
1419                                    case 0x1a: { // volume level of note (Roland GS NRPN)
1420                                        const uint note = NrpnCtrlLSB;
1421                                        const uint vol  = itControlChangeEvent->Param.CC.Value;
1422                                        dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1423                                        if (note < 128 && vol < 128)
1424                                            pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1425                                        break;
1426                                    }
1427                                    case 0x1c: { // panpot of note (Roland GS NRPN)
1428                                        const uint note = NrpnCtrlLSB;
1429                                        const uint pan  = itControlChangeEvent->Param.CC.Value;
1430                                        dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1431                                        if (note < 128 && pan < 128) {
1432                                            pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
1433                                            pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1434                                        }
1435                                        break;
1436                                    }
1437                                    case 0x1d: { // reverb send of note (Roland GS NRPN)
1438                                        const uint note = NrpnCtrlLSB;
1439                                        const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1440                                        dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1441                                        if (note < 128)
1442                                            pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1443                                        break;
1444                                    }
1445                                    case 0x1e: { // chorus send of note (Roland GS NRPN)
1446                                        const uint note = NrpnCtrlLSB;
1447                                        const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1448                                        dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1449                                        if (note < 128)
1450                                            pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1451                                        break;
1452                                    }
1453                                }
1454                                // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data
1455                                pChannel->ResetMidiNrpnController();
1456                          }                          }
                         // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data  
                         pChannel->ResetMidiRpnController();  
1457                          break;                          break;
1458                      }                      }
1459                      case 7: { // volume                      case 7: { // volume
# Line 892  namespace LinuxSampler { Line 1464  namespace LinuxSampler {
1464                      }                      }
1465                      case 10: { // panpot                      case 10: { // panpot
1466                          //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];  
1467                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1468                          break;                          break;
1469                      }                      }
# Line 970  namespace LinuxSampler { Line 1540  namespace LinuxSampler {
1540                          }                          }
1541                          break;                          break;
1542                      }                      }
1543                        case 98: { // NRPN controller LSB
1544                            dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1545                            pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1546                            break;
1547                        }
1548                        case 99: { // NRPN controller MSB
1549                            dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1550                            pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1551                            break;
1552                        }
1553                      case 100: { // RPN controller LSB                      case 100: { // RPN controller LSB
1554                            dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1555                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1556                          break;                          break;
1557                      }                      }
1558                      case 101: { // RPN controller MSB                      case 101: { // RPN controller MSB
1559                            dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1560                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1561                          break;                          break;
1562                      }                      }
# Line 1016  namespace LinuxSampler { Line 1598  namespace LinuxSampler {
1598              /**              /**
1599               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1600               *               *
1601               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1602               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1603               */               */
1604              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1605                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1606                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1607    
                 //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;  
   
1608                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1609                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1610                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1611    
1612                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1613    
1614                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1615                    // programmatically spawned notes (Event::type_play_note). We have
1616                    // to distinguish between them, since certain processing below
1617                    // must only be done on real MIDI note-on events (i.e. for
1618                    // correctly updating which MIDI keys are currently pressed down).
1619                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1620    
1621                    if (isRealMIDINoteOnEvent)
1622                        pChannel->listeners.PreProcessNoteOn(key, vel);
1623    
1624                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1625                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1626                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1627                            pChannel->listeners.PostProcessNoteOn(key, vel);
1628                      return;                      return;
1629                  }                  }
1630                  #endif                  #endif
1631    
1632                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1633                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1634                            pChannel->listeners.PostProcessNoteOn(key, vel);
1635                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1636                  }                  }
1637    
# Line 1050  namespace LinuxSampler { Line 1639  namespace LinuxSampler {
1639                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1640    
1641                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1642                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1643                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1644                      if (itYoungestKey) {                      if (itYoungestKey) {
1645                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1058  namespace LinuxSampler { Line 1647  namespace LinuxSampler {
1647                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1648                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1649                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1650                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1651                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1652                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1653                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1654                                    }
1655                              }                              }
1656                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1657                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1658                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1659                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1660                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1661                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1662                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1663                                    }
1664                              }                              }
1665                          }                          }
1666                      }                      }
# Line 1074  namespace LinuxSampler { Line 1668  namespace LinuxSampler {
1668                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1669                  }                  }
1670    
1671                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1672                        pChannel->ProcessKeySwitchChange(key);
1673    
1674                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1675                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1676                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1677                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1678                    }
1679    
1680                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1681                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1682                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1683                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1684                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1685                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1686                      }                      }
1687                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1688                  }                  }
# Line 1096  namespace LinuxSampler { Line 1693  namespace LinuxSampler {
1693                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1694                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1695    
1696                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1697                  pKey->RoundRobinIndex++;                      pChannel->PortamentoPos = (float) key;
1698                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1699                    //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?
1700                    if (pKey->pRoundRobinIndex) {
1701                        (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1702                        pChannel->RoundRobinIndex++; // common counter for the channel
1703                    }
1704    
1705                    if (isRealMIDINoteOnEvent)
1706                        pChannel->listeners.PostProcessNoteOn(key, vel);
1707              }              }
1708    
1709              /**              /**
# Line 1124  namespace LinuxSampler { Line 1729  namespace LinuxSampler {
1729               *  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.
1730               *  due to completion of sample playback).               *  due to completion of sample playback).
1731               *               *
1732               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1733               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1734               */               */
1735              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1736                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1737    
                 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;  
   
1738                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1739                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1740                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1741    
1742                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1743    
1744                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1745                    // programmatically spawned notes (Event::type_stop_note). We have
1746                    // to distinguish between them, since certain processing below
1747                    // must only be done on real MIDI note-off events (i.e. for
1748                    // correctly updating which MIDI keys are currently pressed down),
1749                    // plus a stop-note event just releases voices of one particular
1750                    // note, whereas a note-off event releases all voices on a
1751                    // particular MIDI key instead.
1752                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1753    
1754                    if (isRealMIDINoteOffEvent)
1755                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1756    
1757                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1758                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1759                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1760                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1761                      return;                      return;
1762                  }                  }
1763                  #endif                  #endif
1764    
1765                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1766                        pKey->KeyPressed = false; // the MIDI key was now released
1767                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1768                    }
1769    
1770                  // move event to the key's own event list                  // move event to the key's own event list
1771                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1772    
1773                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1774                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1775    
1776                  // 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)
1777                  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
1778                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1779                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1780                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1781                          // 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
1782                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1783                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1784                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1785                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1786                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1787                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1788                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1789                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1790                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1791                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1792                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1793                                  // create a pseudo note on event                                      }
1794                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1795                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1796                                      // copy event                                      if (itPseudoNoteOnEvent) {
1797                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1798                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1799                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1800                                      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)
1801                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1802                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1803                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1804                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1805                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1806                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1807                                            }
1808                                            // if neither a voice was spawned or postponed then remove note on event from key again
1809                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1810                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1811    
1812                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1813                                  break; // done                                      break; // done
1814                                    }
1815                              }                              }
1816                          }                          }
1817                      }                          if (bOtherKeysPressed) {
1818                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1819                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1820                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1821                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1822                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1823                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1824                                  if (itVoiceToBeKilled->Type != Voice::type_release_trigger)                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1825                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1826                                        }
1827                                    }
1828                              }                              }
1829                          }                          } else pChannel->PortamentoPos = -1.0f;
1830                      } 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  
1831    
1832                      // 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
1833                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1834                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1835                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1836                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1837                        }
1838                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1839                        // This programmatically caused event is caused by a call to
1840                        // the built-in instrument script function note_off(). In
1841                        // contrast to a real MIDI note-off event the stop-note
1842                        // event just intends to release voices of one particular note.
1843                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1844                        if (pNote) { // the requested note is still alive ...
1845                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1846                        } else { // note is dead and gone ..
1847                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1848                            return; // prevent event to be removed a 2nd time below
1849                      }                      }
1850                  }                  }
1851    
# Line 1221  namespace LinuxSampler { Line 1853  namespace LinuxSampler {
1853                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1854                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1855    
1856                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1857                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1858                }
1859    
1860                /**
1861                 * Called on sustain pedal up events to check and if required,
1862                 * launch release trigger voices on the respective active key.
1863                 *
1864                 * @param pEngineChannel - engine channel on which this event occurred on
1865                 * @param itEvent - release trigger event (contains note number)
1866                 */
1867                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1868                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1869    
1870                    const int iKey = itEvent->Param.Note.Key;
1871                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1872    
1873                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1874    
1875                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1876                }
1877    
1878                /**
1879                 * Called on note-off and sustain pedal up events to check and if
1880                 * required, launch release trigger voices on the respective active
1881                 * key.
1882                 *
1883                 * @param pEngineChannel - engine channel on which this event occurred on
1884                 * @param itEvent - note off event / release trigger event
1885                 * @param pKey - key on which the release trigger voices shall be spawned
1886                 */
1887                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1888                    // spawn release triggered voice(s) if needed
1889                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1890                        // assign a new note to this release event
1891                        if (LaunchNewNote(pChannel, &*itEvent)) {
1892                            // allocate and trigger new release voice(s)
1893                            TriggerReleaseVoices(pChannel, itEvent);
1894                        }
1895                        pKey->ReleaseTrigger = false;
1896                    }
1897                }
1898    
1899                /**
1900                 * Called on note synthesis parameter change events. These are
1901                 * internal events caused by calling built-in real-time instrument
1902                 * script functions like change_vol(), change_pitch(), etc.
1903                 *
1904                 * This method performs two tasks:
1905                 *
1906                 * - It converts the event's relative values changes (Deltas) to
1907                 *   the respective final new synthesis parameter value (AbsValue),
1908                 *   for that particular moment of the event that is.
1909                 *
1910                 * - It moves the individual events to the Note's own event list
1911                 *   (or actually to the event list of the MIDI key), so that
1912                 *   voices can process those events sample accurately.
1913                 *
1914                 * @param pEngineChannel - engine channel on which this event occurred on
1915                 * @param itEvent - note synthesis parameter change event
1916                 */
1917                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1918                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1919    
1920                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1921                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1922    
1923                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1924    
1925                    switch (itEvent->Param.NoteSynthParam.Type) {
1926                        case Event::synth_param_volume:
1927                            if (relative)
1928                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1929                            else
1930                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1931                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1932                            break;
1933                        case Event::synth_param_pitch:
1934                            if (relative)
1935                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1936                            else
1937                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1938                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1939                            break;
1940                        case Event::synth_param_pan:
1941                            if (relative) {
1942                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1943                            } else {
1944                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1945                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1946                            }
1947                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1948                            break;
1949                        case Event::synth_param_cutoff:
1950                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1951                            break;
1952                        case Event::synth_param_resonance:
1953                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1954                            break;
1955                    }
1956    
1957                    // move note parameter event to its MIDI key
1958                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1959                    itEvent.moveToEndOf(pKey->pEvents);
1960              }              }
1961    
1962              /**              /**
# Line 1229  namespace LinuxSampler { Line 1964  namespace LinuxSampler {
1964               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
1965               */               */
1966              virtual void ResetInternal() {              virtual void ResetInternal() {
1967                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
1968    
1969                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
1970                  // while it's reseting                  // while it's reseting
# Line 1241  namespace LinuxSampler { Line 1976  namespace LinuxSampler {
1976                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1977                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1978                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1979                    itLastStolenNote           = NoteIterator();
1980                    itLastStolenNoteGlobally   = NoteIterator();
1981                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
1982                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
1983                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
1984    
1985                    // reset all notes
1986                    pNotePool->clear();
1987                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
1988                         itNote = pNotePool->allocAppend())
1989                    {
1990                        itNote->reset();
1991                    }
1992                    pNotePool->clear();
1993    
1994                  // reset all voices                  // reset all voices
1995                    pVoicePool->clear();
1996                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1997                      iterVoice->Reset();                      iterVoice->Reset();
1998                  }                  }
1999                  pVoicePool->clear();                  pVoicePool->clear();
2000    
2001                    // reset all engine channels
2002                    for (int i = 0; i < engineChannels.size(); i++) {
2003                        AbstractEngineChannel* pEngineChannel =
2004                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2005                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2006                    }
2007    
2008                  // reset disk thread                  // reset disk thread
2009                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2010    
# Line 1258  namespace LinuxSampler { Line 2012  namespace LinuxSampler {
2012                  pEventQueue->init();                  pEventQueue->init();
2013                  pSysexBuffer->init();                  pSysexBuffer->init();
2014                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
2015              }              }
2016    
2017              /**              /**
# Line 1280  namespace LinuxSampler { Line 2033  namespace LinuxSampler {
2033               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2034               *  (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).
2035               *               *
2036               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2037               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2038               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2039               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1306  namespace LinuxSampler { Line 2059  namespace LinuxSampler {
2059    
2060              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }
2061    
2062                int InitNewVoice (
2063                    EngineChannelBase<V, R, I>*  pChannel,
2064                    R*                           pRegion,
2065                    Pool<Event>::Iterator&       itNoteOnEvent,
2066                    Voice::type_t                VoiceType,
2067                    int                          iLayer,
2068                    int                          iKeyGroup,
2069                    bool                         ReleaseTriggerVoice,
2070                    bool                         VoiceStealing,
2071                    typename Pool<V>::Iterator&  itNewVoice
2072                ) {
2073                    int key = itNoteOnEvent->Param.Note.Key;
2074                    typename MidiKeyboardManager<V>::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2075                    if (itNewVoice) {
2076                        // launch the new voice
2077                        if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2078                            dmsg(4,("Voice not triggered\n"));
2079                            GetVoicePool()->free(itNewVoice);
2080                        }
2081                        else { // on success
2082                            --VoiceSpawnsLeft;
2083                            if (!pKey->Active) { // mark as active key
2084                                pKey->Active = true;
2085                                pKey->itSelf = pChannel->pActiveKeys->allocAppend();
2086                                *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
2087                            }
2088                            if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
2089                            return 0; // success
2090                        }
2091                    }
2092                    else if (VoiceStealing) {
2093                        // try to steal one voice
2094                        int result = StealVoice(pChannel, itNoteOnEvent);
2095                        if (!result) { // voice stolen successfully
2096                            // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
2097                            RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
2098                            if (itStealEvent) {
2099                                *itStealEvent = *itNoteOnEvent; // copy event
2100                                itStealEvent->Param.Note.Layer = iLayer;
2101                                itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
2102                                pKey->VoiceTheftsQueued++;
2103                            }
2104                            else dmsg(1,("Voice stealing queue full!\n"));
2105                        }
2106                    }
2107    
2108                    return -1;
2109                }
2110                
2111                /**
2112                 * Checks whether scale tuning setting has been changed since last
2113                 * time this method was called, if yes, it recalculates the pitch
2114                 * for all active voices.
2115                 */
2116                void ProcessScaleTuningChange() {
2117                    const bool changed = ScaleTuningChanged.readAndReset();
2118                    if (!changed) return;
2119                    
2120                    for (int i = 0; i < engineChannels.size(); i++) {
2121                        EngineChannelBase<V, R, I>* channel =
2122                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2123                        channel->OnScaleTuningChanged();
2124                    }
2125                }
2126    
2127          private:          private:
2128                Pool< Note<V> >* pNotePool;
2129                Pool<note_id_t> noteIDPool;
2130              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2131              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2132              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2015  
changed lines
  Added in v.2938

  ViewVC Help
Powered by ViewVC