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

Legend:
Removed from v.2043  
changed lines
  Added in v.3690

  ViewVC Help
Powered by ViewVC