/[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 3697 by schoenebeck, Sat Jan 4 12:09:45 2020 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 841  namespace LinuxSampler { Line 885  namespace LinuxSampler {
885                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
886                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
887                      for (; itEvent != end; ++itEvent) {                      for (; itEvent != end; ++itEvent) {
888                            bool bIsCC = false; // just for resetting RPN/NRPN below
889                          switch (itEvent->Type) {                          switch (itEvent->Type) {
890                              case Event::type_note_on:                              case Event::type_note_on:
891                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
892                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
893                                  break;                                  break;
894                                case Event::type_play_note:
895                                    dmsg(5,("Engine: Play Note received\n"));
896                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
897                                    break;
898                              case Event::type_note_off:                              case Event::type_note_off:
899                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
900                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
901                                  break;                                  break;
902                                case Event::type_stop_note:
903                                    dmsg(5,("Engine: Stop Note received\n"));
904                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
905                                    break;
906                                case Event::type_kill_note:
907                                    dmsg(5,("Engine: Kill Note received\n"));
908                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
909                                    break;
910                              case Event::type_control_change:                              case Event::type_control_change:
911                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
912                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
913                                    bIsCC = true;
914                                    break;
915                                case Event::type_rpn: // this can only be reached here by an instrument script having called set_rpn()
916                                    dmsg(5,("Engine: MIDI RPN received\n"));
917                                    ProcessHardcodedRpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
918                                    bIsCC = true;
919                                    break;
920                                case Event::type_nrpn: // this can only be reached here by an instrument script having called set_nrpn()
921                                    dmsg(5,("Engine: MIDI NRPN received\n"));
922                                    ProcessHardcodedNrpn((EngineChannel*)itEvent->pEngineChannel, itEvent);
923                                    bIsCC = true;
924                                  break;                                  break;
925                              case Event::type_channel_pressure:                              case Event::type_channel_pressure:
926                                  dmsg(5,("Engine: MIDI Chan. Pressure received\n"));                                  dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
# Line 866  namespace LinuxSampler { Line 934  namespace LinuxSampler {
934                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
935                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
936                                  break;                                  break;
937                                case Event::type_note_synth_param:
938                                    dmsg(5,("Engine: Note Synth Param received\n"));
939                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
940                                    break;
941                                case Event::type_sysex:
942                                    break; // TODO ...
943    
944                                case Event::type_cancel_release_key:
945                                case Event::type_release_key:
946                                case Event::type_release_note:
947                                    break; // noop
948                            }
949                            // reset cached RPN/NRPN parameter number and data in
950                            // case this event was not a control change event
951                            if (!bIsCC) {
952                                if (pChannel->GetMidiRpnParameter() >= 0)
953                                    pChannel->ResetMidiRpnParameter();
954                                if (pChannel->GetMidiNrpnParameter() >= 0)
955                                    pChannel->ResetMidiNrpnParameter();
956                          }                          }
957                      }                      }
958                  }                  }
# Line 934  namespace LinuxSampler { Line 1021  namespace LinuxSampler {
1021                      // script event object                      // script event object
1022                      RTList<ScriptEvent>::Iterator itScriptEvent =                      RTList<ScriptEvent>::Iterator itScriptEvent =
1023                          pChannel->pScript->pEvents->allocAppend();                          pChannel->pScript->pEvents->allocAppend();
1024                        // if event handler uses polyphonic variables, reset them
1025                        // to zero values before starting to execute the handler
1026                        if (pEventHandler->isPolyphonic())
1027                            itScriptEvent->execCtx->resetPolyphonicData();
1028                      ProcessScriptEvent(                      ProcessScriptEvent(
1029                          pChannel, itEvent, pEventHandler, itScriptEvent                          pChannel, itEvent, pEventHandler, itScriptEvent
1030                      );                      );
# Line 966  namespace LinuxSampler { Line 1057  namespace LinuxSampler {
1057    
1058                  // initialize/reset other members                  // initialize/reset other members
1059                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1060                    itScriptEvent->scheduleTime = itEvent->SchedTime();
1061                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1062                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1063                    itScriptEvent->ignoreAllWaitCalls = false;
1064                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1065                    itScriptEvent->parentHandlerID = 0;
1066                    itScriptEvent->childHandlerID[0] = 0;
1067                    itScriptEvent->autoAbortByParent = false;
1068                    itScriptEvent->forkIndex = 0;
1069                  // this is the native representation of the $EVENT_ID script variable                  // this is the native representation of the $EVENT_ID script variable
1070                  itScriptEvent->id =                  itScriptEvent->id =
1071                      (itEvent->Type == Event::type_note_on)                      (itEvent->Type == Event::type_note_on)
# Line 1080  namespace LinuxSampler { Line 1178  namespace LinuxSampler {
1178               *  @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
1179               */               */
1180              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1181                    dmsg(3,("StealVoice()\n"));
1182                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1183                      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"));
1184                      return -1;                      return -1;
# Line 1104  namespace LinuxSampler { Line 1203  namespace LinuxSampler {
1203                  int                          iChannelIndex;                  int                          iChannelIndex;
1204                  VoiceIterator                itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1205    
1206                    #if CONFIG_DEVMODE
1207                    EngineChannel* pBegin = NULL; // to detect endless loop
1208                    #endif
1209    
1210                  // select engine channel                  // select engine channel
1211                  if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1212                      pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
# Line 1146  namespace LinuxSampler { Line 1249  namespace LinuxSampler {
1249                  }                  }
1250    
1251                  #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1252                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  pBegin = pSelectedChannel; // to detect endless loop
1253                  #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1254    
1255                  while (true) { // iterate through engine channels                                          while (true) { // iterate through engine channels                        
# Line 1235  namespace LinuxSampler { Line 1338  namespace LinuxSampler {
1338                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1339                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1340                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1341                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1342                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1343                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1344    
1345                                itScriptEvent->cause = pEventGenerator->CreateEvent(0);
1346                                itScriptEvent->cause.Type = (Event::type_t) -1; // some invalid type to avoid random event processing
1347                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1348                                itScriptEvent->cause.pMidiInputPort = pEngineChannel->GetMidiInputPort();
1349                                itScriptEvent->id = 0;
1350                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1351                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1352                                itScriptEvent->currentHandler = 0;
1353                              VMExecStatus_t res = pScriptVM->exec(                              itScriptEvent->executionSlices = 0;
1354                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                              itScriptEvent->ignoreAllWaitCalls = false;
1355                              );                              itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1356                                itScriptEvent->parentHandlerID = 0;
1357                                itScriptEvent->childHandlerID[0] = 0;
1358                                itScriptEvent->autoAbortByParent = false;
1359                                itScriptEvent->forkIndex = 0;
1360    
1361                                VMExecStatus_t res;
1362                                size_t instructionsCount = 0;
1363                                const size_t maxInstructions = 200000; // aiming approx. 1 second max. (based on very roughly 5us / instruction)
1364                                bool bWarningShown = false;
1365                                do {
1366                                    res = pScriptVM->exec(
1367                                        pEngineChannel->pScript->parserContext, &*itScriptEvent
1368                                    );
1369                                    instructionsCount += itScriptEvent->execCtx->instructionsPerformed();
1370                                    if (instructionsCount > maxInstructions && !bWarningShown) {
1371                                        bWarningShown = true;
1372                                        dmsg(0,("[ScriptVM] WARNING: \"init\" event handler of instrument script executing for long time!\n"));
1373                                    }
1374                                } while (res & VM_EXEC_SUSPENDED && !(res & VM_EXEC_ERROR));
1375    
1376                              pEngineChannel->pScript->pEvents->free(itScriptEvent);                              pEngineChannel->pScript->pEvents->free(itScriptEvent);
1377                          }                          }
# Line 1305  namespace LinuxSampler { Line 1432  namespace LinuxSampler {
1432                          // usually there should already be a new Note object                          // usually there should already be a new Note object
1433                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);                          NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1434                          if (!itNote) { // should not happen, but just to be sure ...                          if (!itNote) { // should not happen, but just to be sure ...
1435                              const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);                              dmsg(2,("Engine: No Note object for stolen voice!\n"));
1436                                const note_id_t noteID = LaunchNewNote(pEngineChannel, itVoiceStealEvent);
1437                              if (!noteID) {                              if (!noteID) {
1438                                  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"));
1439                                  continue;                                  continue;
# Line 1349  namespace LinuxSampler { Line 1477  namespace LinuxSampler {
1477              void PostProcess(EngineChannel* pEngineChannel) {              void PostProcess(EngineChannel* pEngineChannel) {
1478                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1479                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1480                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKeys();
1481    
1482                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1483                  // (only events of the current audio fragment cycle)                  // (only events of the current audio fragment cycle)
# Line 1371  namespace LinuxSampler { Line 1499  namespace LinuxSampler {
1499                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1500                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                      static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1501    
1502                    // will be set to true if this CC event has anything to do with RPN/NRPN
1503                    bool bIsRpn = false, bIsNrpn = false;
1504    
1505                  switch (itControlChangeEvent->Param.CC.Controller) {                  switch (itControlChangeEvent->Param.CC.Controller) {
1506                      case 5: { // portamento time                      case 5: { // portamento time
1507                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                          pChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1508                          break;                          break;
1509                      }                      }
1510                      case 6: { // data entry (currently only used for RPN and NRPN controllers)                      case 6: { // data entry (MSB)
1511                          //dmsg(1,("DATA ENTRY %d\n", itControlChangeEvent->Param.CC.Value));                          //dmsg(1,("DATA ENTRY MSB %d\n", itControlChangeEvent->Param.CC.Value));
1512                          if (pChannel->GetMidiRpnController() >= 0) { // RPN controller number was sent previously ...                          if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1513                              dmsg(4,("Guess it's an RPN ...\n"));                              pChannel->SetMidiRpnDataMsb(
1514                              if (pChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones                                  itControlChangeEvent->Param.CC.Value
1515                                  int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;                              );
1516                                  // limit to +- two octaves for now                              bIsRpn = true;
1517                                  transpose = RTMath::Min(transpose,  24);  
1518                                  transpose = RTMath::Max(transpose, -24);                              // look-ahead: if next MIDI event is data entry LSB,
1519                                  pChannel->GlobalTranspose = transpose;                              // then skip this event here for now (to avoid double
1520                                  // workaround, so we won't have hanging notes                              // handling of what's supposed to be one RPN event)
1521                                  pChannel->ReleaseAllVoices(itControlChangeEvent);                              if (isNextEventCCNr(itControlChangeEvent, 38))
1522                              }                                  break;
1523                              // to prevent other MIDI CC #6 messages to be misenterpreted as RPN controller data  
1524                              pChannel->ResetMidiRpnController();                              int ch = itControlChangeEvent->Param.CC.Channel;
1525                          } else if (pChannel->GetMidiNrpnController() >= 0) { // NRPN controller number was sent previously ...                              int param = pChannel->GetMidiRpnParameter();
1526                              dmsg(4,("Guess it's an NRPN ...\n"));                              int value = pChannel->GetMidiRpnData();
1527                              const int NrpnCtrlMSB = pChannel->GetMidiNrpnController() >> 8;  
1528                              const int NrpnCtrlLSB = pChannel->GetMidiNrpnController() & 0xff;                              // transform event type: CC event -> RPN event
1529                              dmsg(4,("NRPN MSB=%d LSB=%d Data=%d\n", NrpnCtrlMSB, NrpnCtrlLSB, itControlChangeEvent->Param.CC.Value));                              itControlChangeEvent->Type = Event::type_rpn;
1530                              switch (NrpnCtrlMSB) {                              itControlChangeEvent->Param.RPN.Channel = ch;
1531                                  case 0x1a: { // volume level of note (Roland GS NRPN)                              itControlChangeEvent->Param.RPN.Parameter = param;
1532                                      const uint note = NrpnCtrlLSB;                              itControlChangeEvent->Param.RPN.Value = value;
1533                                      const uint vol  = itControlChangeEvent->Param.CC.Value;  
1534                                      dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));                              // if there's a RPN script handler, run it ...
1535                                      if (note < 128 && vol < 128)                              if (pChannel->pScript->handlerRpn) {
1536                                          pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];                                  const event_id_t eventID =
1537                                      break;                                      pEventPool->getID(itControlChangeEvent);
1538                                  }                                  // run the RPN script handler
1539                                  case 0x1c: { // panpot of note (Roland GS NRPN)                                  ProcessEventByScript(
1540                                      const uint note = NrpnCtrlLSB;                                      pChannel, itControlChangeEvent,
1541                                      const uint pan  = itControlChangeEvent->Param.CC.Value;                                      pChannel->pScript->handlerRpn
1542                                      dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));                                  );
1543                                      if (note < 128 && pan < 128) {                                  // if RPN event was dropped by script, abort
1544                                          pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];                                  // here to avoid hard coded RPN processing below
1545                                          pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];                                  if (!pEventPool->fromID(eventID))
                                     }  
                                     break;  
                                 }  
                                 case 0x1d: { // reverb send of note (Roland GS NRPN)  
                                     const uint note = NrpnCtrlLSB;  
                                     const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;  
                                     dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));  
                                     if (note < 128)  
                                         pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;  
