/[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 2410 by schoenebeck, Sat Feb 2 18:52:15 2013 UTC revision 3283 by schoenebeck, Wed Jun 21 20:59:06 2017 UTC
# Line 5  Line 5 
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 32  Line 33 
33  #include "InstrumentManager.h"  #include "InstrumentManager.h"
34  #include "../common/global_private.h"  #include "../common/global_private.h"
35    
36    // a bit headroom over CONFIG_MAX_VOICES to avoid minor complications i.e. under voice stealing conditions
37    #define MAX_NOTES_HEADROOM  3
38    #define GLOBAL_MAX_NOTES    (GLOBAL_MAX_VOICES * MAX_NOTES_HEADROOM)
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
# Line 45  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49          class IM  /* Instrument Manager */,          class IM  /* Instrument Manager */,
50          class I   /* Instrument */          class I   /* Instrument */
51      >      >
52      class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {      class EngineBase: public AbstractEngine, public RegionPools<R>, public NotePool<V> {
53    
54          public:          public:
55                typedef typename RTList< Note<V> >::Iterator NoteIterator;
56              typedef typename RTList<V>::Iterator VoiceIterator;              typedef typename RTList<V>::Iterator VoiceIterator;
57              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 79  namespace LinuxSampler { Line 97  namespace LinuxSampler {
97                      dmsg(1,("OK\n"));                      dmsg(1,("OK\n"));
98                  }                  }
99    
100                    if (pNotePool) {
101                        pNotePool->clear();
102                        delete pNotePool;
103                    }
104    
105                  if (pVoicePool) {                  if (pVoicePool) {
106                      pVoicePool->clear();                      pVoicePool->clear();
107                      delete pVoicePool;                      delete pVoicePool;
# Line 104  namespace LinuxSampler { Line 127  namespace LinuxSampler {
127               *  @param Samples - number of sample points to be rendered               *  @param Samples - number of sample points to be rendered
128               *  @returns       0 on success               *  @returns       0 on success
129               */               */
130              virtual int RenderAudio(uint Samples) {              virtual int RenderAudio(uint Samples) OVERRIDE {
131                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
132    
133                  // return if engine disabled                  // return if engine disabled
# Line 140  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163                                  dmsg(5,("Engine: Sysex received\n"));                                  dmsg(5,("Engine: Sysex received\n"));
164                                  ProcessSysex(itEvent);                                  ProcessSysex(itEvent);
165                                  break;                                  break;
166                                default: ; // noop
167                          }                          }
168                      }                      }
169                  }                  }
170                    
171                    // In case scale tuning has been changed, recalculate pitch for
172                    // all active voices.
173                    ProcessScaleTuningChange();
174    
175                  // reset internal voice counter (just for statistic of active voices)                  // reset internal voice counter (just for statistic of active voices)
176                  ActiveVoiceCountTemp = 0;                  ActiveVoiceCountTemp = 0;
# Line 205  namespace LinuxSampler { Line 233  namespace LinuxSampler {
233                  return 0;                  return 0;
234              }              }
235    
236              virtual int MaxVoices() { return pVoicePool->poolSize(); }              virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
237    
238              virtual void SetMaxVoices(int iVoices) throw (Exception) {              virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
239                  if (iVoices < 1)                  if (iVoices < 1)
240                      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");
241    
# Line 231  namespace LinuxSampler { Line 259  namespace LinuxSampler {
259                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
260                  }                  }
261    
262                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
263                  try {                  try {
264                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
265                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
266                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
267                  } catch (...) {                  } catch (...) {
268                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
269                  }                  }
270    
271                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
272                         iterVoice; iterVoice = pVoicePool->allocAppend())
273                    {
274                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
275                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
276                  }                  }
277                  pVoicePool->clear();                  pVoicePool->clear();
278    
279                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
280                         itNote = pNotePool->allocAppend())
281                    {
282                        itNote->init(pVoicePool, &noteIDPool);
283                    }
284                    pNotePool->clear();
285    
286                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
287                  ResumeAll();                  ResumeAll();
288              }              }
# Line 250  namespace LinuxSampler { Line 290  namespace LinuxSampler {
290              /** Called after the new max number of voices is set and before resuming the engine. */              /** Called after the new max number of voices is set and before resuming the engine. */
291              virtual void PostSetMaxVoices(int iVoices) { }              virtual void PostSetMaxVoices(int iVoices) { }
292    
293              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
294              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
295              virtual int  MaxDiskStreams() { return iMaxDiskStreams; }              virtual int  MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
296    
297              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
298                  if (iStreams < 0)                  if (iStreams < 0)
299                      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");
300    
# Line 269  namespace LinuxSampler { Line 309  namespace LinuxSampler {
309                  ResumeAll();                  ResumeAll();
310              }              }
311    
312              virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }              virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
313              virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }              virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
314              virtual InstrumentManager* GetInstrumentManager() { return &instruments; }              virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
315    
316              /**              /**
317               * Connect this engine instance with the given audio output device.               * Connect this engine instance with the given audio output device.
# Line 282  namespace LinuxSampler { Line 322  namespace LinuxSampler {
322               *               *
323               * @param pAudioOut - audio output device to connect to               * @param pAudioOut - audio output device to connect to
324               */               */
325              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
326                  // caution: don't ignore if connecting to the same device here,                  // caution: don't ignore if connecting to the same device here,
327                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!
328    
# Line 311  namespace LinuxSampler { Line 351  namespace LinuxSampler {
351                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
352                      // lower minimum release time                      // lower minimum release time
353                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
354                        pVoicePool->clear();
355                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
356                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
357                      }                      }
# Line 331  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
373                  }                  }
374    
375                    pVoicePool->clear();
376                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
377                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
378                      dmsg(3,("d"));                      dmsg(3,("d"));
379                  }                  }
380                  pVoicePool->clear();                  pVoicePool->clear();
381    
382                  // (re)create event generator                  // update event generator
383                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
384    
385                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
386                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 370  namespace LinuxSampler { Line 411  namespace LinuxSampler {
411              }              }
412                    
413              // Implementattion for abstract method derived from Engine.              // Implementattion for abstract method derived from Engine.
414              virtual void ReconnectAudioOutputDevice() {              virtual void ReconnectAudioOutputDevice() OVERRIDE {
415                  SuspendAll();                  SuspendAll();
416                  if (pAudioOutputDevice) Connect(pAudioOutputDevice);                  if (pAudioOutputDevice) Connect(pAudioOutputDevice);
417                  ResumeAll();                  ResumeAll();
# Line 428  namespace LinuxSampler { Line 469  namespace LinuxSampler {
469               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
470               */               */
471              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
472                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
473                  SuspendedRegionsMutex.Lock();                  {
474                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
475                  pPendingRegionSuspension = pRegion;                      SuspensionChangeOngoing.Set(true);
476                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionSuspension = pRegion;
477                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
478                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  }
479                    dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
480              }              }
481    
482              /**              /**
# Line 444  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
487               */               */
488              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
489                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
490                  SuspendedRegionsMutex.Lock();                  {
491                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
492                  pPendingRegionResumption = pRegion;                      SuspensionChangeOngoing.Set(true);
493                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionResumption = pRegion;
494                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  }
496                    dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
497              }              }
498    
499              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 553  namespace LinuxSampler { Line 596  namespace LinuxSampler {
596              }              }
597    
598              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
599              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
600                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 572  namespace LinuxSampler { Line 617  namespace LinuxSampler {
617              public:              public:
618                  int PendingStreamDeletions;                  int PendingStreamDeletions;
619                  RR* pPendingRegionSuspension;                  RR* pPendingRegionSuspension;
620    
621                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
622                      PendingStreamDeletions = 0;                      PendingStreamDeletions = 0;
623                      this->pPendingRegionSuspension = pPendingRegionSuspension;                      this->pPendingRegionSuspension = pPendingRegionSuspension;
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
632                      return true;                      return true;
633                  }                  }
634    
635                  virtual void Process(VoiceIterator& itVoice) {                  virtual void Process(VoiceIterator& itVoice) OVERRIDE {
636                      // request a notification from disk thread side for stream deletion                      // request a notification from disk thread side for stream deletion
637                      const Stream::Handle hStream = itVoice->KillImmediately(true);                      const Stream::Handle hStream = itVoice->KillImmediately(true);
638                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
# Line 601  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648    
649              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
650              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
653              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
658              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
694    
695                    // usually the new note (and its subsequent voices) will be
696                    // allocated on the key provided by the event's note number,
697                    // however if this new note is requested not to be a regular
698                    // note, but rather a child note, then this new note will be
699                    // allocated on the parent note's key instead in order to
700                    // release the child note simultaniously with its parent note
701                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
702    
703                    // in case this new note was requested to be a child note,
704                    // then retrieve its parent note and link them with each other
705                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
706                    if (parentNoteID) {
707                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
708                        if (itParentNote) {
709                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
710                            if (itChildNoteID) {
711                                // link parent and child note with each other
712                                *itChildNoteID = newNoteID;
713                                itNewNote->parentNoteID = parentNoteID;
714                                itNewNote->hostKey = itParentNote->hostKey;
715                            } else {    
716                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
717                                pNotePool->free(itNewNote);
718                                return 0; // error
719                            }
720                        } else {
721                            // the parent note was apparently released already, so
722                            // free the new note again and inform caller that it
723                            // should drop the event
724                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
725                            pNotePool->free(itNewNote);
726                            return 0; // error
727                        }
728                    }
729    
730                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
731    
732                    // copy event which caused this note
733                    itNewNote->cause = *itNoteOnEvent;
734                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
735                    if (!itNewNote->eventID) {
736                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
737                    }
738    
739                    // move new note to its host key
740                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
741                    itNewNote.moveToEndOf(pKey->pActiveNotes);
742    
743                    // assign unique note ID of this new note to the original note on event
744                    itNoteOnEvent->Param.Note.ID = newNoteID;
745    
746                    return newNoteID; // success
747                }
748    
749              /**              /**
750               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
751               * engine channel.               * engine channel.
# Line 624  namespace LinuxSampler { Line 761  namespace LinuxSampler {
761                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
762                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
763    
764                  // process events                  // if a valid real-time instrument script is loaded, pre-process
765                    // the event list by running the script now, since the script
766                    // might filter events or add new ones for this cycle
767                    if (pChannel->pScript) {
768                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
769    
770                        // resume suspended script executions been scheduled for
771                        // this audio fragment cycle (which were suspended in a
772                        // previous audio fragment cycle)
773                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
774    
775                        // spawn new script executions for the new MIDI events of
776                        // this audio fragment cycle
777                        //
778                        // 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
779                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
780                            end = pChannel->pEvents->end(); itEvent != end; )
781                        {
782                            //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).
783                            RTList<Event>::Iterator itNext = itEvent;
784                            ++itNext;
785    
786                            switch (itEvent->Type) {
787                                case Event::type_note_on:
788                                    if (pChannel->pScript->handlerNote)
789                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
790                                    break;
791                                case Event::type_note_off:
792                                    if (pChannel->pScript->handlerRelease)
793                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
794                                    break;
795                                case Event::type_control_change:
796                                case Event::type_channel_pressure:
797                                case Event::type_pitchbend:
798                                    if (pChannel->pScript->handlerController)
799                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
800                                    break;
801                                case Event::type_note_pressure:
802                                    //TODO: ...
803                                    break;
804    
805                                case Event::type_sysex:
806                                    //TODO: ...
807                                    break;
808    
809                                case Event::type_cancel_release_key:
810                                case Event::type_release_key:
811                                case Event::type_release_note:
812                                case Event::type_play_note:
813                                case Event::type_stop_note:
814                                case Event::type_kill_note:
815                                case Event::type_note_synth_param:
816                                    break; // noop
817                            }
818    
819                            // see HACK comment above
820                            itEvent = itNext;
821                        }
822    
823                        // this has to be run again, since the newly spawned scripts
824                        // above may have cause suspended scripts that must be
825                        // resumed within this same audio fragment cycle
826                        //
827                        // FIXME: see FIXME comment above
828                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
829                    }
830    
831                    // if there are any delayed events scheduled for the current
832                    // audio fragment cycle, then move and sort them into the main
833                    // event list
834                    if (!pChannel->delayedEvents.queue.isEmpty()) {
835                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
836                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
837                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
838                        while (true) {
839                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
840                                pEventGenerator->popNextScheduledEvent(
841                                    pChannel->delayedEvents.queue,
842                                    pChannel->delayedEvents.schedulerNodes,
843                                    fragmentEndTime
844                                );
845                            if (!itDelayedEventNode) break;
846                            // get the actual delayed event object and free the used scheduler node
847                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
848                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
849                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
850                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
851                                continue;
852                            }
853                            // skip all events on main event list which have a time
854                            // before (or equal to) the delayed event to be inserted
855                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
856                                 ++itEvent);
857                            // now move delayed event from delayedEvents.pList to
858                            // the current position on the main event list
859                            itEvent = itDelayedEvent.moveBefore(itEvent);
860                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
861                        }
862                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
863                    }
864    
865                    // now process all events regularly
866                  {                  {
867                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
868                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 634  namespace LinuxSampler { Line 872  namespace LinuxSampler {
872                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
873                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
874                                  break;                                  break;
875                                case Event::type_play_note:
876                                    dmsg(5,("Engine: Play Note received\n"));
877                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
878                                    break;
879                              case Event::type_note_off:                              case Event::type_note_off:
880                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
881                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
882                                  break;                                  break;
883                                case Event::type_stop_note:
884                                    dmsg(5,("Engine: Stop Note received\n"));
885                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
886                                    break;
887                                case Event::type_kill_note:
888                                    dmsg(5,("Engine: Kill Note received\n"));
889                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
890                                    break;
891                              case Event::type_control_change:                              case Event::type_control_change:
892                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
893                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
894                                  break;                                  break;
895                                case Event::type_channel_pressure:
896                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
897                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
898                                    break;
899                                case Event::type_note_pressure:
900                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
901                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
902                                    break;
903                              case Event::type_pitchbend:                              case Event::type_pitchbend:
904                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
905                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
906                                  break;                                  break;
907                                case Event::type_note_synth_param:
908                                    dmsg(5,("Engine: Note Synth Param received\n"));
909                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
910                                    break;
911                                case Event::type_sysex:
912                                    break; // TODO ...
913    
914                                case Event::type_cancel_release_key:
915                                case Event::type_release_key:
916                                case Event::type_release_note:
917                                    break; // noop
918                          }                          }
919                      }                      }
920                  }                  }
# Line 653  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
923                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
924                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
925                    itLastStolenNote          = NoteIterator();
926                    itLastStolenNoteGlobally  = NoteIterator();
927                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
928                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
929                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
930              }              }
931    
932              /**              /**
933                 * Run all suspended script execution instances which are scheduled
934                 * to be resumed for the current audio fragment cycle.
935                 *
936                 * @param pChannel - engine channel on which suspended events occurred
937                 */
938                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
939                    while (true) {
940                        RTList<ScriptEvent>::Iterator itEvent =
941                            pEventGenerator->popNextScheduledScriptEvent(
942                                pChannel->pScript->suspendedEvents,
943                                *pChannel->pScript->pEvents, fragmentEndTime
944                            );
945                        if (!itEvent) break;
946                        ResumeScriptEvent(pChannel, itEvent);
947                    }
948                }
949    
950                /** @brief Call instrument script's event handler for this event.
951                 *
952                 * Causes a new execution instance of the currently loaded real-time
953                 * instrument script's event handler (callback) to be spawned for
954                 * the given MIDI event.
955                 *
956                 * @param pChannel - engine channel on which the MIDI event occurred
957                 * @param itEvent - MIDI event that causes this new script execution
958                 * @param pEventHandler - script's event handler to be executed
959                 */
960                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
961                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
962                    // check if polyphonic data is passed from "note" to "release"
963                    // script event handlers
964                    if (pEventHandler == pChannel->pScript->handlerRelease &&
965                        pChannel->pScript->handlerNote &&
966                        pChannel->pScript->handlerNote->isPolyphonic() &&
967                        pChannel->pScript->handlerRelease->isPolyphonic() &&
968                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
969                    {
970                        // polyphonic variable data is used/passed from "note" to
971                        // "release" script callback, so we have to recycle the
972                        // original "note on" script event(s)
973                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
974                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
975                        for (; it != end; ++it) {
976                            ProcessScriptEvent(
977                                pChannel, itEvent, pEventHandler, it
978                            );
979                        }
980                    } else {
981                        // no polyphonic data is used/passed from "note" to
982                        // "release" script callback, so just use a new fresh
983                        // script event object
984                        RTList<ScriptEvent>::Iterator itScriptEvent =
985                            pChannel->pScript->pEvents->allocAppend();
986                        // if event handler uses polyphonic variables, reset them
987                        // to zero values before starting to execute the handler
988                        if (pEventHandler->isPolyphonic())
989                            itScriptEvent->execCtx->resetPolyphonicData();
990                        ProcessScriptEvent(
991                            pChannel, itEvent, pEventHandler, itScriptEvent
992                        );
993                    }
994                }
995    
996                /** @brief Spawn new execution instance of an instrument script handler.
997                 *
998                 * Will be called to initiate a new execution of a real-time
999                 * instrument script event right from the start of the script's
1000                 * respective handler. If script execution did not complete after
1001                 * calling this method, the respective script exeuction is then
1002                 * suspended and a call to ResumeScriptEvent() will be used next
1003                 * time to continue its execution.
1004                 *
1005                 * @param pChannel - engine channel this script is running for
1006                 * @param itEvent - event which caused execution of this script
1007                 *                  event handler
1008                 * @param pEventHandler - VM representation of event handler to be
1009                 *                        executed
1010                 * @param itScriptEvent - script event that shall be processed
1011                 */
1012                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1013                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1014    
1015                    // fill the list of script handlers to be executed by this event
1016                    int i = 0;
1017                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1018                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1019    
1020                    // initialize/reset other members
1021                    itScriptEvent->cause = *itEvent;
1022                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1023                    itScriptEvent->currentHandler = 0;
1024                    itScriptEvent->executionSlices = 0;
1025                    itScriptEvent->ignoreAllWaitCalls = false;
1026                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1027                    // this is the native representation of the $EVENT_ID script variable
1028                    itScriptEvent->id =
1029                        (itEvent->Type == Event::type_note_on)
1030                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1031                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1032    
1033                    // run script handler(s)
1034                    VMExecStatus_t res = pScriptVM->exec(
1035                        pChannel->pScript->parserContext, &*itScriptEvent
1036                    );
1037    
1038                    // was the script suspended?
1039                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1040                        // in case the script was suspended, keep it on the allocated
1041                        // ScriptEvent list to be resume at the scheduled time in future,
1042                        // additionally insert it into a sorted time queue
1043                        pEventGenerator->scheduleAheadMicroSec(
1044                            pChannel->pScript->suspendedEvents, // scheduler queue
1045                            *itScriptEvent, // script event
1046                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1047                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1048                        );
1049                    } else { // script execution has finished without 'suspended' status ...
1050                        // if "polyphonic" variable data is passed from script's
1051                        // "note" event handler to its "release" event handler, then
1052                        // the script event must be kept and recycled for the later
1053                        // occuring "release" script event ...
1054                        if (pEventHandler == pChannel->pScript->handlerNote &&
1055                            pChannel->pScript->handlerRelease &&
1056                            pChannel->pScript->handlerNote->isPolyphonic() &&
1057                            pChannel->pScript->handlerRelease->isPolyphonic())
1058                        {
1059                            const int key = itEvent->Param.Note.Key;
1060                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1061                        } else {
1062                            // ... otherwise if no polyphonic data is passed and
1063                            // script's execution has finished without suspension
1064                            // status, then free the script event for a new future
1065                            // script event to be triggered from start
1066                            pChannel->pScript->pEvents->free(itScriptEvent);
1067                        }
1068                    }
1069                }
1070    
1071                /** @brief Resume execution of instrument script.
1072                 *
1073                 * Will be called to resume execution of a real-time instrument
1074                 * script event which has been suspended previously.
1075                 *
1076                 * Script execution might be suspended for various reasons. Usually
1077                 * a script will be suspended if the script called the built-in
1078                 * "wait()" function, but it might also be suspended automatically
1079                 * if the script took too much execution time in an audio fragment
1080                 * cycle. So in the latter case automatic suspension is performed in
1081                 * order to avoid harm for the sampler's overall real-time
1082                 * requirements.
1083                 *
1084                 * @param pChannel - engine channel this script is running for
1085                 * @param itScriptEvent - script execution that shall be resumed
1086                 */
1087                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1088                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1089    
1090                    // run script
1091                    VMExecStatus_t res = pScriptVM->exec(
1092                        pChannel->pScript->parserContext, &*itScriptEvent
1093                    );
1094    
1095                    // was the script suspended?
1096                    if (res & VM_EXEC_SUSPENDED) {
1097                        // in case the script was suspended, keep it on the allocated
1098                        // ScriptEvent list to be resume at the scheduled time in future,
1099                        // additionally insert it into a sorted time queue
1100                        pEventGenerator->scheduleAheadMicroSec(
1101                            pChannel->pScript->suspendedEvents, // scheduler queue
1102                            *itScriptEvent, // script event
1103                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1104                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1105                        );
1106                    } else { // script execution has finished without 'suspended' status ...
1107                        // if "polyphonic" variable data is passed from script's
1108                        // "note" event handler to its "release" event handler, then
1109                        // the script event must be kept and recycled for the later
1110                        // occuring "release" script event ...
1111                        if (handler && handler == pChannel->pScript->handlerNote &&
1112                            pChannel->pScript->handlerRelease &&
1113                            pChannel->pScript->handlerNote->isPolyphonic() &&
1114                            pChannel->pScript->handlerRelease->isPolyphonic())
1115                        {
1116                            const int key = itScriptEvent->cause.Param.Note.Key;
1117                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1118                        } else {
1119                            // ... otherwise if no polyphonic data is passed and
1120                            // script's execution has finished without suspension
1121                            // status, then free the script event for a new future
1122                            // script event to be triggered from start
1123                            pChannel->pScript->pEvents->free(itScriptEvent);
1124                        }
1125                    }
1126                }
1127    
1128                /**
1129               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1130               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1131               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1132               *  voice actually died.               *  voice actually died.
1133               *               *
1134               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1135               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1136               *  @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
1137               */               */
1138              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1139                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1140                      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"));
1141                      return -1;                      return -1;
# Line 676  namespace LinuxSampler { Line 1143  namespace LinuxSampler {
1143    
1144                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1145    
1146                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1147                        dmsg(1,("Event pool emtpy!\n"));
1148                        return -1;
1149                    }
1150    
1151                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1152                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1153                          return 0;                      return 0;
1154                      }                  }
1155    
1156                      // 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
1157                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1158                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1159                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1160                      int                       iChannelIndex;                  int                          iChannelIndex;
1161                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1162    
1163                      // select engine channel                  // select engine channel
1164                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1165                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1166                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1167                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1168                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1169                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1170                      }                  }
1171    
1172                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1173                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1174                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1175                          do {                      do {
1176                              ++itSelectedVoice;                          ++itSelectedVoice;
1177                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1178                    }
1179                    // did we find a 'stealable' voice?
1180                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1181                        // remember which voice we stole, so we can simply proceed on next voice stealing
1182                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1183                        // done
1184                        goto stealable_voice_found;
1185                    }
1186    
1187                    // get (next) oldest note
1188                    if (this->itLastStolenNoteGlobally) {
1189                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1190                             itNote; ++itNote)
1191                        {
1192                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1193                                // proceed iterating if voice was created in this audio fragment cycle
1194                                if (itSelectedVoice->IsStealable()) {
1195                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1196                                    this->itLastStolenNoteGlobally  = itNote;
1197                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1198                                    goto stealable_voice_found; // selection succeeded
1199                                }
1200                            }
1201                      }                      }
1202                    }
1203    
1204                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1205                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1206                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1207    
1208                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1209                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1210                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1211                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1212                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1213                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1214                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1215                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1216                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1217                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1218                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1219                                itSelectedVoice = itNote->pActiveVoices->first();
1220                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1221                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1222                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1223                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1224                                  // 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
1225                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1226                                    this->itLastStolenNoteGlobally  = itNote;
1227                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1228                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1229                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1230                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // get next engine channel  
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
1231                          }                          }
1232                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1233                      }                      }
1234                        // get next engine channel
1235                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1236                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1237    
1238                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1239                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1240                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1241                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1242                            dmsg(1,("Exiting.\n"));
1243                            exit(-1);
1244                      }                      }
1245                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1246                    }
1247    
1248                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1249                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1250    
1251                      return 0; // success                  #if CONFIG_DEVMODE
1252                  }                  if (!itSelectedVoice->IsActive()) {
1253                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1254                      return -1;                      return -1;
1255                  }                  }
1256                    #endif // CONFIG_DEVMODE
1257    
1258                    // now kill the selected voice
1259                    itSelectedVoice->Kill(itNoteOnEvent);
1260    
1261                    --VoiceSpawnsLeft;
1262    
1263                    return 0; // success
1264              }              }
1265    
1266              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 790  namespace LinuxSampler { Line 1282  namespace LinuxSampler {
1282                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1283                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1284                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1285                            pEngineChannel->pScript =
1286                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1287                          instrumentChanged = true;                          instrumentChanged = true;
1288    
1289                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1290    
1291                            // the script's "init" event handler is only executed
1292                            // once (when the script is loaded or reloaded)
1293                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1294                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1295                                RTList<ScriptEvent>::Iterator itScriptEvent =
1296                                    pEngineChannel->pScript->pEvents->allocAppend();
1297    
1298                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1299                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1300                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1301                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1302                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1303                                itScriptEvent->handlers[1] = NULL;
1304                                itScriptEvent->currentHandler = 0;
1305                                itScriptEvent->executionSlices = 0;
1306                                itScriptEvent->ignoreAllWaitCalls = false;
1307                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1308    
1309                                VMExecStatus_t res;
1310                                size_t instructionsCount = 0;
1311                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1312                                bool bWarningShown = false;
1313                                do {
1314                                    res = pScriptVM->exec(
1315                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1316                                    );
1317                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1318                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1319                                        bWarningShown = true;
1320                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1321                                    }
1322                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1323    
1324                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1325                            }
1326                      }                      }
1327                  }                  }
1328    
# Line 843  namespace LinuxSampler { Line 1373  namespace LinuxSampler {
1373                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1374                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1375                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1376                        
1377                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1378                          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);
1379                      if (itNewVoice) {                      if (itNewVoice) {
1380                            // usually there should already be a new Note object
1381                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1382                            if (!itNote) { // should not happen, but just to be sure ...
1383                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1384                                if (!noteID) {
1385                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1386                                    continue;
1387                                }
1388                                itNote = GetNotePool()->fromID(noteID);
1389                            }
1390                            // move voice from whereever it was, to the new note's list of active voices
1391                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1392                            // render audio of this new voice for the first time
1393                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1394                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1395                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 883  namespace LinuxSampler { Line 1427  namespace LinuxSampler {
1427                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1428    
1429                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1430                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1431                    pChannel->ClearEventListsOfCurrentFragment();
1432              }              }
1433    
1434              /**              /**
# Line 948  namespace LinuxSampler { Line 1493  namespace LinuxSampler {
1493                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1494                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1495                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1496                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1497                                      if (note < 128)                                      if (note < 128)
1498                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1499                                      break;                                      break;
# Line 956  namespace LinuxSampler { Line 1501  namespace LinuxSampler {
1501                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1502                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1503                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1504                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1505                                      if (note < 128)                                      if (note < 128)
1506                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1507                                      break;                                      break;
# Line 1109  namespace LinuxSampler { Line 1654  namespace LinuxSampler {
1654              /**              /**
1655               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1656               *               *
1657               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1658               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1659               */               */
1660              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1661                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1662                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1663    
                 //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;  
   
1664                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1665                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1666                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1667    
1668                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1669    
1670                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1671                    // programmatically spawned notes (Event::type_play_note). We have
1672                    // to distinguish between them, since certain processing below
1673                    // must only be done on real MIDI note-on events (i.e. for
1674                    // correctly updating which MIDI keys are currently pressed down).
1675                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1676    
1677                    if (isRealMIDINoteOnEvent)
1678                        pChannel->listeners.PreProcessNoteOn(key, vel);
1679    
1680                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1681                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1682                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1683                            pChannel->listeners.PostProcessNoteOn(key, vel);
1684                      return;                      return;
1685                  }                  }
1686                  #endif                  #endif
1687    
1688                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1689                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1690                            pChannel->listeners.PostProcessNoteOn(key, vel);
1691                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1692                  }                  }
1693    
# Line 1143  namespace LinuxSampler { Line 1695  namespace LinuxSampler {
1695                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1696    
1697                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1698                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1699                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1700                      if (itYoungestKey) {                      if (itYoungestKey) {
1701                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1151  namespace LinuxSampler { Line 1703  namespace LinuxSampler {
1703                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1704                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1705                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1706                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1707                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1708                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1709                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1710                                    }
1711                              }                              }
1712                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1713                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1714                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1715                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1716                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1717                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1718                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1719                                    }
1720                              }                              }
1721                          }                          }
1722                      }                      }
# Line 1167  namespace LinuxSampler { Line 1724  namespace LinuxSampler {
1724                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1725                  }                  }
1726    
1727                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1728                        pChannel->ProcessKeySwitchChange(key);
1729    
1730                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1731                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1732                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1733                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1734                    }
1735    
1736                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1737                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1738                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1739                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1740                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1741                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1742                      }                      }
1743                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1744                  }                  }
# Line 1189  namespace LinuxSampler { Line 1749  namespace LinuxSampler {
1749                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1750                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1751    
1752                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1753                        pChannel->PortamentoPos = (float) key;
1754    
1755                    //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?
1756                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1757                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1758                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1759                  }                  }
1760                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1761                    if (isRealMIDINoteOnEvent)
1762                        pChannel->listeners.PostProcessNoteOn(key, vel);
1763              }              }
1764    
1765              /**              /**
# Line 1220  namespace LinuxSampler { Line 1785  namespace LinuxSampler {
1785               *  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.
1786               *  due to completion of sample playback).               *  due to completion of sample playback).
1787               *               *
1788               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1789               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1790               */               */
1791              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1792                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1793    
                 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;  
   
