/[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 2962 by schoenebeck, Sun Jul 17 17:54:04 2016 UTC
# 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() : SuspendedRegions(128), noteIDPool(GLOBAL_MAX_NOTES) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 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 236  namespace LinuxSampler { Line 258  namespace LinuxSampler {
258                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
259                  }                  }
260    
261                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
262                  try {                  try {
263                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
264                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
265                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
266                  } catch (...) {                  } catch (...) {
267                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
268                  }                  }
269    
270                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
271                         iterVoice; iterVoice = pVoicePool->allocAppend())
272                    {
273                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
274                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
275                  }                  }
276                  pVoicePool->clear();                  pVoicePool->clear();
277    
278                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
279                         itNote = pNotePool->allocAppend())
280                    {
281                        itNote->init(pVoicePool, &noteIDPool);
282                    }
283                    pNotePool->clear();
284    
285                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
286                  ResumeAll();                  ResumeAll();
287              }              }
# Line 316  namespace LinuxSampler { Line 350  namespace LinuxSampler {
350                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
351                      // lower minimum release time                      // lower minimum release time
352                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
353                        pVoicePool->clear();
354                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
355                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
356                      }                      }
# Line 336  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
372                  }                  }
373    
374                    pVoicePool->clear();
375                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
376                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
377                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 565  namespace LinuxSampler { Line 601  namespace LinuxSampler {
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 586  namespace LinuxSampler { Line 624  namespace LinuxSampler {
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
# Line 609  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648    
649              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
650              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
653              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
658              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
694    
695                    // usually the new note (and its subsequent voices) will be
696                    // allocated on the key provided by the event's note number,
697                    // however if this new note is requested not to be a regular
698                    // note, but rather a child note, then this new note will be
699                    // allocated on the parent note's key instead in order to
700                    // release the child note simultaniously with its parent note
701                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
702    
703                    // in case this new note was requested to be a child note,
704                    // then retrieve its parent note and link them with each other
705                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
706                    if (parentNoteID) {
707                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
708                        if (itParentNote) {
709                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
710                            if (itChildNoteID) {
711                                // link parent and child note with each other
712                                *itChildNoteID = newNoteID;
713                                itNewNote->parentNoteID = parentNoteID;
714                                itNewNote->hostKey = itParentNote->hostKey;
715                            } else {    
716                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
717                                pNotePool->free(itNewNote);
718                                return 0; // error
719                            }
720                        } else {
721                            // the parent note was apparently released already, so
722                            // free the new note again and inform caller that it
723                            // should drop the event
724                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
725                            pNotePool->free(itNewNote);
726                            return 0; // error
727                        }
728                    }
729    
730                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
731    
732                    // copy event which caused this note
733                    itNewNote->cause = *pNoteOnEvent;
734                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
735    
736                    // move new note to its host key
737                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
738                    itNewNote.moveToEndOf(pKey->pActiveNotes);
739    
740                    // assign unique note ID of this new note to the original note on event
741                    pNoteOnEvent->Param.Note.ID = newNoteID;
742    
743                    return newNoteID; // success
744                }
745    
746              /**              /**
747               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
748               * engine channel.               * engine channel.
# Line 648  namespace LinuxSampler { Line 774  namespace LinuxSampler {
774                      //                      //
775                      // 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
776                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
777                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
778                      {                      {
779                            //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).
780                            RTList<Event>::Iterator itNext = itEvent;
781                            ++itNext;
782    
783                          switch (itEvent->Type) {                          switch (itEvent->Type) {
784                              case Event::type_note_on:                              case Event::type_note_on:
785                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 669  namespace LinuxSampler { Line 799  namespace LinuxSampler {
799                                  //TODO: ...                                  //TODO: ...
800                                  break;                                  break;
801                          }                          }
802    
803                            // see HACK comment above
804                            itEvent = itNext;
805                      }                      }
806    
807                      // 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 856  namespace LinuxSampler {
856                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
857                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
858                                  break;                                  break;
859                                case Event::type_play_note:
860                                    dmsg(5,("Engine: Play Note received\n"));
861                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
862                                    break;
863                              case Event::type_note_off:                              case Event::type_note_off:
864                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
865                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
866                                  break;                                  break;
867                                case Event::type_stop_note:
868                                    dmsg(5,("Engine: Stop Note received\n"));
869                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
870                                    break;
871                              case Event::type_control_change:                              case Event::type_control_change:
872                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
873                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 743  namespace LinuxSampler { Line 884  namespace LinuxSampler {
884                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
885                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
886                                  break;                                  break;
887                                case Event::type_note_synth_param:
888                                    dmsg(5,("Engine: Note Synth Param received\n"));
889                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
890                                    break;
891                          }                          }
892                      }                      }
893                  }                  }
# Line 750  namespace LinuxSampler { Line 895  namespace LinuxSampler {
895                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
896                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
897                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
898                    itLastStolenNote          = NoteIterator();
899                    itLastStolenNoteGlobally  = NoteIterator();
900                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
901                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
902                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
# Line 841  namespace LinuxSampler { Line 988  namespace LinuxSampler {
988    
989                  // initialize/reset other members                  // initialize/reset other members
990                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
                 itScriptEvent->id = pEventPool->getID(itEvent);  
991                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
992                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
993                    itScriptEvent->ignoreAllWaitCalls = false;
994                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
995                    // this is the native representation of the $EVENT_ID script variable
996                    itScriptEvent->id =
997                        (itEvent->Type == Event::type_note_on)
998                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
999                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1000    
1001                  // run script handler(s)                  // run script handler(s)
1002                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
# Line 886  namespace LinuxSampler { Line 1039  namespace LinuxSampler {
1039              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1040               *               *
1041               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1042               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1043               *               *
1044               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1045               * 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 1103  namespace LinuxSampler {
1103               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1104               *  @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
1105               */               */
1106              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1107                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1108                      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"));
1109                      return -1;                      return -1;
# Line 959  namespace LinuxSampler { Line 1111  namespace LinuxSampler {
1111    
1112                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1113    
1114                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1115                        dmsg(1,("Event pool emtpy!\n"));
1116                        return -1;
1117                    }
1118    
1119                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1120                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1121                          return 0;                      return 0;
1122                      }                  }
1123    
1124                      // 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
1125                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1126                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1127                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1128                      int                       iChannelIndex;                  int                          iChannelIndex;
1129                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1130    
1131                      // select engine channel                  // select engine channel
1132                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1133                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1134                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1135                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1136                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1137                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1138                      }                  }
1139    
1140                      // 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
1141                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1142                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1143                          do {                      do {
1144                              ++itSelectedVoice;                          ++itSelectedVoice;
1145                          } 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
1146                    }
1147                    // did we find a 'stealable' voice?
1148                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1149                        // remember which voice we stole, so we can simply proceed on next voice stealing
1150                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1151                        // done
1152                        goto stealable_voice_found;
1153                    }
1154    
1155                    // get (next) oldest note
1156                    if (this->itLastStolenNoteGlobally) {
1157                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1158                             itNote; ++itNote)
1159                        {
1160                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1161                                // proceed iterating if voice was created in this audio fragment cycle
1162                                if (itSelectedVoice->IsStealable()) {
1163                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1164                                    this->itLastStolenNoteGlobally  = itNote;
1165                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1166                                    goto stealable_voice_found; // selection succeeded
1167                                }
1168                            }
1169                      }                      }
1170                    }
1171    
1172                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1173                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1174                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1175    
1176                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1177                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1178                          // 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();
1179                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1180                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1181                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1182                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1183                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1184                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1185                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1186                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1187                                itSelectedVoice = itNote->pActiveVoices->first();
1188                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1189                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1190                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1191                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1192                                  // 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
1193                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1194                                    this->itLastStolenNoteGlobally  = itNote;
1195                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1196                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1197                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1198                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1199                          }                          }
1200                          // get next engine channel                          ++iuiSelectedKey; // get next key on current engine channel
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
                         }  
                         #endif // CONFIG_DEVMODE  
