/[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 2559 by schoenebeck, Sun May 18 17:38:25 2014 UTC revision 3688 by schoenebeck, Thu Jan 2 23:47:42 2020 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 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 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                  }                  }
# Line 178  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202                      PostProcess(engineChannels[i]);                      PostProcess(engineChannels[i]);
203                  }                  }
204    
205                    // Just for debugging: dump the amount of free Note objects to
206                    // the terminal (note due to the static variables being used,
207                    // this is currently just intended for debugging with only one
208                    // engine channel).
209                    #if (CONFIG_DEBUG_LEVEL >= 3)
210                    {
211                        static int slice = 0;
212                        static int noteCount = -1;
213                        if (slice++ % 10 == 0) {
214                            int n = pNotePool->countFreeElements();
215                            if (n != noteCount) {
216                                noteCount = n;
217                                dmsg(1,("[%d] free Note objects count = %d\n", slice / 10, n));
218                            }
219                        }
220                    }
221                    #endif
222    
223                  // empty the engine's event list for the next audio fragment                  // empty the engine's event list for the next audio fragment
224                  ClearEventLists();                  ClearEventLists();
# Line 235  namespace LinuxSampler { Line 276  namespace LinuxSampler {
276                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
277                  }                  }
278    
279                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
280                  try {                  try {
281                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
282                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
283                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
284                  } catch (...) {                  } catch (...) {
285                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
286                  }                  }
287    
288                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
289                         iterVoice; iterVoice = pVoicePool->allocAppend())
290                    {
291                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
292                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
293                  }                  }
294                  pVoicePool->clear();                  pVoicePool->clear();
295    
296                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
297                         itNote = pNotePool->allocAppend())
298                    {
299                        itNote->init(pVoicePool, &noteIDPool);
300                    }
301                    pNotePool->clear();
302    
303                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
304                  ResumeAll();                  ResumeAll();
305              }              }
# Line 315  namespace LinuxSampler { Line 368  namespace LinuxSampler {
368                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
369                      // lower minimum release time                      // lower minimum release time
370                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
371                        pVoicePool->clear();
372                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
373                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
374                      }                      }
# Line 335  namespace LinuxSampler { Line 389  namespace LinuxSampler {
389                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
390                  }                  }
391    
392                    pVoicePool->clear();
393                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
394                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
395                      dmsg(3,("d"));                      dmsg(3,("d"));
396                  }                  }
397                  pVoicePool->clear();                  pVoicePool->clear();
398    
399                  // (re)create event generator                  // update event generator
400                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
401    
402                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
403                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 432  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
487               */               */
488              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
489                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
490                  {                  {
491                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
492                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
493                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
494                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  }                  }
496                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
497              }              }
498    
499              /**              /**
# Line 449  namespace LinuxSampler { Line 503  namespace LinuxSampler {
503               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
504               */               */
505              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
506                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
507                  {                  {
508                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
509                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
510                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
511                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
512                  }                  }
513                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
514              }              }
515    
516              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 559  namespace LinuxSampler { Line 613  namespace LinuxSampler {
613              }              }
614    
615              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
616              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
617                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
618                  return pRegionPool[index];                  return pRegionPool[index];
619              }              }
620    
621              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
622              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
623                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
624                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
625    
626              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
627    
# Line 585  namespace LinuxSampler { Line 641  namespace LinuxSampler {
641                  }                  }
642    
643                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
644                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
645                        VoiceIterator itVoice = itNote->pActiveVoices->first();
646                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
647                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
648    
# Line 608  namespace LinuxSampler { Line 665  namespace LinuxSampler {
665    
666              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
667              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
668                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
669              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
670              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
671              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
672                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
673              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
674              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
675              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
676              int iMaxDiskStreams;              int iMaxDiskStreams;
677    
678                NoteBase* NoteByID(note_id_t id) OVERRIDE {
679                    NoteIterator itNote = GetNotePool()->fromID(id);
680                    if (!itNote) return NULL;
681                    return &*itNote;
682                }
683    
684                /**
685                 * Gets a new @c Note object from the note pool, initializes it
686                 * appropriately, links it with requested parent note (if
687                 * requested), moves it to the appropriate key's list of active
688                 * notes it, and sticks the new note's unique ID to the
689                 * passed @a pNoteOnEvent.
690                 *
691                 * @param pEngineChannel - engine channel on which this event happened
692                 * @param pNoteOnEvent - event which caused this
693                 * @returns new note's unique ID (or zero on error)
694                 */
695                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
696                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
697                    Pool< Note<V> >* pNotePool = GetNotePool();
698    
699                    if (pNotePool->poolIsEmpty()) {
700                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
701                        return 0; // error
702                    }
703    
704                    // create a new note (for new voices to be assigned to)
705                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
706                    NoteIterator itNewNote = pNotePool->allocAppend();
707                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
708    
709                    // remember the engine's time when this note was triggered exactly
710                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
711    
712                    // usually the new note (and its subsequent voices) will be
713                    // allocated on the key provided by the event's note number,
714                    // however if this new note is requested not to be a regular
715                    // note, but rather a child note, then this new note will be
716                    // allocated on the parent note's key instead in order to
717                    // release the child note simultaniously with its parent note
718                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
719    
720                    // in case this new note was requested to be a child note,
721                    // then retrieve its parent note and link them with each other
722                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
723                    if (parentNoteID) {
724                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
725                        if (itParentNote) {
726                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
727                            if (itChildNoteID) {
728                                // link parent and child note with each other
729                                *itChildNoteID = newNoteID;
730                                itNewNote->parentNoteID = parentNoteID;
731                                itNewNote->hostKey = itParentNote->hostKey;
732                            } else {    
733                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
734                                pNotePool->free(itNewNote);
735                                return 0; // error
736                            }
737                        } else {
738                            // the parent note was apparently released already, so
739                            // free the new note again and inform caller that it
740                            // should drop the event
741                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
742                            pNotePool->free(itNewNote);
743                            return 0; // error
744                        }
745                    }
746    
747                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
748    
749                    // copy event which caused this note
750                    itNewNote->cause = *itNoteOnEvent;
751                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
752                    if (!itNewNote->eventID) {
753                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
754                    }
755    
756                    // move new note to its host key
757                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
758                    itNewNote.moveToEndOf(pKey->pActiveNotes);
759                    pChannel->markKeyAsActive(pKey);
760    
761                    // assign unique note ID of this new note to the original note on event
762                    itNoteOnEvent->Param.Note.ID = newNoteID;
763    
764                    return newNoteID; // success
765                }
766    
767              /**              /**
768               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
769               * engine channel.               * engine channel.
# Line 631  namespace LinuxSampler { Line 779  namespace LinuxSampler {
779                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
780                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
781    
782                  // process events                  // if a valid real-time instrument script is loaded, pre-process
783                    // the event list by running the script now, since the script
784                    // might filter events or add new ones for this cycle
785                    if (pChannel->pScript) {
786                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
787    
788                        // resume suspended script executions been scheduled for
789                        // this audio fragment cycle (which were suspended in a
790                        // previous audio fragment cycle)
791                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
792    
793                        // spawn new script executions for the new MIDI events of
794                        // this audio fragment cycle
795                        //
796                        // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
797                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
798                            end = pChannel->pEvents->end(); itEvent != end; )
799                        {
800                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
801                            RTList<Event>::Iterator itNext = itEvent;
802                            ++itNext;
803    
804                            switch (itEvent->Type) {
805                                case Event::type_note_on:
806                                    if (pChannel->pScript->handlerNote)
807                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
808                                    break;
809                                case Event::type_note_off:
810                                    if (pChannel->pScript->handlerRelease)
811                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
812                                    break;
813                                case Event::type_control_change:
814                                case Event::type_channel_pressure:
815                                case Event::type_pitchbend:
816                                    if (pChannel->pScript->handlerController)
817                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
818                                    break;
819                                case Event::type_note_pressure:
820                                    //TODO: ...
821                                    break;
822    
823                                case Event::type_sysex:
824                                    //TODO: ...
825                                    break;
826    
827                                case Event::type_cancel_release_key:
828                                case Event::type_release_key:
829                                case Event::type_release_note:
830                                case Event::type_play_note:
831                                case Event::type_stop_note:
832                                case Event::type_kill_note:
833                                case Event::type_note_synth_param:
834                                    break; // noop
835                            }
836    
837                            // see HACK comment above
838                            itEvent = itNext;
839                        }
840    
841                        // this has to be run again, since the newly spawned scripts
842                        // above may have cause suspended scripts that must be
843                        // resumed within this same audio fragment cycle
844                        //
845                        // FIXME: see FIXME comment above
846                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
847                    }
848    
849                    // if there are any delayed events scheduled for the current
850                    // audio fragment cycle, then move and sort them into the main
851                    // event list
852                    if (!pChannel->delayedEvents.queue.isEmpty()) {
853                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
854                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
855                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
856                        while (true) {
857                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
858                                pEventGenerator->popNextScheduledEvent(
859                                    pChannel->delayedEvents.queue,
860                                    pChannel->delayedEvents.schedulerNodes,
861                                    fragmentEndTime
862                                );
863                            if (!itDelayedEventNode) break;
864                            // get the actual delayed event object and free the used scheduler node
865                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
866                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
867                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
868                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
869                                continue;
870                            }
871                            // skip all events on main event list which have a time
872                            // before (or equal to) the delayed event to be inserted
873                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
874                                 ++itEvent);
875                            // now move delayed event from delayedEvents.pList to
876                            // the current position on the main event list
877                            itEvent = itDelayedEvent.moveBefore(itEvent);
878                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
879                        }
880                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
881                    }
882    
883                    // now process all events regularly
884                  {                  {
885                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
886                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 641  namespace LinuxSampler { Line 890  namespace LinuxSampler {
890                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
891                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
892                                  break;                                  break;
893                                case Event::type_play_note:
894                                    dmsg(5,("Engine: Play Note received\n"));
895                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
896                                    break;
897                              case Event::type_note_off:                              case Event::type_note_off:
898                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
899                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
900                                  break;                                  break;
901                                case Event::type_stop_note:
902                                    dmsg(5,("Engine: Stop Note received\n"));
903                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
904                                    break;
905                                case Event::type_kill_note:
906                                    dmsg(5,("Engine: Kill Note received\n"));
907                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
908                                    break;
909                              case Event::type_control_change:                              case Event::type_control_change:
910                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
911                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 661  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
923                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
924                                  break;                                  break;
925                                case Event::type_note_synth_param:
926                                    dmsg(5,("Engine: Note Synth Param received\n"));
927                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
928                                    break;
929                                case Event::type_sysex:
930                                    break; // TODO ...
931    
932                                case Event::type_cancel_release_key:
933                                case Event::type_release_key:
934                                case Event::type_release_note:
935                                    break; // noop
936                          }                          }
937                      }                      }
938                  }                  }
# Line 668  namespace LinuxSampler { Line 940  namespace LinuxSampler {
940                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
941                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
942                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
943                    itLastStolenNote          = NoteIterator();
944                    itLastStolenNoteGlobally  = NoteIterator();
945                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
946                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
947                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
948              }              }
949    
950              /**              /**
951                 * Run all suspended script execution instances which are scheduled
952                 * to be resumed for the current audio fragment cycle.
953                 *
954                 * @param pChannel - engine channel on which suspended events occurred
955                 */
956                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
957                    while (true) {
958                        RTList<ScriptEvent>::Iterator itEvent =
959                            pEventGenerator->popNextScheduledScriptEvent(
960                                pChannel->pScript->suspendedEvents,
961                                *pChannel->pScript->pEvents, fragmentEndTime
962                            );
963                        if (!itEvent) break;
964                        ResumeScriptEvent(pChannel, itEvent);
965                    }
966                }
967    
968                /** @brief Call instrument script's event handler for this event.
969                 *
970                 * Causes a new execution instance of the currently loaded real-time
971                 * instrument script's event handler (callback) to be spawned for
972                 * the given MIDI event.
973                 *
974                 * @param pChannel - engine channel on which the MIDI event occurred
975                 * @param itEvent - MIDI event that causes this new script execution
976                 * @param pEventHandler - script's event handler to be executed
977                 */
978                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
979                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
980                    // check if polyphonic data is passed from "note" to "release"
981                    // script event handlers
982                    if (pEventHandler == pChannel->pScript->handlerRelease &&
983                        pChannel->pScript->handlerNote &&
984                        pChannel->pScript->handlerNote->isPolyphonic() &&
985                        pChannel->pScript->handlerRelease->isPolyphonic() &&
986                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
987                    {
988                        // polyphonic variable data is used/passed from "note" to
989                        // "release" script callback, so we have to recycle the
990                        // original "note on" script event(s)
991                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
992                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
993                        for (; it != end; ++it) {
994                            ProcessScriptEvent(
995                                pChannel, itEvent, pEventHandler, it
996                            );
997                        }
998                    } else {
999                        // no polyphonic data is used/passed from "note" to
1000                        // "release" script callback, so just use a new fresh
1001                        // script event object
1002                        RTList<ScriptEvent>::Iterator itScriptEvent =
1003                            pChannel->pScript->pEvents->allocAppend();
1004                        // if event handler uses polyphonic variables, reset them
1005                        // to zero values before starting to execute the handler
1006                        if (pEventHandler->isPolyphonic())
1007                            itScriptEvent->execCtx->resetPolyphonicData();
1008                        ProcessScriptEvent(
1009                            pChannel, itEvent, pEventHandler, itScriptEvent
1010                        );
1011                    }
1012                }
1013    
1014                /** @brief Spawn new execution instance of an instrument script handler.
1015                 *
1016                 * Will be called to initiate a new execution of a real-time
1017                 * instrument script event right from the start of the script's
1018                 * respective handler. If script execution did not complete after
1019                 * calling this method, the respective script exeuction is then
1020                 * suspended and a call to ResumeScriptEvent() will be used next
1021                 * time to continue its execution.
1022                 *
1023                 * @param pChannel - engine channel this script is running for
1024                 * @param itEvent - event which caused execution of this script
1025                 *                  event handler
1026                 * @param pEventHandler - VM representation of event handler to be
1027                 *                        executed
1028                 * @param itScriptEvent - script event that shall be processed
1029                 */
1030                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1031                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
1032    
1033                    // fill the list of script handlers to be executed by this event
1034                    int i = 0;
1035                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
1036                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
1037    
1038                    // initialize/reset other members
1039                    itScriptEvent->cause = *itEvent;
1040                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1041                    itScriptEvent->currentHandler = 0;
1042                    itScriptEvent->executionSlices = 0;
1043                    itScriptEvent->ignoreAllWaitCalls = false;
1044                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1045                    itScriptEvent->parentHandlerID = 0;
1046                    itScriptEvent->childHandlerID[0] = 0;
1047                    itScriptEvent->autoAbortByParent = false;
1048                    itScriptEvent->forkIndex = 0;
1049                    // this is the native representation of the $EVENT_ID script variable
1050                    itScriptEvent->id =
1051                        (itEvent->Type == Event::type_note_on)
1052                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1053                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1054    
1055                    // run script handler(s)
1056                    VMExecStatus_t res = pScriptVM->exec(
1057                        pChannel->pScript->parserContext, &*itScriptEvent
1058                    );
1059    
1060                    // was the script suspended?
1061                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1062                        // in case the script was suspended, keep it on the allocated
1063                        // ScriptEvent list to be resume at the scheduled time in future,
1064                        // additionally insert it into a sorted time queue
1065                        pEventGenerator->scheduleAheadMicroSec(
1066                            pChannel->pScript->suspendedEvents, // scheduler queue
1067                            *itScriptEvent, // script event
1068                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1069                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1070                        );
1071                    } else { // script execution has finished without 'suspended' status ...
1072                        // if "polyphonic" variable data is passed from script's
1073                        // "note" event handler to its "release" event handler, then
1074                        // the script event must be kept and recycled for the later
1075                        // occuring "release" script event ...
1076                        if (pEventHandler == pChannel->pScript->handlerNote &&
1077                            pChannel->pScript->handlerRelease &&
1078                            pChannel->pScript->handlerNote->isPolyphonic() &&
1079                            pChannel->pScript->handlerRelease->isPolyphonic())
1080                        {
1081                            const int key = itEvent->Param.Note.Key;
1082                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1083                        } else {
1084                            // ... otherwise if no polyphonic data is passed and
1085                            // script's execution has finished without suspension
1086                            // status, then free the script event for a new future
1087                            // script event to be triggered from start
1088                            pChannel->pScript->pEvents->free(itScriptEvent);
1089                        }
1090                    }
1091                }
1092    
1093                /** @brief Resume execution of instrument script.
1094                 *
1095                 * Will be called to resume execution of a real-time instrument
1096                 * script event which has been suspended previously.
1097                 *
1098                 * Script execution might be suspended for various reasons. Usually
1099                 * a script will be suspended if the script called the built-in
1100                 * "wait()" function, but it might also be suspended automatically
1101                 * if the script took too much execution time in an audio fragment
1102                 * cycle. So in the latter case automatic suspension is performed in
1103                 * order to avoid harm for the sampler's overall real-time
1104                 * requirements.
1105                 *
1106                 * @param pChannel - engine channel this script is running for
1107                 * @param itScriptEvent - script execution that shall be resumed
1108                 */
1109                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1110                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1111    
1112                    // run script
1113                    VMExecStatus_t res = pScriptVM->exec(
1114                        pChannel->pScript->parserContext, &*itScriptEvent
1115                    );
1116    
1117                    // was the script suspended?
1118                    if (res & VM_EXEC_SUSPENDED) {
1119                        // in case the script was suspended, keep it on the allocated
1120                        // ScriptEvent list to be resume at the scheduled time in future,
1121                        // additionally insert it into a sorted time queue
1122                        pEventGenerator->scheduleAheadMicroSec(
1123                            pChannel->pScript->suspendedEvents, // scheduler queue
1124                            *itScriptEvent, // script event
1125                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1126                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1127                        );
1128                    } else { // script execution has finished without 'suspended' status ...
1129                        // if "polyphonic" variable data is passed from script's
1130                        // "note" event handler to its "release" event handler, then
1131                        // the script event must be kept and recycled for the later
1132                        // occuring "release" script event ...
1133                        if (handler && handler == pChannel->pScript->handlerNote &&
1134                            pChannel->pScript->handlerRelease &&
1135                            pChannel->pScript->handlerNote->isPolyphonic() &&
1136                            pChannel->pScript->handlerRelease->isPolyphonic())
1137                        {
1138                            const int key = itScriptEvent->cause.Param.Note.Key;
1139                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1140                        } else {
1141                            // ... otherwise if no polyphonic data is passed and
1142                            // script's execution has finished without suspension
1143                            // status, then free the script event for a new future
1144                            // script event to be triggered from start
1145                            pChannel->pScript->pEvents->free(itScriptEvent);
1146                        }
1147                    }
1148                }
1149    
1150                /**
1151               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1152               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1153               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1154               *  voice actually died.               *  voice actually died.
1155               *               *
1156               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1157               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1158               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1159               */               */
1160              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1161                    dmsg(3,("StealVoice()\n"));
1162                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1163                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1164                      return -1;                      return -1;
# Line 691  namespace LinuxSampler { Line 1166  namespace LinuxSampler {
1166    
1167                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1168    
1169                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1170                        dmsg(1,("Event pool emtpy!\n"));
1171                        return -1;
1172                    }
1173    
1174                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1175                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1176                          return 0;                      return 0;
1177                      }                  }
1178    
1179                      // if we couldn't steal a voice from the same engine channel then                  // if we couldn't steal a voice from the same engine channel then
1180                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1181                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1182                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1183                      int                       iChannelIndex;                  int                          iChannelIndex;
1184                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
   
                     // select engine channel  
                     if (pLastStolenChannel) {  
                         pSelectedChannel = pLastStolenChannel;  
                         iChannelIndex    = pSelectedChannel->iEngineIndexSelf;  
                     } else { // pick the engine channel followed by this engine channel  
                         iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
                     }  
   
                     // if we already stole in this fragment, try to proceed on same key  
                     if (this->itLastStolenVoiceGlobally) {  
                         itSelectedVoice = this->itLastStolenVoiceGlobally;  
                         do {  
                             ++itSelectedVoice;  
                         } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle  
                     }  
