/[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 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC revision 3221 by schoenebeck, Fri May 26 18:30:42 2017 UTC
# Line 5  Line 5 
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *   *   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 33  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 46  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 80  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 141  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 236  namespace LinuxSampler { Line 259  namespace LinuxSampler {
259                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
260                  }                  }
261    
262                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
263                  try {                  try {
264                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
265                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
266                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
267                  } catch (...) {                  } catch (...) {
268                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
269                  }                  }
270    
271                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
272                         iterVoice; iterVoice = pVoicePool->allocAppend())
273                    {
274                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
275                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
276                  }                  }
277                  pVoicePool->clear();                  pVoicePool->clear();
278    
279                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
280                         itNote = pNotePool->allocAppend())
281                    {
282                        itNote->init(pVoicePool, &noteIDPool);
283                    }
284                    pNotePool->clear();
285    
286                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
287                  ResumeAll();                  ResumeAll();
288              }              }
# Line 316  namespace LinuxSampler { Line 351  namespace LinuxSampler {
351                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
352                      // lower minimum release time                      // lower minimum release time
353                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
354                        pVoicePool->clear();
355                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
356                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
357                      }                      }
# Line 336  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
373                  }                  }
374    
375                    pVoicePool->clear();
376                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
377                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
378                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 560  namespace LinuxSampler { Line 597  namespace LinuxSampler {
597              }              }
598    
599              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
600              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
601                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
602                  return pRegionPool[index];                  return pRegionPool[index];
603              }              }
604    
605              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
606              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
607                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
608                virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
609    
610              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
611    
# Line 586  namespace LinuxSampler { Line 625  namespace LinuxSampler {
625                  }                  }
626    
627                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
628                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
629                        VoiceIterator itVoice = itNote->pActiveVoices->first();
630                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
631                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
632    
# Line 609  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649    
650              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)
651              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.
652                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
653              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.
654              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.
655              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
656                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
657              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
658              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.
659              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).
660              int iMaxDiskStreams;              int iMaxDiskStreams;
661    
662                NoteBase* NoteByID(note_id_t id) OVERRIDE {
663                    NoteIterator itNote = GetNotePool()->fromID(id);
664                    if (!itNote) return NULL;
665                    return &*itNote;
666                }
667    
668                /**
669                 * Gets a new @c Note object from the note pool, initializes it
670                 * appropriately, links it with requested parent note (if
671                 * requested), moves it to the appropriate key's list of active
672                 * notes it, and sticks the new note's unique ID to the
673                 * passed @a pNoteOnEvent.
674                 *
675                 * @param pEngineChannel - engine channel on which this event happened
676                 * @param pNoteOnEvent - event which caused this
677                 * @returns new note's unique ID (or zero on error)
678                 */
679                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
680                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
681                    Pool< Note<V> >* pNotePool = GetNotePool();
682    
683                    if (pNotePool->poolIsEmpty()) {
684                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
685                        return 0; // error
686                    }
687    
688                    // create a new note (for new voices to be assigned to)
689                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
690                    NoteIterator itNewNote = pNotePool->allocAppend();
691                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
692    
693                    // remember the engine's time when this note was triggered exactly
694                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
695    
696                    // usually the new note (and its subsequent voices) will be
697                    // allocated on the key provided by the event's note number,
698                    // however if this new note is requested not to be a regular
699                    // note, but rather a child note, then this new note will be
700                    // allocated on the parent note's key instead in order to
701                    // release the child note simultaniously with its parent note
702                    itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
703    
704                    // in case this new note was requested to be a child note,
705                    // then retrieve its parent note and link them with each other
706                    const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
707                    if (parentNoteID) {
708                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
709                        if (itParentNote) {
710                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
711                            if (itChildNoteID) {
712                                // link parent and child note with each other
713                                *itChildNoteID = newNoteID;
714                                itNewNote->parentNoteID = parentNoteID;
715                                itNewNote->hostKey = itParentNote->hostKey;
716                            } else {    
717                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
718                                pNotePool->free(itNewNote);
719                                return 0; // error
720                            }
721                        } else {
722                            // the parent note was apparently released already, so
723                            // free the new note again and inform caller that it
724                            // should drop the event
725                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
726                            pNotePool->free(itNewNote);
727                            return 0; // error
728                        }
729                    }
730    
731                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
732    
733                    // copy event which caused this note
734                    itNewNote->cause = *itNoteOnEvent;
735                    itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
736                    if (!itNewNote->eventID) {
737                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
738                    }
739    
740                    // move new note to its host key
741                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
742                    itNewNote.moveToEndOf(pKey->pActiveNotes);
743    
744                    // assign unique note ID of this new note to the original note on event
745                    itNoteOnEvent->Param.Note.ID = newNoteID;
746    
747                    return newNoteID; // success
748                }
749    
750              /**              /**
751               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
752               * engine channel.               * engine channel.
# Line 648  namespace LinuxSampler { Line 778  namespace LinuxSampler {
778                      //                      //
779                      // 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                      // 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
780                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
781                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
782                      {                      {
783                            //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).
784                            RTList<Event>::Iterator itNext = itEvent;
785                            ++itNext;
786    
787                          switch (itEvent->Type) {                          switch (itEvent->Type) {
788                              case Event::type_note_on:                              case Event::type_note_on:
789                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 668  namespace LinuxSampler { Line 802  namespace LinuxSampler {
802                              case Event::type_note_pressure:                              case Event::type_note_pressure:
803                                  //TODO: ...                                  //TODO: ...
804                                  break;                                  break;
805    
806                                case Event::type_sysex:
807                                    //TODO: ...
808                                    break;
809    
810                                case Event::type_cancel_release_key:
811                                case Event::type_release_key:
812                                case Event::type_release_note:
813                                case Event::type_play_note:
814                                case Event::type_stop_note:
815                                case Event::type_kill_note:
816                                case Event::type_note_synth_param:
817                                    break; // noop
818                          }                          }
819    
820                            // see HACK comment above
821                            itEvent = itNext;
822                      }                      }
823    
824                      // this has to be run again, since the newly spawned scripts                      // this has to be run again, since the newly spawned scripts
# Line 723  namespace LinuxSampler { Line 873  namespace LinuxSampler {
873                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
874                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
875                                  break;                                  break;
876                                case Event::type_play_note:
877                                    dmsg(5,("Engine: Play Note received\n"));
878                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
879                                    break;
880                              case Event::type_note_off:                              case Event::type_note_off:
881                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
882                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
883                                  break;                                  break;
884                                case Event::type_stop_note:
885                                    dmsg(5,("Engine: Stop Note received\n"));
886                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
887                                    break;
888                                case Event::type_kill_note:
889                                    dmsg(5,("Engine: Kill Note received\n"));
890                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
891                                    break;
892                              case Event::type_control_change:                              case Event::type_control_change:
893                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
894                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 743  namespace LinuxSampler { Line 905  namespace LinuxSampler {
905                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
906                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
907                                  break;                                  break;
908                                case Event::type_note_synth_param:
909                                    dmsg(5,("Engine: Note Synth Param received\n"));
910                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
911                                    break;
912                                case Event::type_sysex:
913                                    break; // TODO ...
914    
915                                case Event::type_cancel_release_key:
916                                case Event::type_release_key:
917                                case Event::type_release_note:
918                                    break; // noop
919                          }                          }
920                      }                      }
921                  }                  }
# Line 750  namespace LinuxSampler { Line 923  namespace LinuxSampler {
923                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
924                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
925                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
926                    itLastStolenNote          = NoteIterator();
927                    itLastStolenNoteGlobally  = NoteIterator();
928                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
929                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
930                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
# Line 809  namespace LinuxSampler { Line 984  namespace LinuxSampler {
984                      // script event object                      // script event object
985                      RTList<ScriptEvent>::Iterator itScriptEvent =                      RTList<ScriptEvent>::Iterator itScriptEvent =
986                          pChannel->pScript->pEvents->allocAppend();                          pChannel->pScript->pEvents->allocAppend();
987                        // if event handler uses polyphonic variables, reset them
988                        // to zero values before starting to execute the handler
989                        if (pEventHandler->isPolyphonic())
990                            itScriptEvent->execCtx->resetPolyphonicData();
991                      ProcessScriptEvent(                      ProcessScriptEvent(
992                          pChannel, itEvent, pEventHandler, itScriptEvent                          pChannel, itEvent, pEventHandler, itScriptEvent
993                      );                      );
# Line 841  namespace LinuxSampler { Line 1020  namespace LinuxSampler {
1020    
1021                  // initialize/reset other members                  // initialize/reset other members
1022                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1023                  itScriptEvent->id = pEventPool->getID(itEvent);                  itScriptEvent->scheduleTime = itEvent->SchedTime();
1024                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1025                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1026                    itScriptEvent->ignoreAllWaitCalls = false;
1027                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1028                    // this is the native representation of the $EVENT_ID script variable
1029                    itScriptEvent->id =
1030                        (itEvent->Type == Event::type_note_on)
1031                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
1032                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1033    
1034                  // run script handler(s)                  // run script handler(s)
1035                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
# Line 886  namespace LinuxSampler { Line 1072  namespace LinuxSampler {
1072              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1073               *               *
1074               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1075               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1076               *               *
1077               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1078               * a script will be suspended if the script called the built-in               * a script will be suspended if the script called the built-in
# Line 951  namespace LinuxSampler { Line 1136  namespace LinuxSampler {
1136               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1137               *  @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
1138               */               */
1139              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1140                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1141                      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"));
1142                      return -1;                      return -1;
# Line 959  namespace LinuxSampler { Line 1144  namespace LinuxSampler {
1144    
1145                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1146    
1147                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1148                        dmsg(1,("Event pool emtpy!\n"));
1149                        return -1;
1150                    }
1151    
1152                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1153                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1154                          return 0;                      return 0;
1155                      }                  }
1156    
1157                      // 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
1158                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1159                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1160                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1161                      int                       iChannelIndex;                  int                          iChannelIndex;
1162                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1163    
1164                      // select engine channel                  // select engine channel
1165                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1166                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1167                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1168                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1169                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1170                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1171                      }                  }
1172    
1173                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1174                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1175                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1176                          do {                      do {
1177                              ++itSelectedVoice;                          ++itSelectedVoice;
1178                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1179                    }
1180                    // did we find a 'stealable' voice?
1181                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1182                        // remember which voice we stole, so we can simply proceed on next voice stealing
1183                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1184                        // done
1185                        goto stealable_voice_found;
1186                    }
1187    
1188                    // get (next) oldest note
1189                    if (this->itLastStolenNoteGlobally) {
1190                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1191                             itNote; ++itNote)
1192                        {
1193                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1194                                // proceed iterating if voice was created in this audio fragment cycle
1195                                if (itSelectedVoice->IsStealable()) {
1196                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1197                                    this->itLastStolenNoteGlobally  = itNote;
1198                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1199                                    goto stealable_voice_found; // selection succeeded
1200                                }
1201                            }
1202                      }                      }
1203                    }
1204    
1205                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1206                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1207                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1208    
1209                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1210                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1211                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1212                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1213                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1214                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1215                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1216                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1217                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1218                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1219                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1220                                itSelectedVoice = itNote->pActiveVoices->first();
1221                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1222                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1223                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1224                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1225                                  // 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
1226                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1227                                    this->itLastStolenNoteGlobally  = itNote;
1228                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1229                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1230                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1231                              }                              }
                             ++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);  
