/[svn]/linuxsampler/trunk/src/engines/common/AbstractVoice.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/common/AbstractVoice.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2382 by persson, Sun Dec 2 16:30:42 2012 UTC revision 3017 by schoenebeck, Wed Oct 19 12:28:40 2016 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2015 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
10   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 110  namespace LinuxSampler { Line 110  namespace LinuxSampler {
110          #endif // CONFIG_DEVMODE          #endif // CONFIG_DEVMODE
111    
112          Type            = VoiceType;          Type            = VoiceType;
113          MIDIKey         = itNoteOnEvent->Param.Note.Key;          pNote           = pEngineChannel->pEngine->NoteByID( itNoteOnEvent->Param.Note.ID );
         MIDIVelocity    = itNoteOnEvent->Param.Note.Velocity;  
114          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet          PlaybackState   = playback_state_init; // mark voice as triggered, but no audio rendered yet
115          Delay           = itNoteOnEvent->FragmentPos();          Delay           = itNoteOnEvent->FragmentPos();
116          itTriggerEvent  = itNoteOnEvent;          itTriggerEvent  = itNoteOnEvent;
117          itKillEvent     = Pool<Event>::Iterator();          itKillEvent     = Pool<Event>::Iterator();
118          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pKeyInfo = GetMidiKeyInfo(MIDIKey());
119    
120          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;          pGroupEvents = iKeyGroup ? pEngineChannel->ActiveKeyGroups[iKeyGroup] : 0;
121    
# Line 144  namespace LinuxSampler { Line 143  namespace LinuxSampler {
143          VolumeLeft  = volume * pKeyInfo->PanLeft;          VolumeLeft  = volume * pKeyInfo->PanLeft;
144          VolumeRight = volume * pKeyInfo->PanRight;          VolumeRight = volume * pKeyInfo->PanRight;
145    
146          float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          // this rate is used for rather mellow volume fades
147            const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
148            // this rate is used for very fast volume fades
149            const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* 1ms */);
150          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);          CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate);
151    
152          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);          VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate);
153            NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, quickRampRate);
154    
155          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
156          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;          long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize;
# Line 170  namespace LinuxSampler { Line 174  namespace LinuxSampler {
174              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);              RAMLoop = (SmplInfo.HasLoops && (SmplInfo.LoopStart + SmplInfo.LoopLength) <= MaxRAMPos);
175    
176              if (OrderNewStream()) return -1;              if (OrderNewStream()) return -1;
177              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              dmsg(4,("Disk voice launched (cached samples: %ld, total Samples: %d, MaxRAMPos: %lu, RAMLooping: %s)\n", cachedsamples, SmplInfo.TotalFrameCount, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
178          }          }
179          else { // RAM only voice          else { // RAM only voice
180              MaxRAMPos = cachedsamples;              MaxRAMPos = cachedsamples;
# Line 186  namespace LinuxSampler { Line 190  namespace LinuxSampler {
190          }          }
191    
192          Pitch = CalculatePitchInfo(PitchBend);          Pitch = CalculatePitchInfo(PitchBend);
193            NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f;
194            NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f;
195            NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f;
196    
197          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
198          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);          const double velrelease = 1 / GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity);
# Line 197  namespace LinuxSampler { Line 204  namespace LinuxSampler {
204              // calculate influence of EG1 controller on EG1's parameters              // calculate influence of EG1 controller on EG1's parameters
205              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);              EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue);
206    
207                if (pNote) {
208                    egInfo.Attack  *= pNote->Override.Attack;
209                    egInfo.Decay   *= pNote->Override.Decay;
210                    egInfo.Release *= pNote->Override.Release;
211                }
212    
213              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);              TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity);
214          } else {          } else {
215              pSignalUnitRack->Trigger();              pSignalUnitRack->Trigger();
216          }          }
217    
218          uint8_t pan = MIDIPan;          const uint8_t pan = (pSignalUnitRack) ? pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan) : MIDIPan;
219          if (pSignalUnitRack) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);          NotePanLeft  = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 0 /*left*/ ) : 1.f;
220          PanLeftSmoother.trigger(AbstractEngine::PanCurve[128 - pan], subfragmentRate);          NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f;
221          PanRightSmoother.trigger(AbstractEngine::PanCurve[pan], subfragmentRate);          PanLeftSmoother.trigger(
222                AbstractEngine::PanCurve[128 - pan] * NotePanLeft,
223                quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
224            );
225            PanRightSmoother.trigger(
226                AbstractEngine::PanCurve[pan] * NotePanRight,
227                quickRampRate //NOTE: maybe we should have 2 separate pan smoothers, one for MIDI CC10 (with slow rate) and one for instrument script change_pan() calls (with fast rate)
228            );
229    
230  #ifdef CONFIG_INTERPOLATE_VOLUME  #ifdef CONFIG_INTERPOLATE_VOLUME
231          // setup initial volume in synthesis parameters          // setup initial volume in synthesis parameters
# Line 248  namespace LinuxSampler { Line 268  namespace LinuxSampler {
268                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch                  // if portamento mode is on, we dedicate EG3 purely for portamento, otherwise if portamento is off we do as told by the patch
269                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;                  bool  bPortamento = pEngineChannel->PortamentoMode && pEngineChannel->PortamentoPos >= 0.0f;
270                  float eg3depth = (bPortamento)                  float eg3depth = (bPortamento)
271                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey) * 100)                               ? RTMath::CentsToFreqRatio((pEngineChannel->PortamentoPos - (float) MIDIKey()) * 100)
272                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);                               : RTMath::CentsToFreqRatio(RgnInfo.EG3Depth);
273                  float eg3time = (bPortamento)                  float eg3time = (bPortamento)
274                              ? pEngineChannel->PortamentoTime                              ? pEngineChannel->PortamentoTime
# Line 353  namespace LinuxSampler { Line 373  namespace LinuxSampler {
373          }          }
374                    
375          AbstractEngineChannel* pChannel = pEngineChannel;          AbstractEngineChannel* pChannel = pEngineChannel;
376          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey);          MidiKeyBase* pMidiKeyInfo = GetMidiKeyInfo(MIDIKey());
377    
378          const bool bVoiceRequiresDedicatedRouting =          const bool bVoiceRequiresDedicatedRouting =
379              pEngineChannel->GetFxSendCount() > 0 &&              pEngineChannel->GetFxSendCount() > 0 &&
# Line 379  namespace LinuxSampler { Line 399  namespace LinuxSampler {
399    
400          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pChannel->pEvents->first();
401          RTList<Event>::Iterator itNoteEvent;          RTList<Event>::Iterator itNoteEvent;
402          GetFirstEventOnKey(MIDIKey, itNoteEvent);          GetFirstEventOnKey(HostKey(), itNoteEvent);
403    
404          RTList<Event>::Iterator itGroupEvent;          RTList<Event>::Iterator itGroupEvent;
405          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();          if (pGroupEvents && !Orphan) itGroupEvent = pGroupEvents->first();
# Line 427  namespace LinuxSampler { Line 447  namespace LinuxSampler {
447              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
448              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
449    
450              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change, aftertouch and pitchbend events for this subfragment
451              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
452              uint8_t pan = MIDIPan;              uint8_t pan = MIDIPan;
453              if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);              if (pSignalUnitRack != NULL) pan = pSignalUnitRack->GetEndpointUnit()->CalculatePan(MIDIPan);
               
             PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan]);  
             PanRightSmoother.update(AbstractEngine::PanCurve[pan]);  