1185    
1186                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1187                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = NULL; // to detect endless loop
1188                      #endif // CONFIG_DEVMODE                  #endif
1189    
1190                    // select engine channel
1191                    if (pLastStolenChannel) {
1192                        pSelectedChannel = pLastStolenChannel;
1193                        iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1194                    } else { // pick the engine channel followed by this engine channel
1195                        iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1196                        pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1197                    }
1198    
1199                    // if we already stole in this fragment, try to proceed on same note
1200                    if (this->itLastStolenVoiceGlobally) {
1201                        itSelectedVoice = this->itLastStolenVoiceGlobally;
1202                        do {
1203                            ++itSelectedVoice;
1204                        } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1205                    }
1206                    // did we find a 'stealable' voice?
1207                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1208                        // remember which voice we stole, so we can simply proceed on next voice stealing
1209                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1210                        // done
1211                        goto stealable_voice_found;
1212                    }
1213    
1214                    // get (next) oldest note
1215                    if (this->itLastStolenNoteGlobally) {
1216                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1217                             itNote; ++itNote)
1218                        {
1219                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1220                                // proceed iterating if voice was created in this audio fragment cycle
1221                                if (itSelectedVoice->IsStealable()) {
1222                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1223                                    this->itLastStolenNoteGlobally  = itNote;
1224                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1225                                    goto stealable_voice_found; // selection succeeded
1226                                }
1227                            }
1228                        }
1229                    }
1230    
1231                      // did we find a 'stealable' voice?                  #if CONFIG_DEVMODE
1232                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                  pBegin = pSelectedChannel; // to detect endless loop
1233                          // remember which voice we stole, so we can simply proceed on next voice stealing                  #endif // CONFIG_DEVMODE
1234                          this->itLastStolenVoiceGlobally = itSelectedVoice;  
1235                      } else while (true) { // iterate through engine channels                  while (true) { // iterate through engine channels                        
1236                          // get (next) oldest key                      // get (next) oldest key
1237                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1238                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1239                          while (iuiSelectedKey) {                      while (iuiSelectedKey) {
1240                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1241                              itSelectedVoice = pSelectedKey->pActiveVoices->first();  
1242                            for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1243                                 itNotesEnd = pSelectedKey->pActiveNotes->end();
1244                                 itNote != itNotesEnd; ++itNote)
1245                            {
1246                                itSelectedVoice = itNote->pActiveVoices->first();
1247                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1248                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1249                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1250                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1251                                  // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing                                  // remember which voice of which note on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1252                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1253                                    this->itLastStolenNoteGlobally  = itNote;
1254                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1255                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1256                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1257                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // 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);  
1258                          }                          }
1259                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1260                      }                      }
1261                        // get next engine channel
1262                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1263                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1264    
1265                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1266                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1267                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1268                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1269                            dmsg(1,("Exiting.\n"));
1270                            exit(-1);
1271                      }                      }
1272                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1273                    }
1274    
1275                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1276                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1277    
1278                      return 0; // success                  #if CONFIG_DEVMODE
1279                  }                  if (!itSelectedVoice->IsActive()) {
1280                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1281                      return -1;                      return -1;
1282                  }                  }
1283                    #endif // CONFIG_DEVMODE
1284    
1285                    // now kill the selected voice
1286                    itSelectedVoice->Kill(itNoteOnEvent);
1287    
1288                    --VoiceSpawnsLeft;
1289    
1290                    return 0; // success
1291              }              }
1292    
1293              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 805  namespace LinuxSampler { Line 1309  namespace LinuxSampler {
1309                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1310                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1311                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1312                            pEngineChannel->pScript =
1313                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1314                          instrumentChanged = true;                          instrumentChanged = true;
1315    
1316                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1317    
1318                            // the script's "init" event handler is only executed
1319                            // once (when the script is loaded or reloaded)
1320                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1321                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1322                                RTList<ScriptEvent>::Iterator itScriptEvent =
1323                                    pEngineChannel->pScript->pEvents->allocAppend();
1324    
1325                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1326                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1327                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1328                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1329                                itScriptEvent->id = 0;
1330                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1331                                itScriptEvent->handlers[1] = NULL;
1332                                itScriptEvent->currentHandler = 0;
1333                                itScriptEvent->executionSlices = 0;
1334                                itScriptEvent->ignoreAllWaitCalls = false;
1335                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1336                                itScriptEvent->parentHandlerID = 0;
1337                                itScriptEvent->childHandlerID[0] = 0;
1338                                itScriptEvent->autoAbortByParent = false;
1339                                itScriptEvent->forkIndex = 0;
1340    
1341                                VMExecStatus_t res;
1342                                size_t instructionsCount = 0;
1343                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1344                                bool bWarningShown = false;
1345                                do {
1346                                    res = pScriptVM->exec(
1347                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1348                                    );
1349                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1350                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1351                                        bWarningShown = true;
1352                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1353                                    }
1354                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1355    
1356                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1357                            }
1358                      }                      }
1359                  }                  }
1360    
# Line 858  namespace LinuxSampler { Line 1405  namespace LinuxSampler {
1405                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1406                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1407                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1408                        
1409                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1410                          LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);                          LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1411                      if (itNewVoice) {                      if (itNewVoice) {
1412                            // usually there should already be a new Note object
1413                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1414                            if (!itNote) { // should not happen, but just to be sure ...
1415                                dmsg(2,("Engine: No Note object for stolen voice!\n"));
1416                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1417                                if (!noteID) {
1418                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1419                                    continue;
1420                                }
1421                                itNote = GetNotePool()->fromID(noteID);
1422                            }
1423                            // move voice from whereever it was, to the new note's list of active voices
1424                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1425                            // render audio of this new voice for the first time
1426                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1427                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1428                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 895  namespace LinuxSampler { Line 1457  namespace LinuxSampler {
1457              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1458                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1459                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1460                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1461    
1462                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1463                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1464                    pChannel->ClearEventListsOfCurrentFragment();
1465              }              }
1466    
1467              /**              /**
# Line 921  namespace LinuxSampler { Line 1484  namespace LinuxSampler {
1484                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1485                          break;                          break;
1486                      }                      }
1487                      case 6: { // data entry (currently only used for RPN and NRPN controllers)                      case 6: { // data entry (MSB)
1488                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));                          //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1489                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...  
1490                              dmsg(4,("Guess it's an RPN ...\n"));                          // look-ahead: if next MIDI event is data entry LSB,
1491                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                          // then skip this event here for now (to avoid double
1492                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                          // handling of what's supposed to be one RPN/NRPN event)
1493                                  // limit to +- two octaves for now                          if (isNextEventCCNr(itControlChangeEvent, 38))
1494                                  transpose = RTMath::Min(transpose,  24);                              break;
1495                                  transpose = RTMath::Max(transpose, -24);  
1496                                  pChannel->GlobalTranspose = transpose;                          if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1497                                  // workaround, so we won't have hanging notes                              int ch = itControlChangeEvent->Param.CC.Channel;
1498                                  pChannel->ReleaseAllVoices(itControlChangeEvent);                              int param = pChannel->GetMidiRpnParameter();
1499                              }                              int value = itControlChangeEvent->Param.CC.Value << 7;
1500                              // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data  
1501                              pChannel->ResetMidiRpnController();                              // transform event type: CC event -> RPN event
1502                          } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...                              itControlChangeEvent->Type = Event::type_rpn;
1503                              dmsg(4,("Guess it's an NRPN ...\n"));                              itControlChangeEvent->Param.RPN.Channel = ch;
1504                              const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;                              itControlChangeEvent->Param.RPN.Parameter = param;
1505                              const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;                              itControlChangeEvent->Param.RPN.Value = value;
1506                              dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));  
1507                              switch (NrpnCtrlMSB) {                              // do the actual RPN event processing
1508                                  case 0x1a: { // volume level of note (Roland GS NRPN)                              ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1509                                      const uint note = NrpnCtrlLSB;  
1510                                      const uint vol  = itControlChangeEvent->Param.CC.Value;                              // to prevent other data entry messages to be misenterpreted as RPN value
1511                                      dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));                              pChannel->ResetMidiRpnParameter();
1512                                      if (note < 128 && vol < 128)                          } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1513                                          pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];                              int ch = itControlChangeEvent->Param.CC.Channel;
1514                                      break;                              int param = pChannel->GetMidiNrpnParameter();
1515                                  }                              int value = itControlChangeEvent->Param.CC.Value << 7;
1516                                  case 0x1c: { // panpot of note (Roland GS NRPN)  
1517                                      const uint note = NrpnCtrlLSB;                              // transform event type: CC event -> NRPN event
1518                                      const uint pan  = itControlChangeEvent->Param.CC.Value;                              itControlChangeEvent->Type = Event::type_nrpn;
1519                                      dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));                              itControlChangeEvent->Param.RPN.Channel = ch;
1520                                      if (note < 128 && pan < 128) {                              itControlChangeEvent->Param.RPN.Parameter = param;
1521                                          pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];                              itControlChangeEvent->Param.RPN.Value = value;
1522                                          pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];  
1523                                      }                              // do the actual NRPN event processing
1524                                      break;                              ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1525                                  }  
1526                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                              // to prevent other data entry messages to be misenterpreted as NRPN value
1527                                      const uint note = NrpnCtrlLSB;                              pChannel->ResetMidiNrpnParameter();
                                     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;  
                                     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));  
                                     if (note < 128)  
                                         pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;  
                                     break;  
                                 }  
                                 case 0x1e: { // chorus send of note (Roland GS NRPN)  
                                     const uint note = NrpnCtrlLSB;  
                                     const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;  
                                     dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));  
                                     if (note < 128)  
                                         pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;  
                                     break;  
                                 }  
                             }  
                             // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data  
                             pChannel->ResetMidiNrpnController();  
1528                          }                          }
1529                          break;                          break;
1530                      }                      }
# Line 993  namespace LinuxSampler { Line 1539  namespace LinuxSampler {
1539                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1540                          break;                          break;
1541                      }                      }
1542                        case 38: { // data entry (LSB)
1543                            //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1544                            int value = 0;
1545    
1546                            // look-back: if previous MIDI event was data entry MSB,
1547                            // then obtain that value for the MSB value portion
1548                            if (isPrevEventCCNr(itControlChangeEvent, 6))
1549                                value = prevEventOf(itControlChangeEvent)->Param.CC.Value << 7;
1550    
1551                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1552                                int ch = itControlChangeEvent->Param.CC.Channel;
1553                                int param = pChannel->GetMidiRpnParameter();
1554                                value |= itControlChangeEvent->Param.CC.Value;
1555    
1556                                // transform event type: CC event -> RPN event
1557                                itControlChangeEvent->Type = Event::type_rpn;
1558                                itControlChangeEvent->Param.RPN.Channel = ch;
1559                                itControlChangeEvent->Param.RPN.Parameter = param;
1560                                itControlChangeEvent->Param.RPN.Value = value;
1561    
1562                                // do the actual RPN event processing
1563                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1564    
1565                                // to prevent other data entry messages to be misenterpreted as RPN value
1566                                pChannel->ResetMidiRpnParameter();
1567                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1568                                int ch = itControlChangeEvent->Param.CC.Channel;
1569                                int param = pChannel->GetMidiNrpnParameter();
1570                                value |= itControlChangeEvent->Param.CC.Value;
1571    
1572                                // transform event type: CC event -> NRPN event
1573                                itControlChangeEvent->Type = Event::type_nrpn;
1574                                itControlChangeEvent->Param.RPN.Channel = ch;
1575                                itControlChangeEvent->Param.RPN.Parameter = param;
1576                                itControlChangeEvent->Param.RPN.Value = value;
1577    
1578                                // do the actual NRPN event processing
1579                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1580    
1581                                // to prevent other data entry messages to be misenterpreted as NRPN value
1582                                pChannel->ResetMidiNrpnParameter();
1583                            }
1584                            break;
1585                        }
1586                      case 64: { // sustain                      case 64: { // sustain
1587                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1588                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
# Line 1066  namespace LinuxSampler { Line 1656  namespace LinuxSampler {
1656                          }                          }
1657                          break;                          break;
1658                      }                      }
1659                      case 98: { // NRPN controller LSB                      case 98: { // NRPN parameter LSB
1660                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1661                          pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1662                          break;                          break;
1663                      }                      }
1664                      case 99: { // NRPN controller MSB                      case 99: { // NRPN parameter MSB
1665                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1666                          pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1667                          break;                          break;
1668                      }                      }
1669                      case 100: { // RPN controller LSB                      case 100: { // RPN parameter LSB
1670                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1671                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1672                          break;                          break;
1673                      }                      }
1674                      case 101: { // RPN controller MSB                      case 101: { // RPN parameter MSB
1675                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1676                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1677                          break;                          break;
1678                      }                      }
1679    
# Line 1119  namespace LinuxSampler { Line 1709  namespace LinuxSampler {
1709                  }                  }
1710              }              }
1711    
1712                /**
1713                 * Process MIDI RPN events with hard coded behavior.
1714                 *
1715                 * @param pEngineChannel - engine channel on which the MIDI RPN
1716                 *                         event was received
1717                 * @param itRpnEvent - the actual MIDI RPN event
1718                 */
1719                void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1720                                         Pool<Event>::Iterator& itRpnEvent)
1721                {
1722                    EngineChannelBase<V, R, I>* pChannel =
1723                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1724    
1725                    if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1726                        int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1727                        // limit to +- two octaves for now
1728                        transpose = RTMath::Min(transpose,  24);
1729                        transpose = RTMath::Max(transpose, -24);
1730                        pChannel->GlobalTranspose = transpose;
1731                        // workaround, so we won't have hanging notes
1732                        pChannel->ReleaseAllVoices(itRpnEvent);
1733                    }
1734                }
1735    
1736                /**
1737                 * Process MIDI NRPN events with hard coded behavior.
1738                 *
1739                 * @param pEngineChannel - engine channel on which the MIDI NRPN
1740                 *                         event was received
1741                 * @param itRpnEvent - the actual MIDI NRPN event
1742                 */
1743                void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1744                                          Pool<Event>::Iterator& itNrpnEvent)
1745                {
1746                    EngineChannelBase<V, R, I>* pChannel =
1747                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1748    
1749                    switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
1750                        case 0x1a: { // volume level of note (Roland GS NRPN)
1751                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1752                            const uint vol  = itNrpnEvent->Param.NRPN.ValueMSB();
1753                            dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1754                            if (note < 128 && vol < 128)
1755                                pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1756                            break;
1757                        }
1758                        case 0x1c: { // panpot of note (Roland GS NRPN)
1759                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1760                            const uint pan  = itNrpnEvent->Param.NRPN.ValueMSB();
1761                            dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1762                            if (note < 128 && pan < 128) {
1763                                pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
1764                                pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1765                            }
1766                            break;
1767                        }
1768                        case 0x1d: { // reverb send of note (Roland GS NRPN)
1769                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1770                            const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1771                            dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1772                            if (note < 128)
1773                                pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1774                            break;
1775                        }
1776                        case 0x1e: { // chorus send of note (Roland GS NRPN)
1777                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1778                            const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1779                            dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1780                            if (note < 128)
1781                                pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1782                            break;
1783                        }
1784                    }
1785                }
1786    
1787              virtual D* CreateDiskThread() = 0;              virtual D* CreateDiskThread() = 0;
1788    
1789              /**              /**
1790               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1791               *               *
1792               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1793               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1794               */               */
1795              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1796                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1797                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1798    
                 //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;  
   