1232                          }                          }
1233                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1234                      }                      }
1235                        // get next engine channel
1236                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1237                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1238    
1239                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1240                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1241                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1242                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1243                            dmsg(1,("Exiting.\n"));
1244                            exit(-1);
1245                      }                      }
1246                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1247                    }
1248    
1249                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1250                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
1251    
1252                      --VoiceSpawnsLeft;                  #if CONFIG_DEVMODE
1253                    if (!itSelectedVoice->IsActive()) {
1254                      return 0; // success                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                 }  
                 else {  
                     dmsg(1,("Event pool emtpy!\n"));  
1255                      return -1;                      return -1;
1256                  }                  }
1257                    #endif // CONFIG_DEVMODE
1258    
1259                    // now kill the selected voice
1260                    itSelectedVoice->Kill(itNoteOnEvent);
1261    
1262                    --VoiceSpawnsLeft;
1263    
1264                    return 0; // success
1265              }              }
1266    
1267              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 1082  namespace LinuxSampler { Line 1292  namespace LinuxSampler {
1292                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1293                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1294                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1295                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1296                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1297                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1298    
1299                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1300                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1301                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1302                                itScriptEvent->currentHandler = 0;
1303                              VMExecStatus_t res = pScriptVM->exec(                              itScriptEvent->executionSlices = 0;
1304                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                              itScriptEvent->ignoreAllWaitCalls = false;
1305                              );                              itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1306    
1307                                VMExecStatus_t res;
1308                                size_t instructionsCount = 0;
1309                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1310                                bool bWarningShown = false;
1311                                do {
1312                                    res = pScriptVM->exec(
1313                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1314                                    );
1315                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1316                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1317                                        bWarningShown = true;
1318                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1319                                    }
1320                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1321    
1322                              pEngineChannel->pScript->pEvents->free(itScriptEvent);                              pEngineChannel->pScript->pEvents->free(itScriptEvent);
1323                          }                          }
# Line 1145  namespace LinuxSampler { Line 1371  namespace LinuxSampler {
1371                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1372                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1373                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1374                        
1375                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1376                          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);
1377                      if (itNewVoice) {                      if (itNewVoice) {
1378                            // usually there should already be a new Note object
1379                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1380                            if (!itNote) { // should not happen, but just to be sure ...
1381                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1382                                if (!noteID) {
1383                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1384                                    continue;
1385                                }
1386                                itNote = GetNotePool()->fromID(noteID);
1387                            }
1388                            // move voice from whereever it was, to the new note's list of active voices
1389                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1390                            // render audio of this new voice for the first time
1391                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1392                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1393                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1415  namespace LinuxSampler { Line 1655  namespace LinuxSampler {
1655               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1656               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1657               */               */
1658              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1659                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1660                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1661    
                 //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;  
   
1662                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1663                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1664                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1665    
1666                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1667    
1668                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1669                    // programmatically spawned notes (Event::type_play_note). We have
1670                    // to distinguish between them, since certain processing below
1671                    // must only be done on real MIDI note-on events (i.e. for
1672                    // correctly updating which MIDI keys are currently pressed down).
1673                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1674    
1675                    if (isRealMIDINoteOnEvent)
1676                        pChannel->listeners.PreProcessNoteOn(key, vel);
1677    
1678                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1679                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1680                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1681                            pChannel->listeners.PostProcessNoteOn(key, vel);
1682                      return;                      return;
1683                  }                  }
1684                  #endif                  #endif
1685    
1686                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1687                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1688                            pChannel->listeners.PostProcessNoteOn(key, vel);
1689                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1690                  }                  }
1691    
# Line 1446  namespace LinuxSampler { Line 1693  namespace LinuxSampler {
1693                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1694    
1695                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1696                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1697                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1698                      if (itYoungestKey) {                      if (itYoungestKey) {
1699                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1454  namespace LinuxSampler { Line 1701  namespace LinuxSampler {
1701                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1702                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1703                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1704                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1705                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1706                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1707                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1708                                    }
1709                              }                              }
1710                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1711                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1712                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1713                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1714                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1715                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1716                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1717                                    }
1718                              }                              }
1719                          }                          }
1720                      }                      }
# Line 1470  namespace LinuxSampler { Line 1722  namespace LinuxSampler {
1722                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1723                  }                  }
1724    
1725                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1726                        pChannel->ProcessKeySwitchChange(key);
1727    
1728                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1729                  pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1730                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1731                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1732                    }
1733    
1734                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1735                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1736                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1737                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1738                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1739                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1740                      }                      }
1741                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1742                  }                  }
# Line 1493  namespace LinuxSampler { Line 1747  namespace LinuxSampler {
1747                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1748                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1749    
1750                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1751                        pChannel->PortamentoPos = (float) key;
1752    
1753                    //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?
1754                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1755                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1756                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1757                  }                  }
1758                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1759                    if (isRealMIDINoteOnEvent)
1760                        pChannel->listeners.PostProcessNoteOn(key, vel);
1761              }              }
1762    
1763              /**              /**
# Line 1527  namespace LinuxSampler { Line 1786  namespace LinuxSampler {
1786               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1787               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1788               */               */
1789              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1790                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1791    
                 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;  
   