454    
455              finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend;              PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft);
456              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              PanRightSmoother.update(AbstractEngine::PanCurve[pan]      * NotePanRight);
457    
458                finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch;
459    
460                float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render();
461  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
462              if (pChannel->GetMute()) fFinalVolume = 0;              if (pChannel->GetMute()) fFinalVolume = 0;
463  #endif  #endif
# Line 488  namespace LinuxSampler { Line 509  namespace LinuxSampler {
509    
510                  // process low frequency oscillators                  // process low frequency oscillators
511                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());                  if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render());
512                  if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();                  if (bLFO2Enabled) fFinalCutoff *= (1.0f - pLFO2->render());
513                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());                  if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
514              } else {              } else {
515                  // if the voice was killed in this subfragment, enter fade out stage                  // if the voice was killed in this subfragment, enter fade out stage
# Line 513  namespace LinuxSampler { Line 534  namespace LinuxSampler {
534                      pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);                      pSignalUnitRack->GetEndpointUnit()->CalculatePitch(finalSynthesisParameters.fFinalPitch);
535                                            
536              }              }
537                
538                fFinalCutoff    *= NoteCutoff;
539                fFinalResonance *= NoteResonance;
540    
541              // limit the pitch so we don't read outside the buffer              // limit the pitch so we don't read outside the buffer
542              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));              finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
543    
# Line 611  namespace LinuxSampler { Line 635  namespace LinuxSampler {
635      }      }
636    
637      /**      /**
638       * Process given list of MIDI control change and pitch bend events for       * Process given list of MIDI control change, aftertouch and pitch bend
639       * the given time.       * events for the given time.
640       *       *
641       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
642       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
643       */       */
644      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {      void AbstractVoice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) {
645          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
646              if (itEvent->Type == Event::type_control_change && itEvent->Param.CC.Controller) { // if (valid) MIDI control change event              if ((itEvent->Type == Event::type_control_change || itEvent->Type == Event::type_channel_pressure)
647                    && itEvent->Param.CC.Controller) // if (valid) MIDI control change event
648                {
649                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) {
650                      ProcessCutoffEvent(itEvent);                      ProcessCutoffEvent(itEvent);
651                  }                  }
652                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {                  if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) {
653                      processResonanceEvent(itEvent);                      processResonanceEvent(itEvent);
654                  }                  }
655                    if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH ||
656                        itEvent->Type == Event::type_channel_pressure)
657                    {
658                        ProcessChannelPressureEvent(itEvent);
659                    }
660                  if (pSignalUnitRack == NULL) {                  if (pSignalUnitRack == NULL) {
661                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {                      if (itEvent->Param.CC.Controller == pLFO1->ExtController) {
662                          pLFO1->update(itEvent->Param.CC.Value);                          pLFO1->update(itEvent->Param.CC.Value);
# Line 644  namespace LinuxSampler { Line 675  namespace LinuxSampler {
675                  }                  }
676              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event              } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event
677                  processPitchEvent(itEvent);                  processPitchEvent(itEvent);
678                } else if (itEvent->Type == Event::type_note_pressure) {
679                    ProcessPolyphonicKeyPressureEvent(itEvent);
680              }              }
681    
682              ProcessCCEvent(itEvent);              ProcessCCEvent(itEvent);
# Line 668  namespace LinuxSampler { Line 701  namespace LinuxSampler {
701      }      }
702    
703      /**      /**
704       * Process given list of MIDI note on, note off and sustain pedal events       * Process given list of MIDI note on, note off, sustain pedal events and
705       * for the given time.       * note synthesis parameter events for the given time.
706       *       *
707       * @param itEvent - iterator pointing to the next event to be processed       * @param itEvent - iterator pointing to the next event to be processed
708       * @param End     - youngest time stamp where processing should be stopped       * @param End     - youngest time stamp where processing should be stopped
# Line 678  namespace LinuxSampler { Line 711  namespace LinuxSampler {
711          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {          for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) {
712              // some voice types ignore note off              // some voice types ignore note off
713              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {              if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) {
714                  if (itEvent->Type == Event::type_release) {                  if (itEvent->Type == Event::type_release_key) {
715                      EnterReleaseStage();                      EnterReleaseStage();
716                  } else if (itEvent->Type == Event::type_cancel_release) {                  } else if (itEvent->Type == Event::type_cancel_release_key) {
717                      if (pSignalUnitRack == NULL) {                      if (pSignalUnitRack == NULL) {
718                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
719                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);                          pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
# Line 689  namespace LinuxSampler { Line 722  namespace LinuxSampler {
722                      }                      }
723                  }                  }
724              }              }
725                // process stop-note events (caused by built-in instrument script function note_off())
726                if (itEvent->Type == Event::type_release_note && pNote &&
727                    pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote)
728                {
729                    EnterReleaseStage();
730                }
731                // process synthesis parameter events (caused by built-in realt-time instrument script functions)
732                if (itEvent->Type == Event::type_note_synth_param && pNote &&
733                    pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote)
734                {
735                    switch (itEvent->Param.NoteSynthParam.Type) {
736                        case Event::synth_param_volume:
737                            NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue);
738                            break;
739                        case Event::synth_param_pitch:
740                            NotePitch = itEvent->Param.NoteSynthParam.AbsValue;
741                            break;
742                        case Event::synth_param_pan:
743                            NotePanLeft  = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/);
744                            NotePanRight = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 1 /*right*/);
745                            break;
746                        case Event::synth_param_cutoff:
747                            NoteCutoff = itEvent->Param.NoteSynthParam.AbsValue;
748                            break;
749                        case Event::synth_param_resonance:
750                            NoteResonance = itEvent->Param.NoteSynthParam.AbsValue;
751                            break;
752                    }
753                }
754          }          }
755      }      }
756    
# Line 715  namespace LinuxSampler { Line 777  namespace LinuxSampler {
777      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {      void AbstractVoice::UpdatePortamentoPos(Pool<Event>::Iterator& itNoteOffEvent) {
778          if (pSignalUnitRack == NULL) {          if (pSignalUnitRack == NULL) {
779              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());              const float fFinalEG3Level = EG3.level(itNoteOffEvent->FragmentPos());
780              pEngineChannel->PortamentoPos = (float) MIDIKey + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;              pEngineChannel->PortamentoPos = (float) MIDIKey() + RTMath::FreqRatioToCents(fFinalEG3Level) * 0.01f;
781          } else {          } else {
782              // TODO:              // TODO:
783          }          }
# Line 742  namespace LinuxSampler { Line 804  namespace LinuxSampler {
804    
805      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {      Voice::PitchInfo AbstractVoice::CalculatePitchInfo(int PitchBend) {
806          PitchInfo pitch;          PitchInfo pitch;
807          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey % 12];          double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
808    
809          // GSt behaviour: maximum transpose up is 40 semitones. If          // GSt behaviour: maximum transpose up is 40 semitones. If
810          // MIDI key is more than 40 semitones above unity note,          // MIDI key is more than 40 semitones above unity note,
811          // the transpose is not done.          // the transpose is not done.
812          if (!SmplInfo.Unpitched && (MIDIKey - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey - (int) RgnInfo.UnityNote) * 100;          if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
813    
814          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));          pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
815          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;          pitch.PitchBendRange = 1.0 / 8192.0 * 100.0 * InstrInfo.PitchbendRange;
# Line 755  namespace LinuxSampler { Line 817  namespace LinuxSampler {
817    
818          return pitch;          return pitch;
819      }      }
820        
821        void AbstractVoice::onScaleTuningChanged() {
822            PitchInfo pitch = this->Pitch;
823            double pitchbasecents = InstrInfo.FineTune + RgnInfo.FineTune + GetEngine()->ScaleTuning[MIDIKey() % 12];
824            
825            // GSt behaviour: maximum transpose up is 40 semitones. If
826            // MIDI key is more than 40 semitones above unity note,
827            // the transpose is not done.
828            if (!SmplInfo.Unpitched && (MIDIKey() - (int) RgnInfo.UnityNote) < 40) pitchbasecents += (MIDIKey() - (int) RgnInfo.UnityNote) * 100;
829            
830            pitch.PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(SmplInfo.SampleRate) / double(GetEngine()->SampleRate));
831            this->Pitch = pitch;
832        }
833    
834      double AbstractVoice::CalculateVolume(double velocityAttenuation) {      double AbstractVoice::CalculateVolume(double velocityAttenuation) {
835          // For 16 bit samples, we downscale by 32768 to convert from          // For 16 bit samples, we downscale by 32768 to convert from
# Line 767  namespace LinuxSampler { Line 842  namespace LinuxSampler {
842          // the volume of release triggered samples depends on note length          // the volume of release triggered samples depends on note length
843          if (Type & Voice::type_release_trigger) {          if (Type & Voice::type_release_trigger) {
844              float noteLength = float(GetEngine()->FrameTime + Delay -              float noteLength = float(GetEngine()->FrameTime + Delay -
845                  GetNoteOnTime(MIDIKey) ) / GetEngine()->SampleRate;                  GetNoteOnTime(MIDIKey()) ) / GetEngine()->SampleRate;
846    
847              volume *= GetReleaseTriggerAttenuation(noteLength);              volume *= GetReleaseTriggerAttenuation(noteLength);
848          }          }

Legend:
Removed from v.2382  
changed lines
  Added in v.3017

  ViewVC Help
Powered by ViewVC