/[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 2962 by schoenebeck, Sun Jul 17 17:54:04 2016 UTC
# Line 689  namespace LinuxSampler { Line 689  namespace LinuxSampler {
689                  NoteIterator itNewNote = pNotePool->allocAppend();                  NoteIterator itNewNote = pNotePool->allocAppend();
690                  const note_id_t newNoteID = pNotePool->getID(itNewNote);                  const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
694    
695                  // usually the new note (and its subsequent voices) will be                  // usually the new note (and its subsequent voices) will be
696                  // allocated on the key provided by the event's note number,                  // allocated on the key provided by the event's note number,
697                  // however if this new note is requested not to be a regular                  // however if this new note is requested not to be a regular
# Line 771  namespace LinuxSampler { Line 774  namespace LinuxSampler {
774                      //                      //
775                      // 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
776                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
777                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
778                      {                      {
779                            //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).
780                            RTList<Event>::Iterator itNext = itEvent;
781                            ++itNext;
782    
783                          switch (itEvent->Type) {                          switch (itEvent->Type) {
784                              case Event::type_note_on:                              case Event::type_note_on:
785                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 792  namespace LinuxSampler { Line 799  namespace LinuxSampler {
799                                  //TODO: ...                                  //TODO: ...
800                                  break;                                  break;
801                          }                          }
802    
803                            // see HACK comment above
804                            itEvent = itNext;
805                      }                      }
806    
807                      // 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 856  namespace LinuxSampler {
856                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
857                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
858                                  break;                                  break;
859                                case Event::type_play_note:
860                                    dmsg(5,("Engine: Play Note received\n"));
861                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
862                                    break;
863                              case Event::type_note_off:                              case Event::type_note_off:
864                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
865                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
866                                  break;                                  break;
867                                case Event::type_stop_note:
868                                    dmsg(5,("Engine: Stop Note received\n"));
869                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
870                                    break;
871                              case Event::type_control_change:                              case Event::type_control_change:
872                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
873                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 866  namespace LinuxSampler { Line 884  namespace LinuxSampler {
884                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
885                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
886                                  break;                                  break;
887                                case Event::type_note_synth_param:
888                                    dmsg(5,("Engine: Note Synth Param received\n"));
889                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
890                                    break;
891                          }                          }
892                      }                      }
893                  }                  }
# Line 968  namespace LinuxSampler { Line 990  namespace LinuxSampler {
990                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
991                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
992                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
993                    itScriptEvent->ignoreAllWaitCalls = false;
994                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
995                  // this is the native representation of the $EVENT_ID script variable                  // this is the native representation of the $EVENT_ID script variable
996                  itScriptEvent->id =                  itScriptEvent->id =
997                      (itEvent->Type == Event::type_note_on)                      (itEvent->Type == Event::type_note_on)
# Line 1592  namespace LinuxSampler { Line 1616  namespace LinuxSampler {
1616    
1617                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1618    
1619                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1620                    // programmatically spawned notes (Event::type_play_note). We have
1621                    // to distinguish between them, since certain processing below
1622                    // must only be done on real MIDI note-on events (i.e. for
1623                    // correctly updating which MIDI keys are currently pressed down).
1624                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1625    
1626                    if (isRealMIDINoteOnEvent)
1627                        pChannel->listeners.PreProcessNoteOn(key, vel);
1628    
1629                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1630                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1631                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1632                            pChannel->listeners.PostProcessNoteOn(key, vel);
1633                      return;                      return;
1634                  }                  }
1635                  #endif                  #endif
1636    
1637                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1638                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1639                            pChannel->listeners.PostProcessNoteOn(key, vel);
1640                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1641                  }                  }
1642    
# Line 1609  namespace LinuxSampler { Line 1644  namespace LinuxSampler {
1644                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1645    
1646                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1647                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1648                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1649                      if (itYoungestKey) {                      if (itYoungestKey) {
1650                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1638  namespace LinuxSampler { Line 1673  namespace LinuxSampler {
1673                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1674                  }                  }
1675    
1676                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1677                        pChannel->ProcessKeySwitchChange(key);
1678    
1679                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1680                  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
1681                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1682                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1683                    }
1684    
1685                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1686                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1687                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1688                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1689                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1690                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1691                      }                      }
1692                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1693                  }                  }
# Line 1661  namespace LinuxSampler { Line 1698  namespace LinuxSampler {
1698                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1699                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1700    
1701                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1702                        pChannel->PortamentoPos = (float) key;
1703    
1704                    //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?
1705                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1706                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1707                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1708                  }                  }
1709                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1710                    if (isRealMIDINoteOnEvent)
1711                        pChannel->listeners.PostProcessNoteOn(key, vel);
1712              }              }
1713    
1714              /**              /**
# Line 1704  namespace LinuxSampler { Line 1746  namespace LinuxSampler {
1746    
1747                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1748    
1749                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1750                    // programmatically spawned notes (Event::type_stop_note). We have
1751                    // to distinguish between them, since certain processing below
1752                    // must only be done on real MIDI note-off events (i.e. for
1753                    // correctly updating which MIDI keys are currently pressed down),
1754                    // plus a stop-note event just releases voices of one particular
1755                    // note, whereas a note-off event releases all voices on a
1756                    // particular MIDI key instead.
1757                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1758    
1759                    if (isRealMIDINoteOffEvent)
1760                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1761    
1762                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1763                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1764                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1765                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1766                      return;                      return;
1767                  }                  }
1768                  #endif                  #endif
1769    
1770                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1771                  pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable                      pKey->KeyPressed = false; // the MIDI key was now released
1772                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1773                    }
1774    
1775                  // move event to the key's own event list                  // move event to the key's own event list
1776                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1777    
1778                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1779                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1780    
1781                  // 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)
1782                  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
1783                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1784                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1785                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1786                          // 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
1787                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1788                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1789                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1790                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1791                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1792                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1793                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1794                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1795                                      NoteIterator itNote = pKey->pActiveNotes->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1796                                      VoiceIterator itVoice = itNote->pActiveVoices->first();                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1797                                      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);  
1798                                      }                                      }
1799                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // create a pseudo note on event
1800                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1801                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                      if (itPseudoNoteOnEvent) {
1802                                            // copy event
1803                                            *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1804                                            // transform event to a note on event
1805                                            itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1806                                            itPseudoNoteOnEvent->Param.Note.Key      = i;
1807                                            itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1808                                            // assign a new note to this note-on event
1809                                            if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1810                                                // allocate and trigger new voice(s) for the other key
1811                                                TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1812                                            }
1813                                            // if neither a voice was spawned or postponed then remove note on event from key again
1814                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1815                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1816    
1817                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1818                                  break; // done                                      break; // done
1819                                    }
1820                              }                              }
1821                          }                          }
1822                      }                          if (bOtherKeysPressed) {
1823                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1824                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1825                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1826                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1827                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1828                                  VoiceIterator end               = itNote->pActiveVoices->end();                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1829                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1830                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1831                                          itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      }
1832                                  }                                  }
1833                              }                              }
1834                          }                          } else pChannel->PortamentoPos = -1.0f;
1835                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
1836    
1837                  // 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
1838                  if (bShouldRelease) {                      if (bShouldRelease) {
1839                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1840                            // spawn release triggered voice(s) if needed
1841                      // spawn release triggered voice(s) if needed                          ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1842                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      }
1843                          // assign a new note to this release event                  } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1844                          if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {                      // This programmatically caused event is caused by a call to
1845                              // allocate and trigger new release voice(s)                      // the built-in instrument script function note_off(). In
1846                              TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                      // contrast to a real MIDI note-off event the stop-note
1847                          }                      // event just intends to release voices of one particular note.
1848                          pKey->ReleaseTrigger = false;                      NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1849                        if (pNote) { // the requested note is still alive ...
1850                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1851                        } else { // note is dead and gone ..
1852                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1853                            return; // prevent event to be removed a 2nd time below
1854                      }                      }
1855                  }                  }
1856    
# Line 1796  namespace LinuxSampler { Line 1858  namespace LinuxSampler {
1858                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1859                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1860    
1861                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1862                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1863                }
1864    
1865                /**
1866                 * Called on sustain pedal up events to check and if required,
1867                 * launch release trigger voices on the respective active key.
1868                 *
1869                 * @param pEngineChannel - engine channel on which this event occurred on
1870                 * @param itEvent - release trigger event (contains note number)
1871                 */
1872                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1873                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1874    
1875                    const int iKey = itEvent->Param.Note.Key;
1876                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1877    
1878                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1879    
1880                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1881                }
1882    
1883                /**
1884                 * Called on note-off and sustain pedal up events to check and if
1885                 * required, launch release trigger voices on the respective active
1886                 * key.
1887                 *
1888                 * @param pEngineChannel - engine channel on which this event occurred on
1889                 * @param itEvent - note off event / release trigger event
1890                 * @param pKey - key on which the release trigger voices shall be spawned
1891                 */
1892                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1893                    // spawn release triggered voice(s) if needed
1894                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1895                        // assign a new note to this release event
1896                        if (LaunchNewNote(pChannel, &*itEvent)) {
1897                            // allocate and trigger new release voice(s)
1898                            TriggerReleaseVoices(pChannel, itEvent);
1899                        }
1900                        pKey->ReleaseTrigger = false;
1901                    }
1902                }
1903    
1904                /**
1905                 * Called on note synthesis parameter change events. These are
1906                 * internal events caused by calling built-in real-time instrument
1907                 * script functions like change_vol(), change_pitch(), etc.
1908                 *
1909                 * This method performs two tasks:
1910                 *
1911                 * - It converts the event's relative values changes (Deltas) to
1912                 *   the respective final new synthesis parameter value (AbsValue),
1913                 *   for that particular moment of the event that is.
1914                 *
1915                 * - It moves the individual events to the Note's own event list
1916                 *   (or actually to the event list of the MIDI key), so that
1917                 *   voices can process those events sample accurately.
1918                 *
1919                 * @param pEngineChannel - engine channel on which this event occurred on
1920                 * @param itEvent - note synthesis parameter change event
1921                 */
1922                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1923                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1924    
1925                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1926                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1927    
1928                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1929    
1930                    switch (itEvent->Param.NoteSynthParam.Type) {
1931                        case Event::synth_param_volume:
1932                            if (relative)
1933                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1934                            else
1935                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1936                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1937                            break;
1938                        case Event::synth_param_pitch:
1939                            if (relative)
1940                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1941                            else
1942                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1943                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1944                            break;
1945                        case Event::synth_param_pan:
1946                            if (relative) {
1947                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1948                            } else {
1949                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1950                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1951                            }
1952                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1953                            break;
1954                        case Event::synth_param_cutoff:
1955                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1956                            break;
1957                        case Event::synth_param_resonance:
1958                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1959                            break;
1960                        case Event::synth_param_attack:
1961                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1962                            break;
1963                        case Event::synth_param_decay:
1964                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1965                            break;
1966                        case Event::synth_param_release:
1967                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1968                            break;
1969                    }
1970    
1971                    // move note parameter event to its MIDI key
1972                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1973                    itEvent.moveToEndOf(pKey->pEvents);
1974              }              }
1975    
1976              /**              /**

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

  ViewVC Help
Powered by ViewVC