1799                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1800                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1801                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1802    
1803                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1804    
1805                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1806                    // programmatically spawned notes (Event::type_play_note). We have
1807                    // to distinguish between them, since certain processing below
1808                    // must only be done on real MIDI note-on events (i.e. for
1809                    // correctly updating which MIDI keys are currently pressed down).
1810                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1811    
1812                    if (isRealMIDINoteOnEvent)
1813                        pChannel->listeners.PreProcessNoteOn(key, vel);
1814    
1815                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1816                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1817                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1818                            pChannel->listeners.PostProcessNoteOn(key, vel);
1819                      return;                      return;
1820                  }                  }
1821                  #endif                  #endif
1822    
1823                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1824                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1825                            pChannel->listeners.PostProcessNoteOn(key, vel);
1826                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1827                  }                  }
1828    
# Line 1158  namespace LinuxSampler { Line 1830  namespace LinuxSampler {
1830                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1831    
1832                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1833                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1834                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1835                      if (itYoungestKey) {                      if (itYoungestKey) {
1836                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1166  namespace LinuxSampler { Line 1838  namespace LinuxSampler {
1838                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1839                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1840                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1841                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1842                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1843                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1844                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1845                                    }
1846                              }                              }
1847                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1848                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1849                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1850                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1851                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1852                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1853                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1854                                    }
1855                              }                              }
1856                          }                          }
1857                      }                      }
# Line 1182  namespace LinuxSampler { Line 1859  namespace LinuxSampler {
1859                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1860                  }                  }
1861    
1862                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1863                        pChannel->ProcessKeySwitchChange(key);
1864    
1865                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1866                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1867                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1868                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1869                    }
1870    
1871                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1872                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1873                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1874                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1875                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1876                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1877                      }                      }
1878                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1879                  }                  }
# Line 1204  namespace LinuxSampler { Line 1884  namespace LinuxSampler {
1884                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1885                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1886    
1887                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1888                        pChannel->PortamentoPos = (float) key;
1889    
1890                    //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?
1891                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1892                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1893                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1894                  }                  }
1895                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1896                    if (isRealMIDINoteOnEvent)
1897                        pChannel->listeners.PostProcessNoteOn(key, vel);
1898              }              }
1899    
1900              /**              /**
# Line 1235  namespace LinuxSampler { Line 1920  namespace LinuxSampler {
1920               *  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.
1921               *  due to completion of sample playback).               *  due to completion of sample playback).
1922               *               *
1923               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1924               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1925               */               */
1926              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1927                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1928    
                 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;  
   