1546                                      break;                                      break;
1547                                  }                              }
1548                                  case 0x1e: { // chorus send of note (Roland GS NRPN)  
1549                                      const uint note = NrpnCtrlLSB;                              // do the actual (hard-coded) RPN value change processing
1550                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                              ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1551                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));  
1552                                      if (note < 128)                          } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1553                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                              pChannel->SetMidiNrpnDataMsb(
1554                                    itControlChangeEvent->Param.CC.Value
1555                                );
1556                                bIsNrpn = true;
1557    
1558                                // look-ahead: if next MIDI event is data entry LSB,
1559                                // then skip this event here for now (to avoid double
1560                                // handling of what's supposed to be one NRPN event)
1561                                if (isNextEventCCNr(itControlChangeEvent, 38))
1562                                    break;
1563    
1564                                int ch = itControlChangeEvent->Param.CC.Channel;
1565                                int param = pChannel->GetMidiNrpnParameter();
1566                                int value = pChannel->GetMidiNrpnData();
1567    
1568                                // transform event type: CC event -> NRPN event
1569                                itControlChangeEvent->Type = Event::type_nrpn;
1570                                itControlChangeEvent->Param.NRPN.Channel = ch;
1571                                itControlChangeEvent->Param.NRPN.Parameter = param;
1572                                itControlChangeEvent->Param.NRPN.Value = value;
1573    
1574                                // if there's a NRPN script handler, run it ...
1575                                if (pChannel->pScript->handlerNrpn) {
1576                                    const event_id_t eventID =
1577                                        pEventPool->getID(itControlChangeEvent);
1578                                    // run the NRPN script handler
1579                                    ProcessEventByScript(
1580                                        pChannel, itControlChangeEvent,
1581                                        pChannel->pScript->handlerNrpn
1582                                    );
1583                                    // if NRPN event was dropped by script, abort
1584                                    // here to avoid hard coded NRPN processing below
1585                                    if (!pEventPool->fromID(eventID))
1586                                      break;                                      break;
                                 }  
