/[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 3316 by schoenebeck, Thu Jul 20 12:05:53 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 201  namespace LinuxSampler { Line 202  namespace LinuxSampler {
202                      PostProcess(engineChannels[i]);                      PostProcess(engineChannels[i]);
203                  }                  }
204    
205                    // Just for debugging: dump the amount of free Note objects to
206                    // the terminal (note due to the static variables being used,
207                    // this is currently just intended for debugging with only one
208                    // engine channel).
209                    #if (CONFIG_DEBUG_LEVEL >= 3)
210                    {
211                        static int slice = 0;
212                        static int noteCount = -1;
213                        if (slice++ % 10 == 0) {
214                            int n = pNotePool->countFreeElements();
215                            if (n != noteCount) {
216                                noteCount = n;
217                                dmsg(1,("[%d] free Note objects count = %d\n", slice / 10, n));
218                            }
219                        }
220                    }
221                    #endif
222    
223                  // empty the engine's event list for the next audio fragment                  // empty the engine's event list for the next audio fragment
224                  ClearEventLists();                  ClearEventLists();
# Line 378  namespace LinuxSampler { Line 396  namespace LinuxSampler {
396                  }                  }
397                  pVoicePool->clear();                  pVoicePool->clear();
398    
399                  // (re)create event generator                  // update event generator
400                  if (pEventGenerator) delete pEventGenerator;                  pEventGenerator->SetSampleRate(pAudioOut->SampleRate());
                 pEventGenerator = new EventGenerator(pAudioOut->SampleRate());  