1929                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1930                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1931                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1932    
1933                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1934    
1935                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1936                    // programmatically spawned notes (Event::type_stop_note). We have
1937                    // to distinguish between them, since certain processing below
1938                    // must only be done on real MIDI note-off events (i.e. for
1939                    // correctly updating which MIDI keys are currently pressed down),
1940                    // plus a stop-note event just releases voices of one particular
1941                    // note, whereas a note-off event releases all voices on a
1942                    // particular MIDI key instead.
1943                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1944    
1945                    if (isRealMIDINoteOffEvent)
1946                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1947    
1948                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1949                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1950                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1951                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1952                      return;                      return;
1953                  }                  }
1954                  #endif                  #endif
1955    
1956                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1957                        pKey->KeyPressed = false; // the MIDI key was now released
1958                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1959                    }
1960    
1961                  // move event to the key's own event list                  // move event to the key's own event list
1962                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1963    
1964                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1965                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1966    
1967                  // 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)
1968                  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
1969                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1970                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1971                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1972                          // 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
1973                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1974                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1975                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1976                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1977                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1978                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1979                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1980                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1981                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1982                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1983                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1984                                  // create a pseudo note on event                                      }
1985                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1986                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1987                                      // copy event                                      if (itPseudoNoteOnEvent) {
1988                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1989                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1990                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1991                                      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)
1992                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1993                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1994                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1995                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1996                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1997                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1998                                            }
1999                                            // if neither a voice was spawned or postponed then remove note on event from key again
2000                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2001                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2002    
2003                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
2004                                  break; // done                                      break; // done
2005                                    }
2006                              }                              }
2007                          }                          }
2008                      }                          if (bOtherKeysPressed) {
2009                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
2010                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
2011                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2012                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2013                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
2014                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2015                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2016                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2017                                        }
2018                                    }
2019                              }                              }
2020                          }                          } else pChannel->PortamentoPos = -1.0f;
2021                      } 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  
2022    
2023                      // 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
2024                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
2025                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2026                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
2027                            if (pKey->ReleaseTrigger & release_trigger_noteoff)
2028                                ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2029                        }
2030                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2031                        // This programmatically caused event is caused by a call to
2032                        // the built-in instrument script function note_off(). In
2033                        // contrast to a real MIDI note-off event the stop-note
2034                        // event just intends to release voices of one particular note.
2035                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2036                        if (pNote) { // the requested note is still alive ...
2037                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2038                        } else { // note is dead and gone ..
2039                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2040                            return; // prevent event to be removed a 2nd time below
2041                      }                      }
2042                  }                  }
2043    
# Line 1332  namespace LinuxSampler { Line 2045  namespace LinuxSampler {
2045                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2046                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
2047    
2048                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
2049                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
2050                }
2051    
2052                /**
2053                 * Called on sustain pedal up events to check and if required,
2054                 * launch release trigger voices on the respective active key.
2055                 *
2056                 * @param pEngineChannel - engine channel on which this event occurred on
2057                 * @param itEvent - release trigger event (contains note number)
2058                 */
2059                virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2060                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2061    
2062                    const int iKey = itEvent->Param.Note.Key;
2063                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2064    
2065                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2066    
2067                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
2068                }
2069    
2070                /**
2071                 * Called on note-off and sustain pedal up events to check and if
2072                 * required, launch release trigger voices on the respective active
2073                 * key.
2074                 *
2075                 * @param pEngineChannel - engine channel on which this event occurred on
2076                 * @param itEvent - note off event / release trigger event
2077                 * @param pKey - key on which the release trigger voices shall be spawned
2078                 */
2079                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2080                    // spawn release triggered voice(s) if needed
2081                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2082                        // assign a new note to this release event
2083                        if (LaunchNewNote(pChannel, itEvent)) {
2084                            // allocate and trigger new release voice(s)
2085                            TriggerReleaseVoices(pChannel, itEvent);
2086                        }
2087                        pKey->ReleaseTrigger = release_trigger_none;
2088                    }
2089                }
2090    
2091                /**
2092                 * Called on "kill note" events, which currently only happens on
2093                 * built-in real-time instrument script function fade_out(). This
2094                 * method only fulfills one task: moving the even to the Note's own
2095                 * event list so that its voices can process the kill event sample
2096                 * accurately.
2097                 */
2098                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2099                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2100    
2101                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2102                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2103    
2104                    // move note kill event to its MIDI key
2105                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2106                    itEvent.moveToEndOf(pKey->pEvents);
2107                }
2108    
2109                /**
2110                 * Called on note synthesis parameter change events. These are
2111                 * internal events caused by calling built-in real-time instrument
2112                 * script functions like change_vol(), change_tune(), etc.
2113                 *
2114                 * This method performs two tasks:
2115                 *
2116                 * - It converts the event's relative values changes (Deltas) to
2117                 *   the respective final new synthesis parameter value (AbsValue),
2118                 *   for that particular moment of the event that is.
2119                 *
2120                 * - It moves the individual events to the Note's own event list
2121                 *   (or actually to the event list of the MIDI key), so that
2122                 *   voices can process those events sample accurately.
2123                 *
2124                 * @param pEngineChannel - engine channel on which this event occurred on
2125                 * @param itEvent - note synthesis parameter change event
2126                 */
2127                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2128                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2129    
2130                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2131                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2132    
2133                    switch (itEvent->Param.NoteSynthParam.Type) {
2134                        case Event::synth_param_volume:
2135                            pNote->apply(itEvent, &NoteBase::_Override::Volume);
2136                            break;
2137                        case Event::synth_param_volume_time:
2138                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2139                            break;
2140                        case Event::synth_param_volume_curve:
2141                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2142                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2143                            break;
2144                        case Event::synth_param_pitch:
2145                            pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2146                            break;
2147                        case Event::synth_param_pitch_time:
2148                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2149                            break;
2150                        case Event::synth_param_pitch_curve:
2151                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2152                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2153                            break;
2154                        case Event::synth_param_pan:
2155                            pNote->apply(itEvent, &NoteBase::_Override::Pan);
2156                            break;
2157                        case Event::synth_param_pan_time:
2158                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2159                            break;
2160                        case Event::synth_param_pan_curve:
2161                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2162                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2163                            break;
2164                        case Event::synth_param_cutoff:
2165                            pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2166                            break;
2167                        case Event::synth_param_resonance:
2168                            pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2169                            break;
2170                        case Event::synth_param_attack:
2171                            pNote->apply(itEvent, &NoteBase::_Override::Attack);
2172                            break;
2173                        case Event::synth_param_decay:
2174                            pNote->apply(itEvent, &NoteBase::_Override::Decay);
2175                            break;
2176                        case Event::synth_param_sustain:
2177                            pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2178                            break;
2179                        case Event::synth_param_release:
2180                            pNote->apply(itEvent, &NoteBase::_Override::Release);
2181                            break;
2182    
2183                        case Event::synth_param_cutoff_attack:
2184                            pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2185                            break;
2186                        case Event::synth_param_cutoff_decay:
2187                            pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2188                            break;
2189                        case Event::synth_param_cutoff_sustain:
2190                            pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2191                            break;
2192                        case Event::synth_param_cutoff_release:
2193                            pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2194                            break;
2195    
2196                        case Event::synth_param_amp_lfo_depth:
2197                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2198                            break;
2199                        case Event::synth_param_amp_lfo_freq:
2200                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2201                            break;
2202                        case Event::synth_param_cutoff_lfo_depth:
2203                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2204                            break;
2205                        case Event::synth_param_cutoff_lfo_freq:
2206                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2207                            break;
2208                        case Event::synth_param_pitch_lfo_depth:
2209                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2210                            break;
2211                        case Event::synth_param_pitch_lfo_freq:
2212                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2213                            break;
2214                    }
2215    
2216                    // move note parameter event to its MIDI key
2217                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2218                    itEvent.moveToEndOf(pKey->pEvents);
2219              }              }
2220    
2221              /**              /**
2222               *  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
2223               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2224               */               */
2225              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2226                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2227    
2228                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1352  namespace LinuxSampler { Line 2235  namespace LinuxSampler {
2235                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2236                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2237                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2238                    itLastStolenNote           = NoteIterator();
2239                    itLastStolenNoteGlobally   = NoteIterator();
2240                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2241                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2242                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2243    
2244                    // reset all notes
2245                    pNotePool->clear();
2246                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2247                         itNote = pNotePool->allocAppend())
2248                    {
2249                        itNote->reset();
2250                    }
2251                    pNotePool->clear();
2252    
2253                  // reset all voices                  // reset all voices
2254                    pVoicePool->clear();
2255                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2256                      iterVoice->Reset();                      iterVoice->Reset();
2257                  }                  }
2258                  pVoicePool->clear();                  pVoicePool->clear();
2259    
2260                    // reset all engine channels
2261                    for (int i = 0; i < engineChannels.size(); i++) {
2262                        AbstractEngineChannel* pEngineChannel =
2263                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2264                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2265                    }
2266    
2267                  // reset disk thread                  // reset disk thread
2268                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2269    
# Line 1379  namespace LinuxSampler { Line 2281  namespace LinuxSampler {
2281               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2282               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2283               */               */
2284              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2285                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2286                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2287                  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 1390  namespace LinuxSampler { Line 2292  namespace LinuxSampler {
2292               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2293               *  (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).
2294               *               *
2295               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2296               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2297               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2298               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1414  namespace LinuxSampler { Line 2316  namespace LinuxSampler {
2316                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2317              ) = 0;              ) = 0;
2318    
2319              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2320    
2321              int InitNewVoice (              int InitNewVoice (
2322                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1433  namespace LinuxSampler { Line 2335  namespace LinuxSampler {
2335                      // launch the new voice                      // launch the new voice
2336                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2337                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2338                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2339                      }                      }
2340                      else { // on success                      else { // on success
2341                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2342                          if (!pKey->Active) { // mark as active key  
2343                              pKey->Active = true;                          // should actually be superfluous now, since this is
2344                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2345                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2346                          }  
2347                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)                          if (itNewVoice->Type & Voice::type_release_trigger_required)
2348                                pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2349                          return 0; // success                          return 0; // success
2350                      }                      }
2351                  }                  }
# Line 1482  namespace LinuxSampler { Line 2385  namespace LinuxSampler {
2385              }              }
2386    
2387          private:          private:
2388                Pool< Note<V> >* pNotePool;
2389                Pool<note_id_t> noteIDPool;
2390              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2391              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2392              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2559  
changed lines
  Added in v.3688

  ViewVC Help
Powered by ViewVC