1794                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1795                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1796                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1797    
1798                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1799    
1800                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1801                    // programmatically spawned notes (Event::type_stop_note). We have
1802                    // to distinguish between them, since certain processing below
1803                    // must only be done on real MIDI note-off events (i.e. for
1804                    // correctly updating which MIDI keys are currently pressed down),
1805                    // plus a stop-note event just releases voices of one particular
1806                    // note, whereas a note-off event releases all voices on a
1807                    // particular MIDI key instead.
1808                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1809    
1810                    if (isRealMIDINoteOffEvent)
1811                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1812    
1813                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1814                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1815                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1816                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1817                      return;                      return;
1818                  }                  }
1819                  #endif                  #endif
1820    
1821                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1822                        pKey->KeyPressed = false; // the MIDI key was now released
1823                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1824                    }
1825    
1826                  // move event to the key's own event list                  // move event to the key's own event list
1827                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1828    
1829                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1830                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1831    
1832                  // 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)
1833                  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
1834                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1835                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1836                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1837                          // 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
1838                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1839                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1840                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1841                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1842                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1843                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1844                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1845                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1846                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1847                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1848                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1849                                  // create a pseudo note on event                                      }
1850                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1851                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1852                                      // copy event                                      if (itPseudoNoteOnEvent) {
1853                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1854                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1855                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1856                                      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)
1857                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1858                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1859                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1860                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1861                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1862                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1863                                            }
1864                                            // if neither a voice was spawned or postponed then remove note on event from key again
1865                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1866                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1867    
1868                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1869                                  break; // done                                      break; // done
1870                                    }
1871                              }                              }
1872                          }                          }
1873                      }                          if (bOtherKeysPressed) {
1874                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1875                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1876                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1877                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1878                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1879                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1880                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1881                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1882                                        }
1883                                    }
1884                              }                              }
1885                          }                          } else pChannel->PortamentoPos = -1.0f;
1886                      } 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  
1887    
1888                      // 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
1889                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1890                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1891                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1892                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1893                        }
1894                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1895                        // This programmatically caused event is caused by a call to
1896                        // the built-in instrument script function note_off(). In
1897                        // contrast to a real MIDI note-off event the stop-note
1898                        // event just intends to release voices of one particular note.
1899                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1900                        if (pNote) { // the requested note is still alive ...
1901                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1902                        } else { // note is dead and gone ..
1903                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1904                            return; // prevent event to be removed a 2nd time below
1905                      }                      }
1906                  }                  }
1907    
# Line 1317  namespace LinuxSampler { Line 1909  namespace LinuxSampler {
1909                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1910                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1911    
1912                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1913                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1914                }
1915    
1916                /**
1917                 * Called on sustain pedal up events to check and if required,
1918                 * launch release trigger voices on the respective active key.
1919                 *
1920                 * @param pEngineChannel - engine channel on which this event occurred on
1921                 * @param itEvent - release trigger event (contains note number)
1922                 */
1923                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1924                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1925    
1926                    const int iKey = itEvent->Param.Note.Key;
1927                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1928    
1929                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1930    
1931                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1932                }
1933    
1934                /**
1935                 * Called on note-off and sustain pedal up events to check and if
1936                 * required, launch release trigger voices on the respective active
1937                 * key.
1938                 *
1939                 * @param pEngineChannel - engine channel on which this event occurred on
1940                 * @param itEvent - note off event / release trigger event
1941                 * @param pKey - key on which the release trigger voices shall be spawned
1942                 */
1943                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1944                    // spawn release triggered voice(s) if needed
1945                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1946                        // assign a new note to this release event
1947                        if (LaunchNewNote(pChannel, itEvent)) {
1948                            // allocate and trigger new release voice(s)
1949                            TriggerReleaseVoices(pChannel, itEvent);
1950                        }
1951                        pKey->ReleaseTrigger = false;
1952                    }
1953                }
1954    
1955                /**
1956                 * Called on "kill note" events, which currently only happens on
1957                 * built-in real-time instrument script function fade_out(). This
1958                 * method only fulfills one task: moving the even to the Note's own
1959                 * event list so that its voices can process the kill event sample
1960                 * accurately.
1961                 */
1962                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1963                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1964    
1965                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1966                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1967    
1968                    // move note kill event to its MIDI key
1969                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1970                    itEvent.moveToEndOf(pKey->pEvents);
1971                }
1972    
1973                /**
1974                 * Called on note synthesis parameter change events. These are
1975                 * internal events caused by calling built-in real-time instrument
1976                 * script functions like change_vol(), change_tune(), etc.
1977                 *
1978                 * This method performs two tasks:
1979                 *
1980                 * - It converts the event's relative values changes (Deltas) to
1981                 *   the respective final new synthesis parameter value (AbsValue),
1982                 *   for that particular moment of the event that is.
1983                 *
1984                 * - It moves the individual events to the Note's own event list
1985                 *   (or actually to the event list of the MIDI key), so that
1986                 *   voices can process those events sample accurately.
1987                 *
1988                 * @param pEngineChannel - engine channel on which this event occurred on
1989                 * @param itEvent - note synthesis parameter change event
1990                 */
1991                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1992                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1993    
1994                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1995                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1996    
1997                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1998    
1999                    switch (itEvent->Param.NoteSynthParam.Type) {
2000                        case Event::synth_param_volume:
2001                            if (relative)
2002                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2003                            else
2004                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2005                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2006                            break;
2007                        case Event::synth_param_volume_time:
2008                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2009                            break;
2010                        case Event::synth_param_volume_curve:
2011                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2012                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2013                            break;
2014                        case Event::synth_param_pitch:
2015                            if (relative)
2016                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2017                            else
2018                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2019                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2020                            break;
2021                        case Event::synth_param_pitch_time:
2022                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2023                            break;
2024                        case Event::synth_param_pitch_curve:
2025                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2026                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2027                            break;
2028                        case Event::synth_param_pan:
2029                            if (relative) {
2030                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2031                            } else {
2032                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2033                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2034                            }
2035                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2036                            break;
2037                        case Event::synth_param_cutoff:
2038                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2039                            break;
2040                        case Event::synth_param_resonance:
2041                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2042                            break;
2043                        case Event::synth_param_attack:
2044                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2045                            break;
2046                        case Event::synth_param_decay:
2047                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2048                            break;
2049                        case Event::synth_param_release:
2050                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2051                            break;
2052                        case Event::synth_param_amp_lfo_depth:
2053                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2054                            break;
2055                        case Event::synth_param_amp_lfo_freq:
2056                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2057                            break;
2058                        case Event::synth_param_pitch_lfo_depth:
2059                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2060                            break;
2061                        case Event::synth_param_pitch_lfo_freq:
2062                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2063                            break;
2064                    }
2065    
2066                    // move note parameter event to its MIDI key
2067                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2068                    itEvent.moveToEndOf(pKey->pEvents);
2069              }              }
2070    
2071              /**              /**
2072               *  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
2073               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2074               */               */
2075              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2076                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
2077    
2078                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
2079                  // while it's reseting                  // while it's reseting
# Line 1337  namespace LinuxSampler { Line 2085  namespace LinuxSampler {
2085                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2086                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2087                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2088                    itLastStolenNote           = NoteIterator();
2089                    itLastStolenNoteGlobally   = NoteIterator();
2090                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2091                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2092                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2093    
2094                    // reset all notes
2095                    pNotePool->clear();
2096                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2097                         itNote = pNotePool->allocAppend())
2098                    {
2099                        itNote->reset();
2100                    }
2101                    pNotePool->clear();
2102    
2103                  // reset all voices                  // reset all voices
2104                    pVoicePool->clear();
2105                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2106                      iterVoice->Reset();                      iterVoice->Reset();
2107                  }                  }
2108                  pVoicePool->clear();                  pVoicePool->clear();
2109    
2110                    // reset all engine channels
2111                    for (int i = 0; i < engineChannels.size(); i++) {
2112                        AbstractEngineChannel* pEngineChannel =
2113                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2114                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2115                    }
2116    
2117                  // reset disk thread                  // reset disk thread
2118                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2119    
# Line 1354  namespace LinuxSampler { Line 2121  namespace LinuxSampler {
2121                  pEventQueue->init();                  pEventQueue->init();
2122                  pSysexBuffer->init();                  pSysexBuffer->init();
2123                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
2124              }              }
2125    
2126              /**              /**
# Line 1365  namespace LinuxSampler { Line 2131  namespace LinuxSampler {
2131               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2132               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2133               */               */
2134              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2135                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2136                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2137                  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 1376  namespace LinuxSampler { Line 2142  namespace LinuxSampler {
2142               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2143               *  (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).
2144               *               *
2145               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2146               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2147               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2148               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1400  namespace LinuxSampler { Line 2166  namespace LinuxSampler {
2166                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2167              ) = 0;              ) = 0;
2168    
2169              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2170    
2171              int InitNewVoice (              int InitNewVoice (
2172                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1419  namespace LinuxSampler { Line 2185  namespace LinuxSampler {
2185                      // launch the new voice                      // launch the new voice
2186                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2187                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2188                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2189                      }                      }
2190                      else { // on success                      else { // on success
2191                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1450  namespace LinuxSampler { Line 2216  namespace LinuxSampler {
2216    
2217                  return -1;                  return -1;
2218              }              }
2219                
2220                /**
2221                 * Checks whether scale tuning setting has been changed since last
2222                 * time this method was called, if yes, it recalculates the pitch
2223                 * for all active voices.
2224                 */
2225                void ProcessScaleTuningChange() {
2226                    const bool changed = ScaleTuningChanged.readAndReset();
2227                    if (!changed) return;
2228                    
2229                    for (int i = 0; i < engineChannels.size(); i++) {
2230                        EngineChannelBase<V, R, I>* channel =
2231                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
2232                        channel->OnScaleTuningChanged();
2233                    }
2234                }
2235    
2236          private:          private:
2237                Pool< Note<V> >* pNotePool;
2238                Pool<note_id_t> noteIDPool;
2239              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2240              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2241              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2410  
changed lines
  Added in v.3283

  ViewVC Help
Powered by ViewVC