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

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

  ViewVC Help
Powered by ViewVC