1792                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1793                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1794                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1795    
1796                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1797    
1798                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1799                    // programmatically spawned notes (Event::type_stop_note). We have
1800                    // to distinguish between them, since certain processing below
1801                    // must only be done on real MIDI note-off events (i.e. for
1802                    // correctly updating which MIDI keys are currently pressed down),
1803                    // plus a stop-note event just releases voices of one particular
1804                    // note, whereas a note-off event releases all voices on a
1805                    // particular MIDI key instead.
1806                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1807    
1808                    if (isRealMIDINoteOffEvent)
1809                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1810    
1811                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1812                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1813                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1814                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1815                      return;                      return;
1816                  }                  }
1817                  #endif                  #endif
1818    
1819                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1820                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1821                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1822                    }
1823    
1824                  // move event to the key's own event list                  // move event to the key's own event list
1825                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1826    
1827                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1828                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1829    
1830                  // 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)
1831                  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
1832                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1833                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1834                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1835                          // 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
1836                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1837                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1838                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1839                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1840                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1841                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1842                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1843                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1844                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1845                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1846                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1847                                  // create a pseudo note on event                                      }
1848                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1849                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1850                                      // copy event                                      if (itPseudoNoteOnEvent) {
1851                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1852                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1853                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1854                                      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)
1855                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1856                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1857                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1858                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1859                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1860                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1861                                            }
1862                                            // if neither a voice was spawned or postponed then remove note on event from key again
1863                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1864                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1865    
1866                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1867                                  break; // done                                      break; // done
1868                                    }
1869                              }                              }
1870                          }                          }
1871                      }                          if (bOtherKeysPressed) {
1872                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1873                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1874                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1875                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1876                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1877                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1878                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1879                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1880                                        }
1881                                    }
1882                              }                              }
1883                          }                          } else pChannel->PortamentoPos = -1.0f;
1884                      } 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  
1885    
1886                      // 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
1887                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1888                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1889                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1890                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1891                        }
1892                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1893                        // This programmatically caused event is caused by a call to
1894                        // the built-in instrument script function note_off(). In
1895                        // contrast to a real MIDI note-off event the stop-note
1896                        // event just intends to release voices of one particular note.
1897                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1898                        if (pNote) { // the requested note is still alive ...
1899                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1900                        } else { // note is dead and gone ..
1901                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1902                            return; // prevent event to be removed a 2nd time below
1903                      }                      }
1904                  }                  }
1905    
# Line 1622  namespace LinuxSampler { Line 1907  namespace LinuxSampler {
1907                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1908                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1909    
1910                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1911                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1912                }
1913    
1914                /**
1915                 * Called on sustain pedal up events to check and if required,
1916                 * launch release trigger voices on the respective active key.
1917                 *
1918                 * @param pEngineChannel - engine channel on which this event occurred on
1919                 * @param itEvent - release trigger event (contains note number)
1920                 */
1921                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1922                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1923    
1924                    const int iKey = itEvent->Param.Note.Key;
1925                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1926    
1927                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1928    
1929                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1930                }
1931    
1932                /**
1933                 * Called on note-off and sustain pedal up events to check and if
1934                 * required, launch release trigger voices on the respective active
1935                 * key.
1936                 *
1937                 * @param pEngineChannel - engine channel on which this event occurred on
1938                 * @param itEvent - note off event / release trigger event
1939                 * @param pKey - key on which the release trigger voices shall be spawned
1940                 */
1941                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1942                    // spawn release triggered voice(s) if needed
1943                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1944                        // assign a new note to this release event
1945                        if (LaunchNewNote(pChannel, itEvent)) {
1946                            // allocate and trigger new release voice(s)
1947                            TriggerReleaseVoices(pChannel, itEvent);
1948                        }
1949                        pKey->ReleaseTrigger = false;
1950                    }
1951                }
1952    
1953                /**
1954                 * Called on "kill note" events, which currently only happens on
1955                 * built-in real-time instrument script function fade_out(). This
1956                 * method only fulfills one task: moving the even to the Note's own
1957                 * event list so that its voices can process the kill event sample
1958                 * accurately.
1959                 */
1960                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1961                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1962    
1963                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1964                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1965    
1966                    // move note kill event to its MIDI key
1967                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1968                    itEvent.moveToEndOf(pKey->pEvents);
1969                }
1970    
1971                /**
1972                 * Called on note synthesis parameter change events. These are
1973                 * internal events caused by calling built-in real-time instrument
1974                 * script functions like change_vol(), change_tune(), etc.
1975                 *
1976                 * This method performs two tasks:
1977                 *
1978                 * - It converts the event's relative values changes (Deltas) to
1979                 *   the respective final new synthesis parameter value (AbsValue),
1980                 *   for that particular moment of the event that is.
1981                 *
1982                 * - It moves the individual events to the Note's own event list
1983                 *   (or actually to the event list of the MIDI key), so that
1984                 *   voices can process those events sample accurately.
1985                 *
1986                 * @param pEngineChannel - engine channel on which this event occurred on
1987                 * @param itEvent - note synthesis parameter change event
1988                 */
1989                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1990                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1991    
1992                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1993                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1994    
1995                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1996    
1997                    switch (itEvent->Param.NoteSynthParam.Type) {
1998                        case Event::synth_param_volume:
1999                            if (relative)
2000                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2001                            else
2002                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2003                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2004                            break;
2005                        case Event::synth_param_volume_time:
2006                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2007                            break;
2008                        case Event::synth_param_pitch:
2009                            if (relative)
2010                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2011                            else
2012                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2013                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2014                            break;
2015                        case Event::synth_param_pitch_time:
2016                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2017                            break;
2018                        case Event::synth_param_pan:
2019                            if (relative) {
2020                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2021                            } else {
2022                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2023                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2024                            }
2025                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2026                            break;
2027                        case Event::synth_param_cutoff:
2028                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2029                            break;
2030                        case Event::synth_param_resonance:
2031                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2032                            break;
2033                        case Event::synth_param_attack:
2034                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2035                            break;
2036                        case Event::synth_param_decay:
2037                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2038                            break;
2039                        case Event::synth_param_release:
2040                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2041                            break;
2042                        case Event::synth_param_amp_lfo_depth:
2043                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2044                            break;
2045                        case Event::synth_param_amp_lfo_freq:
2046                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2047                            break;
2048                        case Event::synth_param_pitch_lfo_depth:
2049                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2050                            break;
2051                        case Event::synth_param_pitch_lfo_freq:
2052                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2053                            break;
2054                    }
2055    
2056                    // move note parameter event to its MIDI key
2057                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2058                    itEvent.moveToEndOf(pKey->pEvents);
2059              }              }
2060    
2061              /**              /**
2062               *  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
2063               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2064               */               */
2065              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2066                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2067    
2068                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1642  namespace LinuxSampler { Line 2075  namespace LinuxSampler {
2075                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
2076                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
2077                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
2078                    itLastStolenNote           = NoteIterator();
2079                    itLastStolenNoteGlobally   = NoteIterator();
2080                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2081                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2082                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2083    
2084                    // reset all notes
2085                    pNotePool->clear();
2086                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2087                         itNote = pNotePool->allocAppend())
2088                    {
2089                        itNote->reset();
2090                    }
2091                    pNotePool->clear();
2092    
2093                  // reset all voices                  // reset all voices
2094                    pVoicePool->clear();
2095                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2096                      iterVoice->Reset();                      iterVoice->Reset();
2097                  }                  }
# Line 1676  namespace LinuxSampler { Line 2121  namespace LinuxSampler {
2121               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2122               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2123               */               */
2124              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2125                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2126                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2127                  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 1711  namespace LinuxSampler { Line 2156  namespace LinuxSampler {
2156                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2157              ) = 0;              ) = 0;
2158    
2159              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2160    
2161              int InitNewVoice (              int InitNewVoice (
2162                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1730  namespace LinuxSampler { Line 2175  namespace LinuxSampler {
2175                      // launch the new voice                      // launch the new voice
2176                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2177                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2178                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2179                      }                      }
2180                      else { // on success                      else { // on success
2181                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1779  namespace LinuxSampler { Line 2224  namespace LinuxSampler {
2224              }              }
2225    
2226          private:          private:
2227                Pool< Note<V> >* pNotePool;
2228                Pool<note_id_t> noteIDPool;
2229              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2230              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2231              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2871  
changed lines
  Added in v.3221

  ViewVC Help
Powered by ViewVC