401    
402                  dmsg(1,("Starting disk thread..."));                  dmsg(1,("Starting disk thread..."));
403                  pDiskThread->StartThread();                  pDiskThread->StartThread();
# Line 596  namespace LinuxSampler { Line 613  namespace LinuxSampler {
613              }              }
614    
615              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
616              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
617                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
618                  return pRegionPool[index];                  return pRegionPool[index];
619              }              }
# Line 604  namespace LinuxSampler { Line 621  namespace LinuxSampler {
621              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
622              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
623              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
624              virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }              virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
625    
626              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
627    
# Line 675  namespace LinuxSampler { Line 692  namespace LinuxSampler {
692               * @param pNoteOnEvent - event which caused this               * @param pNoteOnEvent - event which caused this
693               * @returns new note's unique ID (or zero on error)               * @returns new note's unique ID (or zero on error)
694               */               */
695              note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {              note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
696                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
697                  Pool< Note<V> >* pNotePool = GetNotePool();                  Pool< Note<V> >* pNotePool = GetNotePool();
698    
# Line 689  namespace LinuxSampler { Line 706  namespace LinuxSampler {
706                  NoteIterator itNewNote = pNotePool->allocAppend();                  NoteIterator itNewNote = pNotePool->allocAppend();
707                  const note_id_t newNoteID = pNotePool->getID(itNewNote);                  const note_id_t newNoteID = pNotePool->getID(itNewNote);
708    
709                    // remember the engine's time when this note was triggered exactly
710                    itNewNote->triggerSchedTime = itNoteOnEvent->SchedTime();
711    
712                  // usually the new note (and its subsequent voices) will be                  // usually the new note (and its subsequent voices) will be
713                  // allocated on the key provided by the event's note number,                  // allocated on the key provided by the event's note number,
714                  // however if this new note is requested not to be a regular                  // however if this new note is requested not to be a regular
715                  // note, but rather a child note, then this new note will be                  // note, but rather a child note, then this new note will be
716                  // allocated on the parent note's key instead in order to                  // allocated on the parent note's key instead in order to
717                  // release the child note simultaniously with its parent note                  // release the child note simultaniously with its parent note
718                  itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;                  itNewNote->hostKey = itNoteOnEvent->Param.Note.Key;
719    
720                  // in case this new note was requested to be a child note,                  // in case this new note was requested to be a child note,
721                  // then retrieve its parent note and link them with each other                  // then retrieve its parent note and link them with each other
722                  const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;                  const note_id_t parentNoteID = itNoteOnEvent->Param.Note.ParentNoteID;
723                  if (parentNoteID) {                  if (parentNoteID) {
724                      NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                                              NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
725                      if (itParentNote) {                      if (itParentNote) {
# Line 727  namespace LinuxSampler { Line 747  namespace LinuxSampler {
747                  dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));                  dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
748    
749                  // copy event which caused this note                  // copy event which caused this note
750                  itNewNote->cause = *pNoteOnEvent;                  itNewNote->cause = *itNoteOnEvent;
751                  itNewNote->eventID = pEventPool->getID(pNoteOnEvent);                  itNewNote->eventID = pEventPool->getID(itNoteOnEvent);
752                    if (!itNewNote->eventID) {
753                        dmsg(0,("Engine: No valid event ID resolved for note. This is a bug!!!\n"));
754                    }
755    
756                  // move new note to its host key                  // move new note to its host key
757                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
758                  itNewNote.moveToEndOf(pKey->pActiveNotes);                  itNewNote.moveToEndOf(pKey->pActiveNotes);
759                    pChannel->markKeyAsActive(pKey);
760    
761                  // 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
762                  pNoteOnEvent->Param.Note.ID = newNoteID;                  itNoteOnEvent->Param.Note.ID = newNoteID;
763    
764                  return newNoteID; // success                  return newNoteID; // success
765              }              }
# Line 771  namespace LinuxSampler { Line 795  namespace LinuxSampler {
795                      //                      //
796                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
797                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
798                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
799                      {                      {
800                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
801                            RTList<Event>::Iterator itNext = itEvent;
802                            ++itNext;
803    
804                          switch (itEvent->Type) {                          switch (itEvent->Type) {
805                              case Event::type_note_on:                              case Event::type_note_on:
806                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 791  namespace LinuxSampler { Line 819  namespace LinuxSampler {
819                              case Event::type_note_pressure:                              case Event::type_note_pressure:
820                                  //TODO: ...                                  //TODO: ...
821                                  break;                                  break;
822    
823                                case Event::type_sysex:
824                                    //TODO: ...
825                                    break;
826    
827                                case Event::type_cancel_release_key:
828                                case Event::type_release_key:
829                                case Event::type_release_note:
830                                case Event::type_play_note:
831                                case Event::type_stop_note:
832                                case Event::type_kill_note:
833                                case Event::type_note_synth_param:
834                                    break; // noop
835                          }                          }
836    
837                            // see HACK comment above
838                            itEvent = itNext;
839                      }                      }
840    
841                      // this has to be run again, since the newly spawned scripts                      // this has to be run again, since the newly spawned scripts
# Line 846  namespace LinuxSampler { Line 890  namespace LinuxSampler {
890                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
891                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
892                                  break;                                  break;
893                                case Event::type_play_note:
894                                    dmsg(5,("Engine: Play Note received\n"));
895                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
896                                    break;
897                              case Event::type_note_off:                              case Event::type_note_off:
898                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
899                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
900                                  break;                                  break;
901                                case Event::type_stop_note:
902                                    dmsg(5,("Engine: Stop Note received\n"));
903                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
904                                    break;
905                                case Event::type_kill_note:
906                                    dmsg(5,("Engine: Kill Note received\n"));
907                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
908                                    break;
909                              case Event::type_control_change:                              case Event::type_control_change:
910                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
911                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 866  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
923                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
924                                  break;                                  break;
925                                case Event::type_note_synth_param:
926                                    dmsg(5,("Engine: Note Synth Param received\n"));
927                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
928                                    break;
929                                case Event::type_sysex:
930                                    break; // TODO ...
931    
932                                case Event::type_cancel_release_key:
933                                case Event::type_release_key:
934                                case Event::type_release_note:
935                                    break; // noop
936                          }                          }
937                      }                      }
938                  }                  }
# Line 934  namespace LinuxSampler { Line 1001  namespace LinuxSampler {
1001                      // script event object                      // script event object
1002                      RTList<ScriptEvent>::Iterator itScriptEvent =                      RTList<ScriptEvent>::Iterator itScriptEvent =
1003                          pChannel->pScript->pEvents->allocAppend();                          pChannel->pScript->pEvents->allocAppend();
1004                        // if event handler uses polyphonic variables, reset them
1005                        // to zero values before starting to execute the handler
1006                        if (pEventHandler->isPolyphonic())
1007                            itScriptEvent->execCtx->resetPolyphonicData();
1008                      ProcessScriptEvent(                      ProcessScriptEvent(
1009                          pChannel, itEvent, pEventHandler, itScriptEvent                          pChannel, itEvent, pEventHandler, itScriptEvent
1010                      );                      );
# Line 966  namespace LinuxSampler { Line 1037  namespace LinuxSampler {
1037    
1038                  // initialize/reset other members                  // initialize/reset other members
1039                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1040                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1041                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1042                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1043                    itScriptEvent->ignoreAllWaitCalls = false;
1044                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1045                    itScriptEvent->parentHandlerID = 0;
1046                    itScriptEvent->childHandlerID[0] = 0;
1047                    itScriptEvent->autoAbortByParent = false;
1048                    itScriptEvent->forkIndex = 0;
1049                  // this is the native representation of the $EVENT_ID script variable                  // this is the native representation of the $EVENT_ID script variable
1050                  itScriptEvent->id =                  itScriptEvent->id =
1051                      (itEvent->Type == Event::type_note_on)                      (itEvent->Type == Event::type_note_on)
# Line 1080  namespace LinuxSampler { Line 1158  namespace LinuxSampler {
1158               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1159               */               */
1160              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1161                    dmsg(3,("StealVoice()\n"));
1162                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1163                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1164                      return -1;                      return -1;
# Line 1104  namespace LinuxSampler { Line 1183  namespace LinuxSampler {
1183                  int                          iChannelIndex;                  int                          iChannelIndex;
1184                  VoiceIterator                itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1185    
1186                    #if CONFIG_DEVMODE
1187                    EngineChannel* pBegin = NULL; // to detect endless loop
1188                    #endif
1189    
1190                  // select engine channel                  // select engine channel
1191                  if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1192                      pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
# Line 1146  namespace LinuxSampler { Line 1229  namespace LinuxSampler {
1229                  }                  }
1230    
1231                  #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1232                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  pBegin = pSelectedChannel; // to detect endless loop
1233                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1234    
1235                  while (true) { // iterate through engine channels                                          while (true) { // iterate through engine channels                        
# Line 1235  namespace LinuxSampler { Line 1318  namespace LinuxSampler {
1318                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1319                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1320                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1321                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1322                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1323                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1324    
1325                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1326                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1327                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1328                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1329                                itScriptEvent->id = 0;
1330                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1331                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1332                                itScriptEvent->currentHandler = 0;
1333                              VMExecStatus_t res = pScriptVM->exec(                              itScriptEvent->executionSlices = 0;
1334                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                              itScriptEvent->ignoreAllWaitCalls = false;
1335                              );                              itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1336                                itScriptEvent->parentHandlerID = 0;
1337                                itScriptEvent->childHandlerID[0] = 0;
1338                                itScriptEvent->autoAbortByParent = false;
1339                                itScriptEvent->forkIndex = 0;
1340    
1341                                VMExecStatus_t res;
1342                                size_t instructionsCount = 0;
1343                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1344                                bool bWarningShown = false;
1345                                do {
1346                                    res = pScriptVM->exec(
1347                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1348                                    );
1349                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1350                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1351                                        bWarningShown = true;
1352                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1353                                    }
1354                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1355    
1356                              pEngineChannel->pScript->pEvents->free(itScriptEvent);                              pEngineChannel->pScript->pEvents->free(itScriptEvent);
1357                          }                          }
# Line 1305  namespace LinuxSampler { Line 1412  namespace LinuxSampler {
1412                          // usually there should already be a new Note object                          // usually there should already be a new Note object
1413                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1414                          if (!itNote) { // should not happen, but just to be sure ...                          if (!itNote) { // should not happen, but just to be sure ...
1415                              const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);                              dmsg(2,("Engine: No Note object for stolen voice!\n"));
1416                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1417                              if (!noteID) {                              if (!noteID) {
1418                                  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"));
1419                                  continue;                                  continue;
# Line 1349  namespace LinuxSampler { Line 1457  namespace LinuxSampler {
1457              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1458                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1459                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1460                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1461    
1462                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1463                  // (only events of the current audio fragment cycle)                  // (only events of the current audio fragment cycle)
# Line 1582  namespace LinuxSampler { Line 1690  namespace LinuxSampler {
1690               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1691               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1692               */               */
1693              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1694                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1695                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1696    
# Line 1592  namespace LinuxSampler { Line 1700  namespace LinuxSampler {
1700    
1701                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1702    
1703                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1704                    // programmatically spawned notes (Event::type_play_note). We have
1705                    // to distinguish between them, since certain processing below
1706                    // must only be done on real MIDI note-on events (i.e. for
1707                    // correctly updating which MIDI keys are currently pressed down).
1708                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1709    
1710                    if (isRealMIDINoteOnEvent)
1711                        pChannel->listeners.PreProcessNoteOn(key, vel);
1712    
1713                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1714                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1715                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1716                            pChannel->listeners.PostProcessNoteOn(key, vel);
1717                      return;                      return;
1718                  }                  }
1719                  #endif                  #endif
1720    
1721                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1722                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1723                            pChannel->listeners.PostProcessNoteOn(key, vel);
1724                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1725                  }                  }
1726    
# Line 1609  namespace LinuxSampler { Line 1728  namespace LinuxSampler {
1728                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1729    
1730                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1731                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1732                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1733                      if (itYoungestKey) {                      if (itYoungestKey) {
1734                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 1757  namespace LinuxSampler {
1757                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1758                  }                  }
1759    
1760                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1761                        pChannel->ProcessKeySwitchChange(key);
1762    
1763                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1764                  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
1765                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1766                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1767                    }
1768    
1769                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1770                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1771                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1772                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1773                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1774                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1775                      }                      }
1776                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1777                  }                  }
# Line 1661  namespace LinuxSampler { Line 1782  namespace LinuxSampler {
1782                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1783                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1784    
1785                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1786                        pChannel->PortamentoPos = (float) key;
1787    
1788                    //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?
1789                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1790                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1791                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1792                  }                  }
1793                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1794                    if (isRealMIDINoteOnEvent)
1795                        pChannel->listeners.PostProcessNoteOn(key, vel);
1796              }              }
1797    
1798              /**              /**
# Line 1695  namespace LinuxSampler { Line 1821  namespace LinuxSampler {
1821               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1822               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1823               */               */
1824              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1825                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1826    
1827                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
# Line 1704  namespace LinuxSampler { Line 1830  namespace LinuxSampler {
1830    
1831                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1832    
1833                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1834                    // programmatically spawned notes (Event::type_stop_note). We have
1835                    // to distinguish between them, since certain processing below
1836                    // must only be done on real MIDI note-off events (i.e. for
1837                    // correctly updating which MIDI keys are currently pressed down),
1838                    // plus a stop-note event just releases voices of one particular
1839                    // note, whereas a note-off event releases all voices on a
1840                    // particular MIDI key instead.
1841                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1842    
1843                    if (isRealMIDINoteOffEvent)
1844                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1845    
1846                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1847                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1848                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1849                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1850                      return;                      return;
1851                  }                  }
1852                  #endif                  #endif
1853    
1854                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1855                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1856                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1857                    }
1858    
1859                  // move event to the key's own event list                  // move event to the key's own event list
1860                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1861    
1862                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1863                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1864    
1865                  // 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)
1866                  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
1867                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1868                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1869                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1870                          // 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
1871                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1872                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1873                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1874                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1875                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1876                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1877                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1878                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1879                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1880                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1881                                      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);  
1882                                      }                                      }
1883                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
1884                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1885                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
1886                                            // copy event
1887                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1888                                            // transform event to a note on event
1889                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1890                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
1891                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1892                                            // assign a new note to this note-on event
1893                                            if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
1894                                                // allocate and trigger new voice(s) for the other key
1895                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1896                                            }
1897                                            // if neither a voice was spawned or postponed then remove note on event from key again
1898                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1899                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1900    
1901                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1902                                  break; // done                                      break; // done
1903                                    }
1904                              }                              }
1905                          }                          }
1906                      }                          if (bOtherKeysPressed) {
1907                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1908                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1909                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1910                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1911                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1912                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1913                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1914                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1915                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
1916                                  }                                  }
1917                              }                              }
1918                          }                          } else pChannel->PortamentoPos = -1.0f;
1919                      } 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  
1920    
1921                      // 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
1922                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1923                          // assign a new note to this release event                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1924                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                          // spawn release triggered voice(s) if needed
1925                              // allocate and trigger new release voice(s)                          ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1926                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                      }
1927                          }                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1928                          pKey->ReleaseTrigger = false;                      // This programmatically caused event is caused by a call to
1929                        // the built-in instrument script function note_off(). In
1930                        // contrast to a real MIDI note-off event the stop-note
1931                        // event just intends to release voices of one particular note.
1932                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1933                        if (pNote) { // the requested note is still alive ...
1934                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1935                        } else { // note is dead and gone ..
1936                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1937                            return; // prevent event to be removed a 2nd time below
1938                      }                      }
1939                  }                  }
1940    
# Line 1796  namespace LinuxSampler { Line 1942  namespace LinuxSampler {
1942                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1943                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1944    
1945                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1946                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1947                }
1948    
1949                /**
1950                 * Called on sustain pedal up events to check and if required,
1951                 * launch release trigger voices on the respective active key.
1952                 *
1953                 * @param pEngineChannel - engine channel on which this event occurred on
1954                 * @param itEvent - release trigger event (contains note number)
1955                 */
1956                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1957                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1958    
1959                    const int iKey = itEvent->Param.Note.Key;
1960                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1961    
1962                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1963    
1964                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1965                }
1966    
1967                /**
1968                 * Called on note-off and sustain pedal up events to check and if
1969                 * required, launch release trigger voices on the respective active
1970                 * key.
1971                 *
1972                 * @param pEngineChannel - engine channel on which this event occurred on
1973                 * @param itEvent - note off event / release trigger event
1974                 * @param pKey - key on which the release trigger voices shall be spawned
1975                 */
1976                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1977                    // spawn release triggered voice(s) if needed
1978                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1979                        // assign a new note to this release event
1980                        if (LaunchNewNote(pChannel, itEvent)) {
1981                            // allocate and trigger new release voice(s)
1982                            TriggerReleaseVoices(pChannel, itEvent);
1983                        }
1984                        pKey->ReleaseTrigger = false;
1985                    }
1986                }
1987    
1988                /**
1989                 * Called on "kill note" events, which currently only happens on
1990                 * built-in real-time instrument script function fade_out(). This
1991                 * method only fulfills one task: moving the even to the Note's own
1992                 * event list so that its voices can process the kill event sample
1993                 * accurately.
1994                 */
1995                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1996                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1997    
1998                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1999                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2000    
2001                    // move note kill event to its MIDI key
2002                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2003                    itEvent.moveToEndOf(pKey->pEvents);
2004                }
2005    
2006                /**
2007                 * Called on note synthesis parameter change events. These are
2008                 * internal events caused by calling built-in real-time instrument
2009                 * script functions like change_vol(), change_tune(), etc.
2010                 *
2011                 * This method performs two tasks:
2012                 *
2013                 * - It converts the event's relative values changes (Deltas) to
2014                 *   the respective final new synthesis parameter value (AbsValue),
2015                 *   for that particular moment of the event that is.
2016                 *
2017                 * - It moves the individual events to the Note's own event list
2018                 *   (or actually to the event list of the MIDI key), so that
2019                 *   voices can process those events sample accurately.
2020                 *
2021                 * @param pEngineChannel - engine channel on which this event occurred on
2022                 * @param itEvent - note synthesis parameter change event
2023                 */
2024                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2025                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2026    
2027                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2028                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2029    
2030                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
2031    
2032                    switch (itEvent->Param.NoteSynthParam.Type) {
2033                        case Event::synth_param_volume:
2034                            if (relative)
2035                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
2036                            else
2037                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
2038                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
2039                            break;
2040                        case Event::synth_param_volume_time:
2041                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2042                            break;
2043                        case Event::synth_param_volume_curve:
2044                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2045                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2046                            break;
2047                        case Event::synth_param_pitch:
2048                            if (relative)
2049                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
2050                            else
2051                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
2052                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
2053                            break;
2054                        case Event::synth_param_pitch_time:
2055                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2056                            break;
2057                        case Event::synth_param_pitch_curve:
2058                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2059                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2060                            break;
2061                        case Event::synth_param_pan:
2062                            if (relative) {
2063                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2064                            } else {
2065                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2066                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2067                            }
2068                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2069                            break;
2070                        case Event::synth_param_cutoff:
2071                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2072                            break;
2073                        case Event::synth_param_resonance:
2074                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2075                            break;
2076                        case Event::synth_param_attack:
2077                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2078                            break;
2079                        case Event::synth_param_decay:
2080                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2081                            break;
2082                        case Event::synth_param_sustain:
2083                            pNote->Override.Sustain = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2084                            break;
2085                        case Event::synth_param_release:
2086                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2087                            break;
2088                        case Event::synth_param_amp_lfo_depth:
2089                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2090                            break;
2091                        case Event::synth_param_amp_lfo_freq:
2092                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2093                            break;
2094                        case Event::synth_param_pitch_lfo_depth:
2095                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2096                            break;
2097                        case Event::synth_param_pitch_lfo_freq:
2098                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2099                            break;
2100                    }
2101    
2102                    // move note parameter event to its MIDI key
2103                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2104                    itEvent.moveToEndOf(pKey->pEvents);
2105              }              }
2106    
2107              /**              /**
2108               *  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
2109               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2110               */               */
2111              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2112                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2113    
2114                  // 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 2167  namespace LinuxSampler {
2167               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2168               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2169               */               */
2170              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2171                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2172                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2173                  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 2202  namespace LinuxSampler {
2202                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2203              ) = 0;              ) = 0;
2204    
2205              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2206    
2207              int InitNewVoice (              int InitNewVoice (
2208                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1920  namespace LinuxSampler { Line 2225  namespace LinuxSampler {
2225                      }                      }
2226                      else { // on success                      else { // on success
2227                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2228                          if (!pKey->Active) { // mark as active key  
2229                              pKey->Active = true;                          // should actually be superfluous now, since this is
2230                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2231                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2232                          }  
2233                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)                          if (itNewVoice->Type & Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
2234                          return 0; // success                          return 0; // success
2235                      }                      }

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

  ViewVC Help
Powered by ViewVC