/[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 3699 by schoenebeck, Sat Jan 4 14:07:02 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 96: { // data increment (data entry +1)
1751                            //dmsg(1,("DATA INC\n"));
1752                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1753                                pChannel->SetMidiRpnData(
1754                                    pChannel->GetMidiRpnData() + 1
1755                                );
1756                                bIsRpn = true;
1757    
1758                                int ch = itControlChangeEvent->Param.CC.Channel;
1759                                int param = pChannel->GetMidiRpnParameter();
1760                                int value = pChannel->GetMidiRpnData();
1761    
1762                                // transform event type: CC event -> RPN event
1763                                itControlChangeEvent->Type = Event::type_rpn;
1764                                itControlChangeEvent->Param.RPN.Channel = ch;
1765                                itControlChangeEvent->Param.RPN.Parameter = param;
1766                                itControlChangeEvent->Param.RPN.Value = value;
1767    
1768                                // if there's a RPN script handler, run it ...
1769                                if (pChannel->pScript->handlerRpn) {
1770                                    const event_id_t eventID =
1771                                        pEventPool->getID(itControlChangeEvent);
1772                                    // run the RPN script handler
1773                                    ProcessEventByScript(
1774                                        pChannel, itControlChangeEvent,
1775                                        pChannel->pScript->handlerRpn
1776                                    );
1777                                    // if RPN event was dropped by script, abort
1778                                    // here to avoid hard coded RPN processing below
1779                                    if (!pEventPool->fromID(eventID))
1780                                        break;
1781                                }
1782    
1783                                // do the actual (hard-coded) RPN value change processing
1784                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1785    
1786                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1787                                pChannel->SetMidiNrpnData(
1788                                    pChannel->GetMidiNrpnData() + 1
1789                                );
1790                                bIsNrpn = true;
1791    
1792                                int ch = itControlChangeEvent->Param.CC.Channel;
1793                                int param = pChannel->GetMidiNrpnParameter();
1794                                int value = pChannel->GetMidiNrpnData();
1795    
1796                                // transform event type: CC event -> NRPN event
1797                                itControlChangeEvent->Type = Event::type_nrpn;
1798                                itControlChangeEvent->Param.NRPN.Channel = ch;
1799                                itControlChangeEvent->Param.NRPN.Parameter = param;
1800                                itControlChangeEvent->Param.NRPN.Value = value;
1801    
1802                                // if there's a NRPN script handler, run it ...
1803                                if (pChannel->pScript->handlerNrpn) {
1804                                    const event_id_t eventID =
1805                                        pEventPool->getID(itControlChangeEvent);
1806                                    // run the NRPN script handler
1807                                    ProcessEventByScript(
1808                                        pChannel, itControlChangeEvent,
1809                                        pChannel->pScript->handlerNrpn
1810                                    );
1811                                    // if NRPN event was dropped by script, abort
1812                                    // here to avoid hard coded NRPN processing below
1813                                    if (!pEventPool->fromID(eventID))
1814                                        break;
1815                                }
1816    
1817                                // do the actual (hard-coded) NRPN value change processing
1818                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1819                            }
1820                            break;
1821                        }
1822                        case 97: { // data decrement (data entry -1)
1823                            //dmsg(1,("DATA DEC\n"));
1824                            if (pChannel->GetMidiRpnParameter() >= 0) { // RPN parameter number was sent previously ...
1825                                pChannel->SetMidiRpnData(
1826                                    pChannel->GetMidiRpnData() - 1
1827                                );
1828                                bIsRpn = true;
1829    
1830                                int ch = itControlChangeEvent->Param.CC.Channel;
1831                                int param = pChannel->GetMidiRpnParameter();
1832                                int value = pChannel->GetMidiRpnData();
1833    
1834                                // transform event type: CC event -> RPN event
1835                                itControlChangeEvent->Type = Event::type_rpn;
1836                                itControlChangeEvent->Param.RPN.Channel = ch;
1837                                itControlChangeEvent->Param.RPN.Parameter = param;
1838                                itControlChangeEvent->Param.RPN.Value = value;
1839    
1840                                // if there's a RPN script handler, run it ...
1841                                if (pChannel->pScript->handlerRpn) {
1842                                    const event_id_t eventID =
1843                                        pEventPool->getID(itControlChangeEvent);
1844                                    // run the RPN script handler
1845                                    ProcessEventByScript(
1846                                        pChannel, itControlChangeEvent,
1847                                        pChannel->pScript->handlerRpn
1848                                    );
1849                                    // if RPN event was dropped by script, abort
1850                                    // here to avoid hard coded RPN processing below
1851                                    if (!pEventPool->fromID(eventID))
1852                                        break;
1853                                }
1854    
1855                                // do the actual (hard-coded) RPN value change processing
1856                                ProcessHardcodedRpn(pEngineChannel, itControlChangeEvent);
1857    
1858                            } else if (pChannel->GetMidiNrpnParameter() >= 0) { // NRPN parameter number was sent previously ...
1859                                pChannel->SetMidiNrpnData(
1860                                    pChannel->GetMidiNrpnData() - 1
1861                                );
1862                                bIsNrpn = true;
1863    
1864                                int ch = itControlChangeEvent->Param.CC.Channel;
1865                                int param = pChannel->GetMidiNrpnParameter();
1866                                int value = pChannel->GetMidiNrpnData();
1867    
1868                                // transform event type: CC event -> NRPN event
1869                                itControlChangeEvent->Type = Event::type_nrpn;
1870                                itControlChangeEvent->Param.NRPN.Channel = ch;
1871                                itControlChangeEvent->Param.NRPN.Parameter = param;
1872                                itControlChangeEvent->Param.NRPN.Value = value;
1873    
1874                                // if there's a NRPN script handler, run it ...
1875                                if (pChannel->pScript->handlerNrpn) {
1876                                    const event_id_t eventID =
1877                                        pEventPool->getID(itControlChangeEvent);
1878                                    // run the NRPN script handler
1879                                    ProcessEventByScript(
1880                                        pChannel, itControlChangeEvent,
1881                                        pChannel->pScript->handlerNrpn
1882                                    );
1883                                    // if NRPN event was dropped by script, abort
1884                                    // here to avoid hard coded NRPN processing below
1885                                    if (!pEventPool->fromID(eventID))
1886                                        break;
1887                                }
1888    
1889                                // do the actual (hard-coded) NRPN value change processing
1890                                ProcessHardcodedNrpn(pEngineChannel, itControlChangeEvent);
1891                            }
1892                            break;
1893                        }
1894                        case 98: { // NRPN parameter LSB
1895                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1896                          pEngineChannel->SetMidiNrpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1897                            pEngineChannel->SetMidiNrpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1898                          break;                          break;
1899                      }                      }
1900                      case 99: { // NRPN controller MSB                      case 99: { // NRPN parameter MSB
1901                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("NRPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1902                          pEngineChannel->SetMidiNrpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsNrpn = true;
1903                            pEngineChannel->SetMidiNrpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1904                          break;                          break;
1905                      }                      }
1906                      case 100: { // RPN controller LSB                      case 100: { // RPN parameter LSB
1907                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN LSB %d\n", itControlChangeEvent->Param.CC.Value));
1908                          pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1909                            pEngineChannel->SetMidiRpnParameterLsb(itControlChangeEvent->Param.CC.Value);
1910                          break;                          break;
1911                      }                      }
1912                      case 101: { // RPN controller MSB                      case 101: { // RPN parameter MSB
1913                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));                          dmsg(4,("RPN MSB %d\n", itControlChangeEvent->Param.CC.Value));
1914                          pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);                          bIsRpn = true;
1915                            pEngineChannel->SetMidiRpnParameterMsb(itControlChangeEvent->Param.CC.Value);
1916                          break;                          break;
1917                      }                      }
1918    
# Line 1572  namespace LinuxSampler { Line 1946  namespace LinuxSampler {
1946                          break;                          break;
1947                      }                      }
1948                  }                  }
1949    
1950                    // reset cached RPN/NRPN parameter number and data in case this
1951                    // CC event had nothing to do with RPN/NRPN
1952                    if (!bIsRpn && pChannel->GetMidiRpnParameter() >= 0)
1953                        pChannel->ResetMidiRpnParameter();
1954                    if (!bIsNrpn && pChannel->GetMidiNrpnParameter() >= 0)
1955                        pChannel->ResetMidiNrpnParameter();
1956                }
1957    
1958                /**
1959                 * Process MIDI RPN events with hard coded behavior.
1960                 *
1961                 * @param pEngineChannel - engine channel on which the MIDI RPN
1962                 *                         event was received
1963                 * @param itRpnEvent - the actual MIDI RPN event
1964                 */
1965                void ProcessHardcodedRpn(EngineChannel* pEngineChannel,
1966                                         Pool<Event>::Iterator& itRpnEvent)
1967                {
1968                    EngineChannelBase<V, R, I>* pChannel =
1969                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1970    
1971                    if (itRpnEvent->Param.RPN.Parameter == 2) { // coarse tuning in half tones
1972                        int transpose = (int) itRpnEvent->Param.RPN.ValueMSB() - 64;
1973                        // limit to +- two octaves for now
1974                        transpose = RTMath::Min(transpose,  24);
1975                        transpose = RTMath::Max(transpose, -24);
1976                        pChannel->GlobalTranspose = transpose;
1977                        // workaround, so we won't have hanging notes
1978                        pChannel->ReleaseAllVoices(itRpnEvent);
1979                    }
1980                }
1981    
1982                /**
1983                 * Process MIDI NRPN events with hard coded behavior.
1984                 *
1985                 * @param pEngineChannel - engine channel on which the MIDI NRPN
1986                 *                         event was received
1987                 * @param itRpnEvent - the actual MIDI NRPN event
1988                 */
1989                void ProcessHardcodedNrpn(EngineChannel* pEngineChannel,
1990                                          Pool<Event>::Iterator& itNrpnEvent)
1991                {
1992                    EngineChannelBase<V, R, I>* pChannel =
1993                        static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1994    
1995                    switch (itNrpnEvent->Param.NRPN.ParameterMSB()) {
1996                        case 0x1a: { // volume level of note (Roland GS NRPN)
1997                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
1998                            const uint vol  = itNrpnEvent->Param.NRPN.ValueMSB();
1999                            dmsg(4,("Note Volume NRPN received (note=%d,vol=%d).\n", note, vol));
2000                            if (note < 128 && vol < 128)
2001                                pChannel->pMIDIKeyInfo[note].Volume = VolumeCurve[vol];
2002                            break;
2003                        }
2004                        case 0x1c: { // panpot of note (Roland GS NRPN)
2005                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2006                            const uint pan  = itNrpnEvent->Param.NRPN.ValueMSB();
2007                            dmsg(4,("Note Pan NRPN received (note=%d,pan=%d).\n", note, pan));
2008                            if (note < 128 && pan < 128) {
2009                                pChannel->pMIDIKeyInfo[note].PanLeft  = PanCurve[128 - pan];
2010                                pChannel->pMIDIKeyInfo[note].PanRight = PanCurve[pan];
2011                            }
2012                            break;
2013                        }
2014                        case 0x1d: { // reverb send of note (Roland GS NRPN)
2015                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2016                            const float reverb = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2017                            dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
2018                            if (note < 128)
2019                                pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
2020                            break;
2021                        }
2022                        case 0x1e: { // chorus send of note (Roland GS NRPN)
2023                            const uint note = itNrpnEvent->Param.NRPN.ParameterLSB();
2024                            const float chorus = float(itNrpnEvent->Param.NRPN.Value) / 16383.f;
2025                            dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
2026                            if (note < 128)
2027                                pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
2028                            break;
2029                        }
2030                    }
2031              }              }
2032    
2033              virtual D* CreateDiskThread() = 0;              virtual D* CreateDiskThread() = 0;
# Line 1582  namespace LinuxSampler { Line 2038  namespace LinuxSampler {
2038               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
2039               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
2040               */               */
2041              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
2042                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
2043                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2044    
# Line 1592  namespace LinuxSampler { Line 2048  namespace LinuxSampler {
2048    
2049                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
2050    
2051                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
2052                    // programmatically spawned notes (Event::type_play_note). We have
2053                    // to distinguish between them, since certain processing below
2054                    // must only be done on real MIDI note-on events (i.e. for
2055                    // correctly updating which MIDI keys are currently pressed down).
2056                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
2057    
2058                    if (isRealMIDINoteOnEvent)
2059                        pChannel->listeners.PreProcessNoteOn(key, vel);
2060    
2061                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2062                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2063                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
2064                            pChannel->listeners.PostProcessNoteOn(key, vel);
2065                      return;                      return;
2066                  }                  }
2067                  #endif                  #endif
2068    
2069                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
2070                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
2071                            pChannel->listeners.PostProcessNoteOn(key, vel);
2072                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
2073                  }                  }
2074    
# Line 1609  namespace LinuxSampler { Line 2076  namespace LinuxSampler {
2076                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
2077    
2078                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
2079                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
2080                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
2081                      if (itYoungestKey) {                      if (itYoungestKey) {
2082                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 2105  namespace LinuxSampler {
2105                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
2106                  }                  }
2107    
2108                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
2109                        pChannel->ProcessKeySwitchChange(key);
2110    
2111                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
2112                  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
2113                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
2114                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
2115                    }
2116    
2117                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
2118                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
2119                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
2120                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
2121                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
2122                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
2123                      }                      }
2124                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
2125                  }                  }
# Line 1661  namespace LinuxSampler { Line 2130  namespace LinuxSampler {
2130                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2131                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
2132    
2133                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
2134                        pChannel->PortamentoPos = (float) key;
2135    
2136                    //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?
2137                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
2138                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
2139                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
2140                  }                  }
2141                  pChannel->listeners.PostProcessNoteOn(key, vel);  
2142                    if (isRealMIDINoteOnEvent)
2143                        pChannel->listeners.PostProcessNoteOn(key, vel);
2144              }              }
2145    
2146              /**              /**
# Line 1695  namespace LinuxSampler { Line 2169  namespace LinuxSampler {
2169               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
2170               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
2171               */               */
2172              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
2173                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2174    
2175                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
# Line 1704  namespace LinuxSampler { Line 2178  namespace LinuxSampler {
2178    
2179                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2180    
2181                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
2182                    // programmatically spawned notes (Event::type_stop_note). We have
2183                    // to distinguish between them, since certain processing below
2184                    // must only be done on real MIDI note-off events (i.e. for
2185                    // correctly updating which MIDI keys are currently pressed down),
2186                    // plus a stop-note event just releases voices of one particular
2187                    // note, whereas a note-off event releases all voices on a
2188                    // particular MIDI key instead.
2189                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
2190    
2191                    if (isRealMIDINoteOffEvent)
2192                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
2193    
2194                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
2195                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
2196                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
2197                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
2198                      return;                      return;
2199                  }                  }
2200                  #endif                  #endif
2201    
2202                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
2203                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
2204                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
2205                    }
2206    
2207                  // move event to the key's own event list                  // move event to the key's own event list
2208                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
2209    
2210                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
2211                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
2212    
2213                  // 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)
2214                  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
2215                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
2216                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
2217                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
2218                          // 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
2219                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
2220                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
2221                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
2222                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
2223                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
2224                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
2225                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
2226                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
2227                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
2228                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
2229                                      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);  
2230                                      }                                      }
2231                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
2232                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
2233                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
2234                                            // copy event
2235                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
2236                                            // transform event to a note on event
2237                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
2238                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
2239                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
2240                                            // assign a new note to this note-on event
2241                                            if (LaunchNewNote(pChannel, itPseudoNoteOnEvent)) {
2242                                                // allocate and trigger new voice(s) for the other key
2243                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
2244                                            }
2245                                            // if neither a voice was spawned or postponed then remove note on event from key again
2246                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
2247                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
2248    
2249                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
2250                                  break; // done                                      break; // done
2251                                    }
2252                              }                              }
2253                          }                          }
2254                      }                          if (bOtherKeysPressed) {
2255                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
2256                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
2257                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
2258                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
2259                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
2260                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
2261                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
2262                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
2263                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
2264                                  }                                  }
2265                              }                              }
2266                          }                          } else pChannel->PortamentoPos = -1.0f;
2267                      } 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  
2268    
2269                      // 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
2270                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
2271                          // assign a new note to this release event                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
2272                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                          // spawn release triggered voice(s) if needed
2273                              // allocate and trigger new release voice(s)                          if (pKey->ReleaseTrigger & release_trigger_noteoff)
2274                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                              ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
2275                          }                      }
2276                          pKey->ReleaseTrigger = false;                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
2277                        // This programmatically caused event is caused by a call to
2278                        // the built-in instrument script function note_off(). In
2279                        // contrast to a real MIDI note-off event the stop-note
2280                        // event just intends to release voices of one particular note.
2281                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
2282                        if (pNote) { // the requested note is still alive ...
2283                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
2284                        } else { // note is dead and gone ..
2285                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
2286                            return; // prevent event to be removed a 2nd time below
2287                      }                      }
2288                  }                  }
2289    
# Line 1796  namespace LinuxSampler { Line 2291  namespace LinuxSampler {
2291                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
2292                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
2293    
2294                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
2295                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
2296                }
2297    
2298                /**
2299                 * Called on sustain pedal up events to check and if required,
2300                 * launch release trigger voices on the respective active key.
2301                 *
2302                 * @param pEngineChannel - engine channel on which this event occurred on
2303                 * @param itEvent - release trigger event (contains note number)
2304                 */
2305                virtual void ProcessReleaseTriggerBySustain(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
2306                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2307    
2308                    const int iKey = itEvent->Param.Note.Key;
2309                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
2310    
2311                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
2312    
2313                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
2314                }
2315    
2316                /**
2317                 * Called on note-off and sustain pedal up events to check and if
2318                 * required, launch release trigger voices on the respective active
2319                 * key.
2320                 *
2321                 * @param pEngineChannel - engine channel on which this event occurred on
2322                 * @param itEvent - note off event / release trigger event
2323                 * @param pKey - key on which the release trigger voices shall be spawned
2324                 */
2325                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
2326                    // spawn release triggered voice(s) if needed
2327                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
2328                        // assign a new note to this release event
2329                        if (LaunchNewNote(pChannel, itEvent)) {
2330                            // allocate and trigger new release voice(s)
2331                            TriggerReleaseVoices(pChannel, itEvent);
2332                        }
2333                        pKey->ReleaseTrigger = release_trigger_none;
2334                    }
2335                }
2336    
2337                /**
2338                 * Called on "kill note" events, which currently only happens on
2339                 * built-in real-time instrument script function fade_out(). This
2340                 * method only fulfills one task: moving the even to the Note's own
2341                 * event list so that its voices can process the kill event sample
2342                 * accurately.
2343                 */
2344                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2345                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2346    
2347                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
2348                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2349    
2350                    // move note kill event to its MIDI key
2351                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2352                    itEvent.moveToEndOf(pKey->pEvents);
2353                }
2354    
2355                /**
2356                 * Called on note synthesis parameter change events. These are
2357                 * internal events caused by calling built-in real-time instrument
2358                 * script functions like change_vol(), change_tune(), etc.
2359                 *
2360                 * This method performs two tasks:
2361                 *
2362                 * - It converts the event's relative values changes (Deltas) to
2363                 *   the respective final new synthesis parameter value (AbsValue),
2364                 *   for that particular moment of the event that is.
2365                 *
2366                 * - It moves the individual events to the Note's own event list
2367                 *   (or actually to the event list of the MIDI key), so that
2368                 *   voices can process those events sample accurately.
2369                 *
2370                 * @param pEngineChannel - engine channel on which this event occurred on
2371                 * @param itEvent - note synthesis parameter change event
2372                 */
2373                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
2374                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2375    
2376                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
2377                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
2378    
2379                    switch (itEvent->Param.NoteSynthParam.Type) {
2380                        case Event::synth_param_volume:
2381                            pNote->apply(itEvent, &NoteBase::_Override::Volume);
2382                            break;
2383                        case Event::synth_param_volume_time:
2384                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2385                            break;
2386                        case Event::synth_param_volume_curve:
2387                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2388                            pNote->Override.VolumeCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2389                            break;
2390                        case Event::synth_param_pitch:
2391                            pNote->apply(itEvent, &NoteBase::_Override::Pitch);
2392                            break;
2393                        case Event::synth_param_pitch_time:
2394                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2395                            break;
2396                        case Event::synth_param_pitch_curve:
2397                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2398                            pNote->Override.PitchCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2399                            break;
2400                        case Event::synth_param_pan:
2401                            pNote->apply(itEvent, &NoteBase::_Override::Pan);
2402                            break;
2403                        case Event::synth_param_pan_time:
2404                            pNote->Override.PanTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2405                            break;
2406                        case Event::synth_param_pan_curve:
2407                            itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2408                            pNote->Override.PanCurve = (fade_curve_t) itEvent->Param.NoteSynthParam.AbsValue;
2409                            break;
2410                        case Event::synth_param_cutoff:
2411                            pNote->apply(itEvent, &NoteBase::_Override::Cutoff);
2412                            break;
2413                        case Event::synth_param_resonance:
2414                            pNote->apply(itEvent, &NoteBase::_Override::Resonance);
2415                            break;
2416                        case Event::synth_param_attack:
2417                            pNote->apply(itEvent, &NoteBase::_Override::Attack);
2418                            break;
2419                        case Event::synth_param_decay:
2420                            pNote->apply(itEvent, &NoteBase::_Override::Decay);
2421                            break;
2422                        case Event::synth_param_sustain:
2423                            pNote->apply(itEvent, &NoteBase::_Override::Sustain);
2424                            break;
2425                        case Event::synth_param_release:
2426                            pNote->apply(itEvent, &NoteBase::_Override::Release);
2427                            break;
2428    
2429                        case Event::synth_param_cutoff_attack:
2430                            pNote->apply(itEvent, &NoteBase::_Override::CutoffAttack);
2431                            break;
2432                        case Event::synth_param_cutoff_decay:
2433                            pNote->apply(itEvent, &NoteBase::_Override::CutoffDecay);
2434                            break;
2435                        case Event::synth_param_cutoff_sustain:
2436                            pNote->apply(itEvent, &NoteBase::_Override::CutoffSustain);
2437                            break;
2438                        case Event::synth_param_cutoff_release:
2439                            pNote->apply(itEvent, &NoteBase::_Override::CutoffRelease);
2440                            break;
2441    
2442                        case Event::synth_param_amp_lfo_depth:
2443                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFODepth);
2444                            break;
2445                        case Event::synth_param_amp_lfo_freq:
2446                            pNote->apply(itEvent, &NoteBase::_Override::AmpLFOFreq);
2447                            break;
2448                        case Event::synth_param_cutoff_lfo_depth:
2449                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFODepth);
2450                            break;
2451                        case Event::synth_param_cutoff_lfo_freq:
2452                            pNote->apply(itEvent, &NoteBase::_Override::CutoffLFOFreq);
2453                            break;
2454                        case Event::synth_param_pitch_lfo_depth:
2455                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFODepth);
2456                            break;
2457                        case Event::synth_param_pitch_lfo_freq:
2458                            pNote->apply(itEvent, &NoteBase::_Override::PitchLFOFreq);
2459                            break;
2460                    }
2461    
2462                    // move note parameter event to its MIDI key
2463                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2464                    itEvent.moveToEndOf(pKey->pEvents);
2465              }              }
2466    
2467              /**              /**
2468               *  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
2469               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2470               */               */
2471              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2472                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2473    
2474                  // 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 2527  namespace LinuxSampler {
2527               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2528               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2529               */               */
2530              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2531                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2532                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2533                  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 2562  namespace LinuxSampler {
2562                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2563              ) = 0;              ) = 0;
2564    
2565              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2566    
2567              int InitNewVoice (              int InitNewVoice (
2568                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,
# Line 1920  namespace LinuxSampler { Line 2585  namespace LinuxSampler {
2585                      }                      }
2586                      else { // on success                      else { // on success
2587                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
2588                          if (!pKey->Active) { // mark as active key  
2589                              pKey->Active = true;                          // should actually be superfluous now, since this is
2590                              pKey->itSelf = pChannel->pActiveKeys->allocAppend();                          // already done in LaunchNewNote()
2591                              *pKey->itSelf = itNoteOnEvent->Param.Note.Key;                          pChannel->markKeyAsActive(pKey);
2592                          }  
2593                          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)
2594                                pKey->ReleaseTrigger |= itNewVoice->GetReleaseTriggerFlags(); // mark key for the need of release triggered voice(s)
2595                          return 0; // success                          return 0; // success
2596                      }                      }
2597                  }                  }

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

  ViewVC Help
Powered by ViewVC