/[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 2879 by schoenebeck, Tue Apr 19 14:07:53 2016 UTC revision 3293 by schoenebeck, Tue Jun 27 22:19:19 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 58  namespace LinuxSampler { Line 58  namespace LinuxSampler {
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), noteIDPool(GLOBAL_MAX_NOTES) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                  pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);                  pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                  pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);                  pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
# Line 163  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 378  namespace LinuxSampler { Line 379  namespace LinuxSampler {
379                  }                  }
380                  pVoicePool->clear();                  pVoicePool->clear();
381    
382                  // (re)create event generator                  // update event generator
383                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
384    
385                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
386                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 596  namespace LinuxSampler { Line 596  namespace LinuxSampler {
596              }              }
597    
598              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
599              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
600                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
# Line 604  namespace LinuxSampler { Line 604  namespace LinuxSampler {
604              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607              virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }              virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 675  namespace LinuxSampler { Line 675  namespace LinuxSampler {
675               * @param pNoteOnEvent - event which caused this               * @param pNoteOnEvent - event which caused this
676               * @returns new note's unique ID (or zero on error)               * @returns new note's unique ID (or zero on error)
677               */               */
678              note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {              note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
679                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                  Pool< Note<V> >* pNotePool = GetNotePool();                  Pool< Note<V> >* pNotePool = GetNotePool();
681    
# Line 689  namespace LinuxSampler { Line 689  namespace LinuxSampler {
689                  NoteIterator itNewNote = pNotePool->allocAppend();                  NoteIterator itNewNote = pNotePool->allocAppend();
690                  const note_id_t newNoteID = pNotePool->getID(itNewNote);                  const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
694    
695                  // usually the new note (and its subsequent voices) will be                  // usually the new note (and its subsequent voices) will be
696                  // allocated on the key provided by the event's note number,                  // allocated on the key provided by the event's note number,
697                  // however if this new note is requested not to be a regular                  // 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                  // note, but rather a child note, then this new note will be
699                  // allocated on the parent note's key instead in order to                  // allocated on the parent note's key instead in order to
700                  // release the child note simultaniously with its parent note                  // release the child note simultaniously with its parent note
701                  itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;                  itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
702    
703                  // in case this new note was requested to be a child note,                  // in case this new note was requested to be a child note,
704                  // then retrieve its parent note and link them with each other                  // then retrieve its parent note and link them with each other
705                  const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;                  const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
706                  if (parentNoteID) {                  if (parentNoteID) {
707                      NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                                              NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
708                      if (itParentNote) {                      if (itParentNote) {
# Line 727  namespace LinuxSampler { Line 730  namespace LinuxSampler {
730                  dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));                  dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
731    
732                  // copy event which caused this note                  // copy event which caused this note
733                  itNewNote->cause = *pNoteOnEvent;                  itNewNote->cause = *itNoteOnEvent;
734                  itNewNote->eventID = pEventPool->getID(pNoteOnEvent);                  itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
735                    if (!itNewNote->eventID) {
736                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
737                    }
738    
739                  // move new note to its host key                  // move new note to its host key
740                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
741                  itNewNote.moveToEndOf(pKey->pActiveNotes);                  itNewNote.moveToEndOf(pKey->pActiveNotes);
742    
743                  // assign unique note ID of this new note to the original note on event                  // assign unique note ID of this new note to the original note on event
744                  pNoteOnEvent->Param.Note.ID = newNoteID;                  itNoteOnEvent->Param.Note.ID = newNoteID;
745    
746                  return newNoteID; // success                  return newNoteID; // success
747              }              }
# Line 771  namespace LinuxSampler { Line 777  namespace LinuxSampler {
777                      //                      //
778                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
779                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
780                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
781                      {                      {
782                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
783                            RTList<Event>::Iterator itNext = itEvent;
784                            ++itNext;
785    
786                          switch (itEvent->Type) {                          switch (itEvent->Type) {
787                              case Event::type_note_on:                              case Event::type_note_on:
788                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 791  namespace LinuxSampler { Line 801  namespace LinuxSampler {
801                              case Event::type_note_pressure:                              case Event::type_note_pressure:
802                                  //TODO: ...                                  //TODO: ...
803                                  break;                                  break;
804    
805                                case Event::type_sysex:
806                                    //TODO: ...
807                                    break;
808    
809                                case Event::type_cancel_release_key:
810                                case Event::type_release_key:
811                                case Event::type_release_note:
812                                case Event::type_play_note:
813                                case Event::type_stop_note:
814                                case Event::type_kill_note:
815                                case Event::type_note_synth_param:
816                                    break; // noop
817                          }                          }
818    
819                            // see HACK comment above
820                            itEvent = itNext;
821                      }                      }
822    
823                      // this has to be run again, since the newly spawned scripts                      // this has to be run again, since the newly spawned scripts
# Line 846  namespace LinuxSampler { Line 872  namespace LinuxSampler {
872                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
873                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
874                                  break;                                  break;
875                                case Event::type_play_note:
876                                    dmsg(5,("Engine: Play Note received\n"));
877                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
878                                    break;
879                              case Event::type_note_off:                              case Event::type_note_off:
880                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
881                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
882                                  break;                                  break;
883                                case Event::type_stop_note:
884                                    dmsg(5,("Engine: Stop Note received\n"));
885                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
886                                    break;
887                                case Event::type_kill_note:
888                                    dmsg(5,("Engine: Kill Note received\n"));
889                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
890                                    break;
891                              case Event::type_control_change:                              case Event::type_control_change:
892                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
893                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 866  namespace LinuxSampler { Line 904  namespace LinuxSampler {
904                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
905                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
906                                  break;                                  break;
907                                case Event::type_note_synth_param:
908                                    dmsg(5,("Engine: Note Synth Param received\n"));
909                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
910                                    break;
911                                case Event::type_sysex:
912                                    break; // TODO ...
913    
914                                case Event::type_cancel_release_key:
915                                case Event::type_release_key:
916                                case Event::type_release_note:
917                                    break; // noop
918                          }                          }
919                      }                      }
920                  }                  }
# Line 934  namespace LinuxSampler { Line 983  namespace LinuxSampler {
983                      // script event object                      // script event object
984                      RTList<ScriptEvent>::Iterator itScriptEvent =                      RTList<ScriptEvent>::Iterator itScriptEvent =
985                          pChannel->pScript->pEvents->allocAppend();                          pChannel->pScript->pEvents->allocAppend();
986                        // if event handler uses polyphonic variables, reset them
987                        // to zero values before starting to execute the handler
988                        if (pEventHandler->isPolyphonic())
989                            itScriptEvent->execCtx->resetPolyphonicData();
990                      ProcessScriptEvent(                      ProcessScriptEvent(
991                          pChannel, itEvent, pEventHandler, itScriptEvent                          pChannel, itEvent, pEventHandler, itScriptEvent
992                      );                      );
# Line 966  namespace LinuxSampler { Line 1019  namespace LinuxSampler {
1019    
1020                  // initialize/reset other members                  // initialize/reset other members
1021                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1022                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1023                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1024                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1025                    itScriptEvent->ignoreAllWaitCalls = false;
1026                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1027                    itScriptEvent->parentHandlerID = 0;
1028                    itScriptEvent->childHandlerID[0] = 0;
1029                    itScriptEvent->autoAbortByParent = false;
1030                    itScriptEvent->forkIndex = 0;
1031                  // this is the native representation of the $EVENT_ID script variable                  // this is the native representation of the $EVENT_ID script variable
1032                  itScriptEvent->id =                  itScriptEvent->id =
1033                      (itEvent->Type == Event::type_note_on)                      (itEvent->Type == Event::type_note_on)
# Line 1235  namespace LinuxSampler { Line 1295  namespace LinuxSampler {
1295                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1296                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1297                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1298                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1299                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1300                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1301    
1302                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1303                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1304                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1305                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1306                                itScriptEvent->id = 0;
1307                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1308                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1309                                itScriptEvent->currentHandler = 0;
1310                              VMExecStatus_t res = pScriptVM->exec(                              itScriptEvent->executionSlices = 0;
1311                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                              itScriptEvent->ignoreAllWaitCalls = false;
1312                              );                              itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1313                                itScriptEvent->parentHandlerID = 0;
1314                                itScriptEvent->childHandlerID[0] = 0;
1315                                itScriptEvent->autoAbortByParent = false;
1316                                itScriptEvent->forkIndex = 0;
1317    
1318                                VMExecStatus_t res;
1319                                size_t instructionsCount = 0;
1320                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1321                                bool bWarningShown = false;
1322                                do {
1323                                    res = pScriptVM->exec(
1324                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1325                                    );
1326                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1327                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1328                                        bWarningShown = true;
1329                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1330                                    }
1331                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1332    
1333                              pEngineChannel->pScript->pEvents->free(itScriptEvent);                              pEngineChannel->pScript->pEvents->free(itScriptEvent);
1334                          }                          }
# Line 1305  namespace LinuxSampler { Line 1389  namespace LinuxSampler {
1389                          // usually there should already be a new Note object                          // usually there should already be a new Note object
1390                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1391                          if (!itNote) { // should not happen, but just to be sure ...                          if (!itNote) { // should not happen, but just to be sure ...
1392                              const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);                              const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1393                              if (!noteID) {                              if (!noteID) {
1394                                  dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));                                  dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1395                                  continue;                                  continue;
# Line 1582  namespace LinuxSampler { Line 1666  namespace LinuxSampler {
1666               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1667               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1668               */               */
1669              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1670                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1671                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1672    
# Line 1592  namespace LinuxSampler { Line 1676  namespace LinuxSampler {
1676    
1677                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1678    
1679                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1680                    // programmatically spawned notes (Event::type_play_note). We have
1681                    // to distinguish between them, since certain processing below
1682                    // must only be done on real MIDI note-on events (i.e. for
1683                    // correctly updating which MIDI keys are currently pressed down).
1684                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1685    
1686                    if (isRealMIDINoteOnEvent)
1687                        pChannel->listeners.PreProcessNoteOn(key, vel);
1688    
1689                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1690                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1691                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1692                            pChannel->listeners.PostProcessNoteOn(key, vel);
1693                      return;                      return;
1694                  }                  }
1695                  #endif                  #endif
1696    
1697                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1698                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1699                            pChannel->listeners.PostProcessNoteOn(key, vel);
1700                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1701                  }                  }
1702    
# Line 1609  namespace LinuxSampler { Line 1704  namespace LinuxSampler {
1704                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1705    
1706                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1707                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1708                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1709                      if (itYoungestKey) {                      if (itYoungestKey) {
1710                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 1733  namespace LinuxSampler {
1733                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1734                  }                  }
1735    
1736                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1737                        pChannel->ProcessKeySwitchChange(key);
1738    
1739                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1740                  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
1741                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1742                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1743                    }
1744    
1745                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1746                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1747                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1748                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1749                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1750                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1751                      }                      }
1752                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1753                  }                  }
# Line 1661  namespace LinuxSampler { Line 1758  namespace LinuxSampler {
1758                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1759                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1760    
1761                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1762                        pChannel->PortamentoPos = (float) key;
1763    
1764                    //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?
1765                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1766                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1767                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1768                  }                  }
1769                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1770                    if (isRealMIDINoteOnEvent)
1771                        pChannel->listeners.PostProcessNoteOn(key, vel);
1772              }              }
1773    
1774              /**              /**
# Line 1695  namespace LinuxSampler { Line 1797  namespace LinuxSampler {
1797               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1798               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1799               */               */
1800              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1801                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1802    
1803                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
# Line 1704  namespace LinuxSampler { Line 1806  namespace LinuxSampler {
1806    
1807                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1808    
1809                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1810                    // programmatically spawned notes (Event::type_stop_note). We have
1811                    // to distinguish between them, since certain processing below
1812                    // must only be done on real MIDI note-off events (i.e. for
1813                    // correctly updating which MIDI keys are currently pressed down),
1814                    // plus a stop-note event just releases voices of one particular
1815                    // note, whereas a note-off event releases all voices on a
1816                    // particular MIDI key instead.
1817                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1818    
1819                    if (isRealMIDINoteOffEvent)
1820                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1821    
1822                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1823                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1824                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1825                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1826                      return;                      return;
1827                  }                  }
1828                  #endif                  #endif
1829    
1830                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1831                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1832                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1833                    }
1834    
1835                  // move event to the key's own event list                  // move event to the key's own event list
1836                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1837    
1838                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1839                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1840    
1841                  // 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)
1842                  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
1843                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1844                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1845                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1846                          // 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
1847                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1848                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1849                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1850                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1851                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1852                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1853                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1854                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1855                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1856                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1857                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
                                 }  
                                 // create a pseudo note on event  
                                 RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();  
                                 if (itPseudoNoteOnEvent) {  
                                     // copy event  
                                     *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;  
                                     // transform event to a note on event  
                                     itPseudoNoteOnEvent->Type                = Event::type_note_on;  
                                     itPseudoNoteOnEvent->Param.Note.Key      = i;  
                                     itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;  
                                     // assign a new note to this note-on event  
                                     if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {  
                                         // allocate and trigger new voice(s) for the other key  
                                         TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);  
1858                                      }                                      }
1859                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
1860                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1861                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
1862                                            // copy event
1863                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1864                                            // transform event to a note on event
1865                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1866                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
1867                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1868                                            // assign a new note to this note-on event
1869                                            if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1870                                                // allocate and trigger new voice(s) for the other key
1871                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1872                                            }
1873                                            // if neither a voice was spawned or postponed then remove note on event from key again
1874                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1875                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1876    
1877                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1878                                  break; // done                                      break; // done
1879                                    }
1880                              }                              }
1881                          }                          }
1882                      }                          if (bOtherKeysPressed) {
1883                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1884                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1885                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1886                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1887                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1888                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1889                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1890                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1891                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
1892                                  }                                  }
1893                              }                              }
1894                          }                          } else pChannel->PortamentoPos = -1.0f;
1895                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
1896    
1897                  // 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 no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1898                  if (bShouldRelease) {                      if (bShouldRelease) {
1899                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1900                            // spawn release triggered voice(s) if needed
1901                      // spawn release triggered voice(s) if needed                          ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1902                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      }
1903                          // assign a new note to this release event                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1904                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                      // This programmatically caused event is caused by a call to
1905                              // allocate and trigger new release voice(s)                      // the built-in instrument script function note_off(). In
1906                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                      // contrast to a real MIDI note-off event the stop-note
1907                          }                      // event just intends to release voices of one particular note.
1908                          pKey->ReleaseTrigger = false;                      NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1909                        if (pNote) { // the requested note is still alive ...
1910                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1911                        } else { // note is dead and gone ..
1912                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1913                            return; // prevent event to be removed a 2nd time below
1914                      }                      }
1915                  }                  }
1916    
# Line 1796  namespace LinuxSampler { Line 1918  namespace LinuxSampler {
1918                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1919                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1920    
1921                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1922                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1923                }
1924    
1925                /**
1926                 * Called on sustain pedal up events to check and if required,
1927                 * launch release trigger voices on the respective active key.
1928                 *
1929                 * @param pEngineChannel - engine channel on which this event occurred on
1930                 * @param itEvent - release trigger event (contains note number)
1931                 */
1932                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1933                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1934    
1935                    const int iKey = itEvent->Param.Note.Key;
1936                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1937    
1938                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1939    
1940                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1941                }
1942    
1943                /**
1944                 * Called on note-off and sustain pedal up events to check and if
1945                 * required, launch release trigger voices on the respective active
1946                 * key.
1947                 *
1948                 * @param pEngineChannel - engine channel on which this event occurred on
1949                 * @param itEvent - note off event / release trigger event
1950                 * @param pKey - key on which the release trigger voices shall be spawned
1951                 */
1952                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1953                    // spawn release triggered voice(s) if needed
1954                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1955                        // assign a new note to this release event
1956                        if (LaunchNewNote(pChannel, itEvent)) {
1957                            // allocate and trigger new release voice(s)
1958                            TriggerReleaseVoices(pChannel, itEvent);
1959                        }
1960                        pKey->ReleaseTrigger = false;
1961                    }
1962                }
1963    
1964                /**
1965                 * Called on "kill note" events, which currently only happens on
1966                 * built-in real-time instrument script function fade_out(). This
1967                 * method only fulfills one task: moving the even to the Note's own
1968                 * event list so that its voices can process the kill event sample
1969                 * accurately.
1970                 */
1971                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1972                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1973    
1974                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1975                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1976    
1977                    // move note kill event to its MIDI key
1978                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1979                    itEvent.moveToEndOf(pKey->pEvents);
1980                }
1981    
1982                /**
1983                 * Called on note synthesis parameter change events. These are
1984                 * internal events caused by calling built-in real-time instrument
1985                 * script functions like change_vol(), change_tune(), etc.
1986                 *
1987                 * This method performs two tasks:
1988                 *
1989                 * - It converts the event's relative values changes (Deltas) to
1990                 *   the respective final new synthesis parameter value (AbsValue),
1991                 *   for that particular moment of the event that is.
1992                 *
1993                 * - It moves the individual events to the Note's own event list
1994                 *   (or actually to the event list of the MIDI key), so that
1995                 *   voices can process those events sample accurately.
1996                 *
1997                 * @param pEngineChannel - engine channel on which this event occurred on
1998                 * @param itEvent - note synthesis parameter change event
1999                 */
2000                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2001                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2002    
2003                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2004                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2005    
2006                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
2007    
2008                    switch (itEvent->Param.NoteSynthParam.Type) {
2009                        case Event::synth_param_volume:
2010                            if (relative)
2011                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2012                            else
2013                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2014                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2015                            break;
2016                        case Event::synth_param_volume_time:
2017                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2018                            break;
2019                        case Event::synth_param_volume_curve:
2020                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2021                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2022                            break;
2023                        case Event::synth_param_pitch:
2024                            if (relative)
2025                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2026                            else
2027                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2028                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2029                            break;
2030                        case Event::synth_param_pitch_time:
2031                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2032                            break;
2033                        case Event::synth_param_pitch_curve:
2034                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2035                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2036                            break;
2037                        case Event::synth_param_pan:
2038                            if (relative) {
2039                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2040                            } else {
2041                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2042                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2043                            }
2044                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2045                            break;
2046                        case Event::synth_param_cutoff:
2047                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2048                            break;
2049                        case Event::synth_param_resonance:
2050                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2051                            break;
2052                        case Event::synth_param_attack:
2053                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2054                            break;
2055                        case Event::synth_param_decay:
2056                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2057                            break;
2058                        case Event::synth_param_release:
2059                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2060                            break;
2061                        case Event::synth_param_amp_lfo_depth:
2062                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2063                            break;
2064                        case Event::synth_param_amp_lfo_freq:
2065                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2066                            break;
2067                        case Event::synth_param_pitch_lfo_depth:
2068                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2069                            break;
2070                        case Event::synth_param_pitch_lfo_freq:
2071                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2072                            break;
2073                    }
2074    
2075                    // move note parameter event to its MIDI key
2076                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2077                    itEvent.moveToEndOf(pKey->pEvents);
2078              }              }
2079    
2080              /**              /**
2081               *  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
2082               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2083               */               */
2084              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2085                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2086    
2087                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
# Line 1862  namespace LinuxSampler { Line 2140  namespace LinuxSampler {
2140               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2141               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2142               */               */
2143              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2144                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2145                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2146                  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 1897  namespace LinuxSampler { Line 2175  namespace LinuxSampler {
2175                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2176              ) = 0;              ) = 0;
2177    
2178              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2179    
2180              int InitNewVoice (              int InitNewVoice (
2181                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,

Legend:
Removed from v.2879  
changed lines
  Added in v.3293

  ViewVC Help
Powered by ViewVC