/[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 3188 by schoenebeck, Fri May 19 14:23:12 2017 UTC
# Line 5  Line 5 
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *   *   Copyright (C) 2012-2017 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 58  namespace LinuxSampler { Line 58  namespace LinuxSampler {
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128), noteIDPool(GLOBAL_MAX_NOTES) {              EngineBase() : noteIDPool(GLOBAL_MAX_NOTES), SuspendedRegions(128) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                  pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);                  pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                  pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);                  pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
# Line 163  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163                                  dmsg(5,("Engine: Sysex received\n"));                                  dmsg(5,("Engine: Sysex received\n"));
164                                  ProcessSysex(itEvent);                                  ProcessSysex(itEvent);
165                                  break;                                  break;
166                                default: ; // noop
167                          }                          }
168                      }                      }
169                  }                  }
# Line 596  namespace LinuxSampler { Line 597  namespace LinuxSampler {
597              }              }
598    
599              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'              // implementation of abstract method derived from class 'LinuxSampler::RegionPools'
600              virtual Pool<R*>* GetRegionPool(int index) {              virtual Pool<R*>* GetRegionPool(int index) OVERRIDE {
601                  if (index < 0 || index > 1) throw Exception("Index out of bounds");                  if (index < 0 || index > 1) throw Exception("Index out of bounds");
602                  return pRegionPool[index];                  return pRegionPool[index];
603              }              }
# Line 604  namespace LinuxSampler { Line 605  namespace LinuxSampler {
605              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
606              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
607              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }              virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
608              virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }              virtual Pool<note_id_t>* GetNoteIDPool() OVERRIDE { return &noteIDPool; }
609    
610              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
611    
# Line 689  namespace LinuxSampler { Line 690  namespace LinuxSampler {
690                  NoteIterator itNewNote = pNotePool->allocAppend();                  NoteIterator itNewNote = pNotePool->allocAppend();
691                  const note_id_t newNoteID = pNotePool->getID(itNewNote);                  const note_id_t newNoteID = pNotePool->getID(itNewNote);
692    
693                    // remember the engine's time when this note was triggered exactly
694                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
695    
696                  // usually the new note (and its subsequent voices) will be                  // usually the new note (and its subsequent voices) will be
697                  // allocated on the key provided by the event's note number,                  // allocated on the key provided by the event's note number,
698                  // however if this new note is requested not to be a regular                  // however if this new note is requested not to be a regular
# Line 771  namespace LinuxSampler { Line 775  namespace LinuxSampler {
775                      //                      //
776                      // 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
777                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
778                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
779                      {                      {
780                            //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).
781                            RTList<Event>::Iterator itNext = itEvent;
782                            ++itNext;
783    
784                          switch (itEvent->Type) {                          switch (itEvent->Type) {
785                              case Event::type_note_on:                              case Event::type_note_on:
786                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 791  namespace LinuxSampler { Line 799  namespace LinuxSampler {
799                              case Event::type_note_pressure:                              case Event::type_note_pressure:
800                                  //TODO: ...                                  //TODO: ...
801                                  break;                                  break;
802    
803                                case Event::type_sysex:
804                                    //TODO: ...
805                                    break;
806    
807                                case Event::type_cancel_release_key:
808                                case Event::type_release_key:
809                                case Event::type_release_note:
810                                case Event::type_play_note:
811                                case Event::type_stop_note:
812                                case Event::type_kill_note:
813                                case Event::type_note_synth_param:
814                                    break; // noop
815                          }                          }
816    
817                            // see HACK comment above
818                            itEvent = itNext;
819                      }                      }
820    
821                      // this has to be run again, since the newly spawned scripts                      // this has to be run again, since the newly spawned scripts
# Line 846  namespace LinuxSampler { Line 870  namespace LinuxSampler {
870                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
871                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
872                                  break;                                  break;
873                                case Event::type_play_note:
874                                    dmsg(5,("Engine: Play Note received\n"));
875                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
876                                    break;
877                              case Event::type_note_off:                              case Event::type_note_off:
878                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
879                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
880                                  break;                                  break;
881                                case Event::type_stop_note:
882                                    dmsg(5,("Engine: Stop Note received\n"));
883                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
884                                    break;
885                                case Event::type_kill_note:
886                                    dmsg(5,("Engine: Kill Note received\n"));
887                                    ProcessKillNote((EngineChannel*)itEvent->pEngineChannel, itEvent);
888                                    break;
889                              case Event::type_control_change:                              case Event::type_control_change:
890                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
891                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 866  namespace LinuxSampler { Line 902  namespace LinuxSampler {
902                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
903                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
904                                  break;                                  break;
905                                case Event::type_note_synth_param:
906                                    dmsg(5,("Engine: Note Synth Param received\n"));
907                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
908                                    break;
909                                case Event::type_sysex:
910                                    break; // TODO ...
911    
912                                case Event::type_cancel_release_key:
913                                case Event::type_release_key:
914                                case Event::type_release_note:
915                                    break; // noop
916                          }                          }
917                      }                      }
918                  }                  }
# Line 968  namespace LinuxSampler { Line 1015  namespace LinuxSampler {
1015                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
1016                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
1017                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
1018                    itScriptEvent->ignoreAllWaitCalls = false;
1019                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
1020                  // this is the native representation of the $EVENT_ID script variable                  // this is the native representation of the $EVENT_ID script variable
1021                  itScriptEvent->id =                  itScriptEvent->id =
1022                      (itEvent->Type == Event::type_note_on)                      (itEvent->Type == Event::type_note_on)
# Line 1235  namespace LinuxSampler { Line 1284  namespace LinuxSampler {
1284                          // the script's "init" event handler is only executed                          // the script's "init" event handler is only executed
1285                          // once (when the script is loaded or reloaded)                          // once (when the script is loaded or reloaded)
1286                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {                          if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1287                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1288                              RTList<ScriptEvent>::Iterator itScriptEvent =                              RTList<ScriptEvent>::Iterator itScriptEvent =
1289                                  pEngineChannel->pScript->pEvents->allocAppend();                                  pEngineChannel->pScript->pEvents->allocAppend();
1290    
1291                              itScriptEvent->cause.pEngineChannel = pEngineChannel;                              itScriptEvent->cause.pEngineChannel = pEngineChannel;
1292                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;                              itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1293                              itScriptEvent->handlers[1] = NULL;                              itScriptEvent->handlers[1] = NULL;
1294                                itScriptEvent->currentHandler = 0;
1295                                itScriptEvent->executionSlices = 0;
1296                                itScriptEvent->ignoreAllWaitCalls = false;
1297                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1298    
1299                              VMExecStatus_t res = pScriptVM->exec(                              /*VMExecStatus_t res = */ pScriptVM->exec(
1300                                  pEngineChannel->pScript->parserContext, &*itScriptEvent                                  pEngineChannel->pScript->parserContext, &*itScriptEvent
1301                              );                              );
1302    
# Line 1582  namespace LinuxSampler { Line 1636  namespace LinuxSampler {
1636               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1637               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1638               */               */
1639              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) OVERRIDE {
1640                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1641                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1642    
# Line 1592  namespace LinuxSampler { Line 1646  namespace LinuxSampler {
1646    
1647                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1648    
1649                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1650                    // programmatically spawned notes (Event::type_play_note). We have
1651                    // to distinguish between them, since certain processing below
1652                    // must only be done on real MIDI note-on events (i.e. for
1653                    // correctly updating which MIDI keys are currently pressed down).
1654                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1655    
1656                    if (isRealMIDINoteOnEvent)
1657                        pChannel->listeners.PreProcessNoteOn(key, vel);
1658    
1659                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1660                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1661                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1662                            pChannel->listeners.PostProcessNoteOn(key, vel);
1663                      return;                      return;
1664                  }                  }
1665                  #endif                  #endif
1666    
1667                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1668                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1669                            pChannel->listeners.PostProcessNoteOn(key, vel);
1670                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1671                  }                  }
1672    
# Line 1609  namespace LinuxSampler { Line 1674  namespace LinuxSampler {
1674                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1675    
1676                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1677                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1678                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1679                      if (itYoungestKey) {                      if (itYoungestKey) {
1680                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 1703  namespace LinuxSampler {
1703                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1704                  }                  }
1705    
1706                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1707                        pChannel->ProcessKeySwitchChange(key);
1708    
1709                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1710                  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
1711                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1712                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1713                    }
1714    
1715                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1716                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1717                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1718                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1719                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1720                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1721                      }                      }
1722                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1723                  }                  }
# Line 1661  namespace LinuxSampler { Line 1728  namespace LinuxSampler {
1728                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1729                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1730    
1731                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1732                        pChannel->PortamentoPos = (float) key;
1733    
1734                    //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?
1735                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1736                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1737                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1738                  }                  }
1739                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1740                    if (isRealMIDINoteOnEvent)
1741                        pChannel->listeners.PostProcessNoteOn(key, vel);
1742              }              }
1743    
1744              /**              /**
# Line 1695  namespace LinuxSampler { Line 1767  namespace LinuxSampler {
1767               *  @param pEngineChannel - engine channel on which this event occurred on               *  @param pEngineChannel - engine channel on which this event occurred on
1768               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1769               */               */
1770              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) OVERRIDE {
1771                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1772    
1773                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
# Line 1704  namespace LinuxSampler { Line 1776  namespace LinuxSampler {
1776    
1777                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1778    
1779                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1780                    // programmatically spawned notes (Event::type_stop_note). We have
1781                    // to distinguish between them, since certain processing below
1782                    // must only be done on real MIDI note-off events (i.e. for
1783                    // correctly updating which MIDI keys are currently pressed down),
1784                    // plus a stop-note event just releases voices of one particular
1785                    // note, whereas a note-off event releases all voices on a
1786                    // particular MIDI key instead.
1787                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1788    
1789                    if (isRealMIDINoteOffEvent)
1790                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1791    
1792                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1793                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1794                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1795                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1796                      return;                      return;
1797                  }                  }
1798                  #endif                  #endif
1799    
1800                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1801                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1802                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1803                    }
1804    
1805                  // move event to the key's own event list                  // move event to the key's own event list
1806                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1807    
1808                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1809                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1810    
1811                  // 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)
1812                  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
1813                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1814                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1815                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1816                          // 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
1817                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1818                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1819                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1820                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1821                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1822                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1823                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1824                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1825                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1826                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1827                                      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);  
1828                                      }                                      }
1829                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
1830                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1831                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
1832                                            // copy event
1833                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1834                                            // transform event to a note on event
1835                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1836                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
1837                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1838                                            // assign a new note to this note-on event
1839                                            if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1840                                                // allocate and trigger new voice(s) for the other key
1841                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1842                                            }
1843                                            // if neither a voice was spawned or postponed then remove note on event from key again
1844                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1845                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1846    
1847                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1848                                  break; // done                                      break; // done
1849                                    }
1850                              }                              }
1851                          }                          }
1852                      }                          if (bOtherKeysPressed) {
1853                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1854                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1855                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1856                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1857                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1858                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1859                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1860                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1861                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
1862                                  }                                  }
1863                              }                              }
1864                          }                          } else pChannel->PortamentoPos = -1.0f;
1865                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
1866    
1867                  // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed                      // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1868                  if (bShouldRelease) {                      if (bShouldRelease) {
1869                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1870                            // spawn release triggered voice(s) if needed
1871                      // spawn release triggered voice(s) if needed                          ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1872                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      }
1873                          // assign a new note to this release event                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1874                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                      // This programmatically caused event is caused by a call to
1875                              // allocate and trigger new release voice(s)                      // the built-in instrument script function note_off(). In
1876                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                      // contrast to a real MIDI note-off event the stop-note
1877                          }                      // event just intends to release voices of one particular note.
1878                          pKey->ReleaseTrigger = false;                      NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1879                        if (pNote) { // the requested note is still alive ...
1880                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1881                        } else { // note is dead and gone ..
1882                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1883                            return; // prevent event to be removed a 2nd time below
1884                      }                      }
1885                  }                  }
1886    
# Line 1796  namespace LinuxSampler { Line 1888  namespace LinuxSampler {
1888                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1889                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1890    
1891                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1892                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1893                }
1894    
1895                /**
1896                 * Called on sustain pedal up events to check and if required,
1897                 * launch release trigger voices on the respective active key.
1898                 *
1899                 * @param pEngineChannel - engine channel on which this event occurred on
1900                 * @param itEvent - release trigger event (contains note number)
1901                 */
1902                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1903                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1904    
1905                    const int iKey = itEvent->Param.Note.Key;
1906                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1907    
1908                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1909    
1910                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1911                }
1912    
1913                /**
1914                 * Called on note-off and sustain pedal up events to check and if
1915                 * required, launch release trigger voices on the respective active
1916                 * key.
1917                 *
1918                 * @param pEngineChannel - engine channel on which this event occurred on
1919                 * @param itEvent - note off event / release trigger event
1920                 * @param pKey - key on which the release trigger voices shall be spawned
1921                 */
1922                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1923                    // spawn release triggered voice(s) if needed
1924                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1925                        // assign a new note to this release event
1926                        if (LaunchNewNote(pChannel, &*itEvent)) {
1927                            // allocate and trigger new release voice(s)
1928                            TriggerReleaseVoices(pChannel, itEvent);
1929                        }
1930                        pKey->ReleaseTrigger = false;
1931                    }
1932                }
1933    
1934                /**
1935                 * Called on "kill note" events, which currently only happens on
1936                 * built-in real-time instrument script function fade_out(). This
1937                 * method only fulfills one task: moving the even to the Note's own
1938                 * event list so that its voices can process the kill event sample
1939                 * accurately.
1940                 */
1941                void ProcessKillNote(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1942                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1943    
1944                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.Note.ID );
1945                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1946    
1947                    // move note kill event to its MIDI key
1948                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1949                    itEvent.moveToEndOf(pKey->pEvents);
1950                }
1951    
1952                /**
1953                 * Called on note synthesis parameter change events. These are
1954                 * internal events caused by calling built-in real-time instrument
1955                 * script functions like change_vol(), change_tune(), etc.
1956                 *
1957                 * This method performs two tasks:
1958                 *
1959                 * - It converts the event's relative values changes (Deltas) to
1960                 *   the respective final new synthesis parameter value (AbsValue),
1961                 *   for that particular moment of the event that is.
1962                 *
1963                 * - It moves the individual events to the Note's own event list
1964                 *   (or actually to the event list of the MIDI key), so that
1965                 *   voices can process those events sample accurately.
1966                 *
1967                 * @param pEngineChannel - engine channel on which this event occurred on
1968                 * @param itEvent - note synthesis parameter change event
1969                 */
1970                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1971                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1972    
1973                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1974                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1975    
1976                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1977    
1978                    switch (itEvent->Param.NoteSynthParam.Type) {
1979                        case Event::synth_param_volume:
1980                            if (relative)
1981                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1982                            else
1983                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1984                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1985                            break;
1986                        case Event::synth_param_volume_time:
1987                            pNote->Override.VolumeTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1988                            break;
1989                        case Event::synth_param_pitch:
1990                            if (relative)
1991                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1992                            else
1993                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1994                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1995                            break;
1996                        case Event::synth_param_pitch_time:
1997                            pNote->Override.PitchTime = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1998                            break;
1999                        case Event::synth_param_pan:
2000                            if (relative) {
2001                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
2002                            } else {
2003                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
2004                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
2005                            }
2006                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
2007                            break;
2008                        case Event::synth_param_cutoff:
2009                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2010                            break;
2011                        case Event::synth_param_resonance:
2012                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2013                            break;
2014                        case Event::synth_param_attack:
2015                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2016                            break;
2017                        case Event::synth_param_decay:
2018                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2019                            break;
2020                        case Event::synth_param_release:
2021                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2022                            break;
2023                        case Event::synth_param_amp_lfo_depth:
2024                            pNote->Override.AmpLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2025                            break;
2026                        case Event::synth_param_amp_lfo_freq:
2027                            pNote->Override.AmpLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2028                            break;
2029                        case Event::synth_param_pitch_lfo_depth:
2030                            pNote->Override.PitchLFODepth = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2031                            break;
2032                        case Event::synth_param_pitch_lfo_freq:
2033                            pNote->Override.PitchLFOFreq = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
2034                            break;
2035                    }
2036    
2037                    // move note parameter event to its MIDI key
2038                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
2039                    itEvent.moveToEndOf(pKey->pEvents);
2040              }              }
2041    
2042              /**              /**
2043               *  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
2044               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
2045               */               */
2046              virtual void ResetInternal() {              virtual void ResetInternal() OVERRIDE {
2047                  LockGuard lock(ResetInternalMutex);                  LockGuard lock(ResetInternalMutex);
2048    
2049                  // 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 2102  namespace LinuxSampler {
2102               * @param pEngineChannel - engine channel on which all voices should be killed               * @param pEngineChannel - engine channel on which all voices should be killed
2103               * @param itKillEvent    - event which caused this killing of all voices               * @param itKillEvent    - event which caused this killing of all voices
2104               */               */
2105              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) {              virtual void KillAllVoices(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itKillEvent) OVERRIDE {
2106                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
2107                  int count = pChannel->KillAllVoices(itKillEvent);                  int count = pChannel->KillAllVoices(itKillEvent);
2108                  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 2137  namespace LinuxSampler {
2137                  bool                    HandleKeyGroupConflicts                  bool                    HandleKeyGroupConflicts
2138              ) = 0;              ) = 0;
2139    
2140              virtual int GetMinFadeOutSamples() { return MinFadeOutSamples; }              virtual int GetMinFadeOutSamples() OVERRIDE { return MinFadeOutSamples; }
2141    
2142              int InitNewVoice (              int InitNewVoice (
2143                  EngineChannelBase<V, R, I>*  pChannel,                  EngineChannelBase<V, R, I>*  pChannel,

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

  ViewVC Help
Powered by ViewVC