1587                              }                              }
1588                              // to prevent other MIDI CC #6 messages to be misenterpreted as NRPN controller data  
1589                              pChannel->ResetMidiNrpnController();                              // do the actual (hard-coded) NRPN value change processing
1590                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1591                          }                          }
1592                          break;                          break;
1593                      }                      }
# Line 1448  namespace LinuxSampler { Line 1602  namespace LinuxSampler {
1602                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1603                          break;                          break;
1604                      }                      }
1605                        case 38: { // data entry (LSB)
1606                            //dmsg(1,("DATA ENTRY LSB %d\n", itControlChangeEvent->Param.CC.Value));
1607                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1608                                pChannel->SetMidiRpnDataLsb(
1609                                    itControlChangeEvent->Param.CC.Value
1610                                );
1611                                bIsRpn = true;
1612    
1613                                int ch = itControlChangeEvent->Param.CC.Channel;
1614                                int param = pChannel->GetMidiRpnParameter();
1615                                int value = pChannel->GetMidiRpnData();
1616    
1617                                // transform event type: CC event -> RPN event
1618                                itControlChangeEvent->Type = Event::type_rpn;
1619                                itControlChangeEvent->Param.RPN.Channel = ch;
1620                                itControlChangeEvent->Param.RPN.Parameter = param;
1621                                itControlChangeEvent->Param.RPN.Value = value;
1622    
1623                                // if there's a RPN script handler, run it ...
1624                                if (pChannel->pScript->handlerRpn) {
1625                                    const event_id_t eventID =
1626                                        pEventPool->getID(itControlChangeEvent);
1627                                    // run the RPN script handler
1628                                    ProcessEventByScript(
1629                                        pChannel, itControlChangeEvent,
1630                                        pChannel->pScript->handlerRpn
1631                                    );
1632                                    // if RPN event was dropped by script, abort
1633                                    // here to avoid hard coded RPN processing below
1634                                    if (!pEventPool->fromID(eventID))
1635                                        break;
1636                                }
1637    
1638                                // do the actual (hard-coded) RPN value change processing
1639                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1640    
1641                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1642                                pChannel->SetMidiNrpnDataLsb(
1643                                    itControlChangeEvent->Param.CC.Value
1644                                );
1645                                bIsNrpn = true;
1646    
1647                                int ch = itControlChangeEvent->Param.CC.Channel;
1648                                int param = pChannel->GetMidiNrpnParameter();
1649                                int value = pChannel->GetMidiNrpnData();
1650    
1651                                // transform event type: CC event -> NRPN event
1652                                itControlChangeEvent->Type = Event::type_nrpn;
1653                                itControlChangeEvent->Param.NRPN.Channel = ch;
1654                                itControlChangeEvent->Param.NRPN.Parameter = param;
1655                                itControlChangeEvent->Param.NRPN.Value = value;
1656    
1657                                // if there's a NRPN script handler, run it ...
1658                                if (pChannel->pScript->handlerNrpn) {
1659                                    const event_id_t eventID =
1660                                        pEventPool->getID(itControlChangeEvent);
1661                                    // run the NRPN script handler
1662                                    ProcessEventByScript(
1663                                        pChannel, itControlChangeEvent,
1664                                        pChannel->pScript->handlerNrpn
1665                                    );
1666                                    // if NRPN event was dropped by script, abort
1667                                    // here to avoid hard coded NRPN processing below
1668                                    if (!pEventPool->fromID(eventID))
1669                                        break;
1670                                }
1671    
1672                                // do the actual (hard-coded) NRPN value change processing
1673                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1674                            }
1675                            break;
1676                        }
1677                      case 64: { // sustain                      case 64: { // sustain
1678                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {                          if (itControlChangeEvent->Param.CC.Value >= 64 && !pChannel->SustainPedal) {
1679                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));                              dmsg(4,("DAMPER (RIGHT) PEDAL DOWN\n"));
# Line 1521  namespace LinuxSampler { Line 1747  namespace LinuxSampler {
1747                          }                          }
1748                          break;                          break;
1749                      }                      }
1750                      case 98: { // NRPN controller LSB                      case 98: { // NRPN parameter LSB
1751                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1752                          pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1753                            pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1754                          break;                          break;
1755                      }                      }
1756                      case 99: { // NRPN controller MSB                      case 99: { // NRPN parameter MSB
1757                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1758                          pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1759                            pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1760                          break;                          break;
1761                      }                      }
1762                      case 100: { // RPN controller LSB                      case 100: { // RPN parameter LSB
1763                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1764                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1765                            pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1766                          break;                          break;
1767                      }                      }
1768                      case 101: { // RPN controller MSB                      case 101: { // RPN parameter MSB
1769                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1770                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1771                            pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1772                          break;                          break;
1773                      }                      }
1774    
# Line 1572  namespace LinuxSampler { Line 1802  namespace LinuxSampler {
1802                          break;                          break;
1803                      }                      }
1804                  }                  }
1805    
1806                    // reset cached RPN/NRPN parameter number and data in case this
1807                    // CC event had nothing to do with RPN/NRPN
1808                    if (!bIsRpn && pChannel->GetMidiRpnParameter() >= 0)
1809                        pChannel->ResetMidiRpnParameter();
1810                    if (!bIsNrpn && pChannel->GetMidiNrpnParameter() >= 0)
1811                        pChannel->ResetMidiNrpnParameter();
1812                }
1813    
1814                /**
1815                 * Process MIDI RPN events with hard coded behavior.
1816                 *
1817                 * @param pEngineChannel - engine channel on which the MIDI RPN
1818                 *                         event was received
1819                 * @param itRpnEvent - the actual MIDI RPN event
1820                 */
1821                void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1822                                         Pool<Event>::Iterator& itRpnEvent)
1823                {
1824                    EngineChannelBase<V, R, I>* pChannel =
1825                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1826    
1827                    if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1828                        int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1829                        // limit to +- two octaves for now
1830                        transpose = RTMath::Min(transpose,  24);
1831                        transpose = RTMath::Max(transpose, -24);
1832                        pChannel->GlobalTranspose = transpose;
1833                        // workaround, so we won't have hanging notes
1834                        pChannel->ReleaseAllVoices(itRpnEvent);
1835                    }
1836                }
1837    
1838                /**
1839                 * Process MIDI NRPN events with hard coded behavior.
1840                 *
1841                 * @param pEngineChannel - engine channel on which the MIDI NRPN
1842                 *                         event was received
1843                 * @param itRpnEvent - the actual MIDI NRPN event
1844                 */
1845                void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1846                                          Pool<Event>::Iterator& itNrpnEvent)
1847                {
1848                    EngineChannelBase<V, R, I>* pChannel =
1849                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1850    
1851                    switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
1852                        case 0x1a: { // volume level of note (Roland GS NRPN)
1853                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1854                            const uint vol  = itNrpnEvent->Param.NRPN.ValueMSB();
1855                            dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
1856                            if (note < 128 && vol < 128)
1857                                pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
1858                            break;
1859                        }
1860                        case 0x1c: { // panpot of note (Roland GS NRPN)
1861                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1862                            const uint pan  = itNrpnEvent->Param.NRPN.ValueMSB();
1863                            dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
1864                            if (note < 128 && pan < 128) {
1865                                pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
1866                                pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
1867                            }
1868                            break;
1869                        }
1870                        case 0x1d: { // reverb send of note (Roland GS NRPN)
1871                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1872                            const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1873                            dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1874                            if (note < 128)
1875                                pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1876                            break;
1877                        }
1878                        case 0x1e: { // chorus send of note (Roland GS NRPN)
1879                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1880                            const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
1881                            dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1882                            if (note < 128)
1883                                pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1884                            break;
1885                        }
1886                    }
1887              }              }
1888    
1889              virtual D* CreateDiskThread() = 0;              virtual D* CreateDiskThread() = 0;
# Line 1582  namespace LinuxSampler { Line 1894  namespace LinuxSampler {
1894               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1895               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1896               */               */
1897              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1898                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1899                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1900    
# Line 1592  namespace LinuxSampler { Line 1904  namespace LinuxSampler {
1904    
1905                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1906    
1907                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1908                    // programmatically spawned notes (Event::type_play_note). We have
1909                    // to distinguish between them, since certain processing below
1910                    // must only be done on real MIDI note-on events (i.e. for
1911                    // correctly updating which MIDI keys are currently pressed down).
1912                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1913    
1914                    if (isRealMIDINoteOnEvent)
1915                        pChannel->listeners.PreProcessNoteOn(key, vel);
1916    
1917                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1918                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1919                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1920                            pChannel->listeners.PostProcessNoteOn(key, vel);
1921                      return;                      return;
1922                  }                  }
1923                  #endif                  #endif
1924    
1925                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1926                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1927                            pChannel->listeners.PostProcessNoteOn(key, vel);
1928                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1929                  }                  }
1930    
# Line 1609  namespace LinuxSampler { Line 1932  namespace LinuxSampler {
1932                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1933    
1934                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1935                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1936                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1937                      if (itYoungestKey) {                      if (itYoungestKey) {
1938                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 1961  namespace LinuxSampler {
1961                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1962                  }                  }
1963    
1964                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1965                        pChannel->ProcessKeySwitchChange(key);
1966    
1967                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1968                  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
1969                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1970                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1971                    }
1972    
1973                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1974                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1975                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1976                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1977                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1978                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1979                      }                      }
1980                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1981                  }                  }
# Line 1661  namespace LinuxSampler { Line 1986  namespace LinuxSampler {
1986                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1987                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1988    
1989                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1990                        pChannel->PortamentoPos = (float) key;
1991    
1992                    //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?
1993                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1994                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1995                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1996                  }                  }
1997                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1998                    if (isRealMIDINoteOnEvent)
1999                        pChannel->listeners.PostProcessNoteOn(key, vel);
2000              }              }
2001    
2002              /**              /**
# Line 1695  namespace LinuxSampler { Line 2025  namespace LinuxSampler {
2025               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
2026               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
2027               */               */
2028              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
2029                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2030    
2031                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
# Line 1704  namespace LinuxSampler { Line 2034  namespace LinuxSampler {
2034    
2035                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2036    
2037                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
2038                    // programmatically spawned notes (Event::type_stop_note). We have
2039                    // to distinguish between them, since certain processing below
2040                    // must only be done on real MIDI note-off events (i.e. for
2041                    // correctly updating which MIDI keys are currently pressed down),
2042                    // plus a stop-note event just releases voices of one particular
2043                    // note, whereas a note-off event releases all voices on a
2044                    // particular MIDI key instead.
2045                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2046    
2047                    if (isRealMIDINoteOffEvent)
2048                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
2049    
2050                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2051                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2052                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
2053                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
2054                      return;                      return;
2055                  }                  }
2056                  #endif                  #endif
2057    
2058                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
2059                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
2060                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2061                    }
2062    
2063                  // move event to the key's own event list                  // move event to the key's own event list
2064                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2065    
2066                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
2067                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2068    
2069                  // 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)
2070                  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
2071                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
2072                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
2073                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
2074                          // 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
2075                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
2076                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2077                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
2078                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
2079                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
2080                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
2081                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
2082                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
2083                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
2084                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
2085                                      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);  
2086                                      }                                      }
2087                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
2088                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2089                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
2090                                            // copy event
2091                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2092                                            // transform event to a note on event
2093                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
2094                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
2095                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2096                                            // assign a new note to this note-on event
2097                                            if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2098                                                // allocate and trigger new voice(s) for the other key
2099                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2100                                            }
2101                                            // if neither a voice was spawned or postponed then remove note on event from key again
2102                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2103                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2104    
2105                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
2106                                  break; // done                                      break; // done
2107                                    }
2108                              }                              }
2109                          }                          }
2110                      }                          if (bOtherKeysPressed) {
2111                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
2112                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
2113                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2114                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2115                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
2116                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2117                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2118                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2119                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
2120                                  }                                  }
2121                              }                              }
2122                          }                          } else pChannel->PortamentoPos = -1.0f;
2123                      } 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  
2124    
2125                      // 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
2126                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
2127                          // assign a new note to this release event                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2128                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                          // spawn release triggered voice(s) if needed
2129                              // allocate and trigger new release voice(s)                          if (pKey->ReleaseTrigger & release_trigger_noteoff)
2130                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                              ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2131                          }                      }
2132                          pKey->ReleaseTrigger = false;                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2133                        // This programmatically caused event is caused by a call to
2134                        // the built-in instrument script function note_off(). In
2135                        // contrast to a real MIDI note-off event the stop-note
2136                        // event just intends to release voices of one particular note.
2137                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2138                        if (pNote) { // the requested note is still alive ...
2139                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2140                        } else { // note is dead and gone ..
2141                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2142                            return; // prevent event to be removed a 2nd time below
2143                      }                      }
2144                  }                  }
2145    
# Line 1796  namespace LinuxSampler { Line 2147  namespace LinuxSampler {
2147                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2148                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
2149    
2150                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
2151                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
2152                }
2153    
2154                /**
2155                 * Called on sustain pedal up events to check and if required,
2156                 * launch release trigger voices on the respective active key.
2157                 *
2158                 * @param pEngineChannel - engine channel on which this event occurred on
2159                 * @param itEvent - release trigger event (contains note number)
2160                 */
2161                virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2162                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2163    
2164                    const int iKey = itEvent->Param.Note.Key;
2165                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2166    
2167                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2168    
2169                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
2170                }
2171    
2172                /**
2173                 * Called on note-off and sustain pedal up events to check and if
2174                 * required, launch release trigger voices on the respective active
2175                 * key.
2176                 *
2177                 * @param pEngineChannel - engine channel on which this event occurred on
2178                 * @param itEvent - note off event / release trigger event
2179                 * @param pKey - key on which the release trigger voices shall be spawned
2180                 */
2181                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2182                    // spawn release triggered voice(s) if needed
2183                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2184                        // assign a new note to this release event
2185                        if (LaunchNewNote(pChannel, itEvent)) {
2186                            // allocate and trigger new release voice(s)
2187                            TriggerReleaseVoices(pChannel, itEvent);
2188                        }
2189                        pKey->ReleaseTrigger = release_trigger_none;
2190                    }
2191                }
2192    
2193                /**
2194                 * Called on "kill note" events, which currently only happens on
2195                 * built-in real-time instrument script function fade_out(). This
2196                 * method only fulfills one task: moving the even to the Note's own
2197                 * event list so that its voices can process the kill event sample
2198                 * accurately.
2199                 */
2200                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2201                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2202    
2203                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2204                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2205    
2206                    // move note kill event to its MIDI key
2207                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2208                    itEvent.moveToEndOf(pKey->pEvents);
2209                }
2210    
2211                /**
2212                 * Called on note synthesis parameter change events. These are
2213                 * internal events caused by calling built-in real-time instrument
2214                 * script functions like change_vol(), change_tune(), etc.
2215                 *
2216                 * This method performs two tasks:
2217                 *
2218                 * - It converts the event's relative values changes (Deltas) to
2219                 *   the respective final new synthesis parameter value (AbsValue),
2220                 *   for that particular moment of the event that is.
2221                 *
2222                 * - It moves the individual events to the Note's own event list
2223                 *   (or actually to the event list of the MIDI key), so that
2224                 *   voices can process those events sample accurately.
2225                 *
2226                 * @param pEngineChannel - engine channel on which this event occurred on
2227                 * @param itEvent - note synthesis parameter change event
2228                 */
2229                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2230                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2231    
2232                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2233                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2234    
2235                    switch (itEvent->Param.NoteSynthParam.Type) {
2236                        case Event::synth_param_volume:
2237                            pNote->apply(itEvent, &NoteBase::_Override::Volume);
2238                            break;
2239                        case Event::synth_param_volume_time:
2240                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2241                            break;
2242                        case Event::synth_param_volume_curve:
2243                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2244                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2245                            break;
2246                        case Event::synth_param_pitch:
2247                            pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2248                            break;
2249                        case Event::synth_param_pitch_time:
2250                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2251                            break;
2252                        case Event::synth_param_pitch_curve:
2253                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2254                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2255                            break;
2256                        case Event::synth_param_pan:
2257                            pNote->apply(itEvent, &NoteBase::_Override::Pan);
2258                            break;
2259                        case Event::synth_param_pan_time:
2260                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2261                            break;
2262                        case Event::synth_param_pan_curve:
2263                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2264                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2265                            break;
2266                        case Event::synth_param_cutoff:
2267                            pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2268                            break;
2269                        case Event::synth_param_resonance:
2270                            pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2271                            break;
2272                        case Event::synth_param_attack:
2273                            pNote->apply(itEvent, &NoteBase::_Override::Attack);
2274                            break;
2275                        case Event::synth_param_decay:
2276                            pNote->apply(itEvent, &NoteBase::_Override::Decay);
2277                            break;
2278                        case Event::synth_param_sustain:
2279                            pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2280                            break;
2281                        case Event::synth_param_release:
2282                            pNote->apply(itEvent, &NoteBase::_Override::Release);
2283                            break;
2284    
2285                        case Event::synth_param_cutoff_attack:
2286                            pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2287                            break;
2288                        case Event::synth_param_cutoff_decay:
2289                            pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2290                            break;
2291                        case Event::synth_param_cutoff_sustain:
2292                            pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2293                            break;
2294                        case Event::synth_param_cutoff_release:
2295                            pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2296                            break;
2297    
2298                        case Event::synth_param_amp_lfo_depth:
2299                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2300                            break;
2301                        case Event::synth_param_amp_lfo_freq:
2302                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2303                            break;
2304                        case Event::synth_param_cutoff_lfo_depth:
2305                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2306                            break;
2307                        case Event::synth_param_cutoff_lfo_freq:
2308                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2309                            break;
2310                        case Event::synth_param_pitch_lfo_depth:
2311                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2312                            break;
2313                        case Event::synth_param_pitch_lfo_freq:
2314                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2315                            break;
2316                    }
2317    
2318                    // move note parameter event to its MIDI key
2319                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2320                    itEvent.moveToEndOf(pKey->pEvents);
2321              }              }
2322    
2323              /**              /**
2324               *  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
2325               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2326               */               */
2327              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2328                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2329    
2330                  // 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 2383  namespace LinuxSampler {
2383               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2384               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2385               */               */
2386              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2387                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2388                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2389                  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 2418  namespace LinuxSampler {
2418                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2419              ) = 0;              ) = 0;
2420    
2421              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2422    
2423              int InitNewVoice (              int InitNewVoice (
2424                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1920  namespace LinuxSampler { Line 2441  namespace LinuxSampler {
2441                      }                      }
2442                      else { // on success                      else { // on success
2443                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2444                          if (!pKey->Active) { // mark as active key  
2445                              pKey->Active = true;                          // should actually be superfluous now, since this is
2446                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2447                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2448                          }  
2449                          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)
2450                                pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2451                          return 0; // success                          return 0; // success
2452                      }                      }
2453                  }                  }

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

  ViewVC Help
Powered by ViewVC