1201                      }                      }
1202                        // get next engine channel
1203                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1204                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1205    
1206                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1207                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1208                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1209                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1210                            dmsg(1,("Exiting.\n"));
1211                            exit(-1);
1212                      }                      }
1213                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1214                    }
1215    
1216                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1217                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1218    
1219                      return 0; // success                  #if CONFIG_DEVMODE
1220                  }                  if (!itSelectedVoice->IsActive()) {
1221                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1222                      return -1;                      return -1;
1223                  }                  }
1224                    #endif // CONFIG_DEVMODE
1225    
1226                    // now kill the selected voice
1227                    itSelectedVoice->Kill(itNoteOnEvent);
1228    
1229                    --VoiceSpawnsLeft;
1230    
1231                    return 0; // success
1232              }              }
1233    
1234              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 1145  namespace LinuxSampler { Line 1322  namespace LinuxSampler {
1322                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1323                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1324                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1325                        
1326                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1327                          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);
1328                      if (itNewVoice) {                      if (itNewVoice) {
1329                            // usually there should already be a new Note object
1330                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1331                            if (!itNote) { // should not happen, but just to be sure ...
1332                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1333                                if (!noteID) {
1334                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1335                                    continue;
1336                                }
1337                                itNote = GetNotePool()->fromID(noteID);
1338                            }
1339                            // move voice from whereever it was, to the new note's list of active voices
1340                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1341                            // render audio of this new voice for the first time
1342                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1343                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1344                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1419  namespace LinuxSampler { Line 1610  namespace LinuxSampler {
1610                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1611                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1612    
                 //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;  
   
1613                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1614                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1615                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1616    
1617                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1618    
1619                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1620                    // programmatically spawned notes (Event::type_play_note). We have
1621                    // to distinguish between them, since certain processing below
1622                    // must only be done on real MIDI note-on events (i.e. for
1623                    // correctly updating which MIDI keys are currently pressed down).
1624                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1625    
1626                    if (isRealMIDINoteOnEvent)
1627                        pChannel->listeners.PreProcessNoteOn(key, vel);
1628    
1629                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1630                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1631                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1632                            pChannel->listeners.PostProcessNoteOn(key, vel);
1633                      return;                      return;
1634                  }                  }
1635                  #endif                  #endif
1636    
1637                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1638                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1639                            pChannel->listeners.PostProcessNoteOn(key, vel);
1640                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1641                  }                  }
1642    
# Line 1446  namespace LinuxSampler { Line 1644  namespace LinuxSampler {
1644                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1645    
1646                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1647                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1648                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1649                      if (itYoungestKey) {                      if (itYoungestKey) {
1650                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1454  namespace LinuxSampler { Line 1652  namespace LinuxSampler {
1652                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1653                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1654                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1655                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1656                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1657                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1658                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1659                                    }
1660                              }                              }
1661                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1662                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1663                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1664                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1665                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1666                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1667                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1668                                    }
1669                              }                              }
1670                          }                          }
1671                      }                      }
# Line 1470  namespace LinuxSampler { Line 1673  namespace LinuxSampler {
1673                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1674                  }                  }
1675    
1676                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1677                        pChannel->ProcessKeySwitchChange(key);
1678    
1679                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1680                  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
1681                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1682                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1683                    }
1684    
1685                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1686                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1687                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1688                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1689                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1690                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1691                      }                      }
1692                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1693                  }                  }
# Line 1493  namespace LinuxSampler { Line 1698  namespace LinuxSampler {
1698                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1699                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1700    
1701                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1702                        pChannel->PortamentoPos = (float) key;
1703    
1704                    //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?
1705                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1706                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1707                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1708                  }                  }
1709                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1710                    if (isRealMIDINoteOnEvent)
1711                        pChannel->listeners.PostProcessNoteOn(key, vel);
1712              }              }
1713    
1714              /**              /**
# Line 1530  namespace LinuxSampler { Line 1740  namespace LinuxSampler {
1740              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1741                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1742    
                 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;  
   
1743                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1744                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1745                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1746    
1747                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1748    
1749                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1750                    // programmatically spawned notes (Event::type_stop_note). We have
1751                    // to distinguish between them, since certain processing below
1752                    // must only be done on real MIDI note-off events (i.e. for
1753                    // correctly updating which MIDI keys are currently pressed down),
1754                    // plus a stop-note event just releases voices of one particular
1755                    // note, whereas a note-off event releases all voices on a
1756                    // particular MIDI key instead.
1757                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1758    
1759                    if (isRealMIDINoteOffEvent)
1760                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1761    
1762                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1763                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1764                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1765                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1766                      return;                      return;
1767                  }                  }
1768                  #endif                  #endif
1769    
1770                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1771                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1772                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1773                    }
1774    
1775                  // move event to the key's own event list                  // move event to the key's own event list
1776                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1777    
1778                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1779                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1780    
1781                  // 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)
1782                  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
1783                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1784                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1785                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1786                          // 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
1787                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1788                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1789                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1790                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1791                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1792                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1793                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1794                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1795                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1796                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1797                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1798                                  // create a pseudo note on event                                      }
1799                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1800                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1801                                      // copy event                                      if (itPseudoNoteOnEvent) {
1802                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1803                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1804                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1805                                      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)
1806                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1807                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1808                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1809                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1810                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1811                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1812                                            }
1813                                            // if neither a voice was spawned or postponed then remove note on event from key again
1814                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1815                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1816    
1817                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1818                                  break; // done                                      break; // done
1819                                    }
1820                              }                              }
1821                          }                          }
1822                      }                          if (bOtherKeysPressed) {
1823                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1824                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1825                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1826                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1827                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1828                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1829                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1830                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1831                                        }
1832                                    }
1833                              }                              }
1834                          }                          } else pChannel->PortamentoPos = -1.0f;
1835                      } 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  
1836    
1837                      // 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
1838                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1839                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1840                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1841                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1842                        }
1843                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1844                        // This programmatically caused event is caused by a call to
1845                        // the built-in instrument script function note_off(). In
1846                        // contrast to a real MIDI note-off event the stop-note
1847                        // event just intends to release voices of one particular note.
1848                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1849                        if (pNote) { // the requested note is still alive ...
1850                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1851                        } else { // note is dead and gone ..
1852                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1853                            return; // prevent event to be removed a 2nd time below
1854                      }                      }
1855                  }                  }
1856    
# Line 1622  namespace LinuxSampler { Line 1858  namespace LinuxSampler {
1858                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1859                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1860    
1861                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1862                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1863                }
1864    
1865                /**
1866                 * Called on sustain pedal up events to check and if required,
1867                 * launch release trigger voices on the respective active key.
1868                 *
1869                 * @param pEngineChannel - engine channel on which this event occurred on
1870                 * @param itEvent - release trigger event (contains note number)
1871                 */
1872                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1873                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1874    
1875                    const int iKey = itEvent->Param.Note.Key;
1876                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1877    
1878                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1879    
1880                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1881                }
1882    
1883                /**
1884                 * Called on note-off and sustain pedal up events to check and if
1885                 * required, launch release trigger voices on the respective active
1886                 * key.
1887                 *
1888                 * @param pEngineChannel - engine channel on which this event occurred on
1889                 * @param itEvent - note off event / release trigger event
1890                 * @param pKey - key on which the release trigger voices shall be spawned
1891                 */
1892                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1893                    // spawn release triggered voice(s) if needed
1894                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1895                        // assign a new note to this release event
1896                        if (LaunchNewNote(pChannel, &*itEvent)) {
1897                            // allocate and trigger new release voice(s)
1898                            TriggerReleaseVoices(pChannel, itEvent);
1899                        }
1900                        pKey->ReleaseTrigger = false;
1901                    }
1902                }
1903    
1904                /**
1905                 * Called on note synthesis parameter change events. These are
1906                 * internal events caused by calling built-in real-time instrument
1907                 * script functions like change_vol(), change_pitch(), etc.
1908                 *
1909                 * This method performs two tasks:
1910                 *
1911                 * - It converts the event's relative values changes (Deltas) to
1912                 *   the respective final new synthesis parameter value (AbsValue),
1913                 *   for that particular moment of the event that is.
1914                 *
1915                 * - It moves the individual events to the Note's own event list
1916                 *   (or actually to the event list of the MIDI key), so that
1917                 *   voices can process those events sample accurately.
1918                 *
1919                 * @param pEngineChannel - engine channel on which this event occurred on
1920                 * @param itEvent - note synthesis parameter change event
1921                 */
1922                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1923                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1924    
1925                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1926                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1927    
1928                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1929    
1930                    switch (itEvent->Param.NoteSynthParam.Type) {
1931                        case Event::synth_param_volume:
1932                            if (relative)
1933                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1934                            else
1935                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1936                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1937                            break;
1938                        case Event::synth_param_pitch:
1939                            if (relative)
1940                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1941                            else
1942                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1943                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1944                            break;
1945                        case Event::synth_param_pan:
1946                            if (relative) {
1947                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1948                            } else {
1949                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1950                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1951                            }
1952                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1953                            break;
1954                        case Event::synth_param_cutoff:
1955                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1956                            break;
1957                        case Event::synth_param_resonance:
1958                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1959                            break;
1960                        case Event::synth_param_attack:
1961                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1962                            break;
1963                        case Event::synth_param_decay:
1964                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1965                            break;
1966                        case Event::synth_param_release:
1967                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1968                            break;
1969                    }
1970    
1971                    // move note parameter event to its MIDI key
1972                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1973                    itEvent.moveToEndOf(pKey->pEvents);
1974              }              }
1975    
1976              /**              /**
# Line 1642  namespace LinuxSampler { Line 1990  namespace LinuxSampler {
1990                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1991                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1992                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1993                    itLastStolenNote           = NoteIterator();
1994                    itLastStolenNoteGlobally   = NoteIterator();
1995                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
1996                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
1997                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
1998    
1999                    // reset all notes
2000                    pNotePool->clear();
2001                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2002                         itNote = pNotePool->allocAppend())
2003                    {
2004                        itNote->reset();
2005                    }
2006                    pNotePool->clear();
2007    
2008                  // reset all voices                  // reset all voices
2009                    pVoicePool->clear();
2010                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2011                      iterVoice->Reset();                      iterVoice->Reset();
2012                  }                  }
# Line 1730  namespace LinuxSampler { Line 2090  namespace LinuxSampler {
2090                      // launch the new voice                      // launch the new voice
2091                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2092                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2093                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2094                      }                      }
2095                      else { // on success                      else { // on success
2096                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1779  namespace LinuxSampler { Line 2139  namespace LinuxSampler {
2139              }              }
2140    
2141          private:          private:
2142                Pool< Note<V> >* pNotePool;
2143                Pool<note_id_t> noteIDPool;
2144              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2145              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2146              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

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

  ViewVC Help
Powered by ViewVC