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

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

  ViewVC Help
Powered by ViewVC