--- linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2016/07/10 14:24:13 2935 +++ linuxsampler/trunk/src/engines/common/AbstractVoice.cpp 2017/05/19 14:23:12 3188 @@ -4,7 +4,8 @@ * * * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * * Copyright (C) 2005-2008 Christian Schoenebeck * - * Copyright (C) 2009-2015 Christian Schoenebeck and Grigor Iliev * + * Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * + * Copyright (C) 2013-2016 Christian Schoenebeck and Andreas Persson * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -143,10 +144,15 @@ VolumeLeft = volume * pKeyInfo->PanLeft; VolumeRight = volume * pKeyInfo->PanRight; - float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE; + // this rate is used for rather mellow volume fades + const float subfragmentRate = GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE; + // this rate is used for very fast volume fades + const float quickRampRate = RTMath::Min(subfragmentRate, GetEngine()->SampleRate * 0.001f /* approx. 13ms */); CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate); + VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate); - NoteVolumeSmoother.trigger(pNote ? pNote->Override.Volume : 1.f, subfragmentRate); + NoteVolume.setCurrentValue(pNote ? pNote->Override.Volume : 1.f); + NoteVolume.setDefaultDuration(pNote ? pNote->Override.VolumeTime : DEFAULT_NOTE_VOLUME_TIME_S); // Check if the sample needs disk streaming or is too short for that long cachedsamples = GetSampleCacheSize() / SmplInfo.FrameSize; @@ -186,7 +192,8 @@ } Pitch = CalculatePitchInfo(PitchBend); - NotePitch = (pNote) ? pNote->Override.Pitch : 1.0f; + NotePitch.setCurrentValue(pNote ? pNote->Override.Pitch : 1.0f); + NotePitch.setDefaultDuration(pNote ? pNote->Override.PitchTime : DEFAULT_NOTE_PITCH_TIME_S); NoteCutoff = (pNote) ? pNote->Override.Cutoff : 1.0f; NoteResonance = (pNote) ? pNote->Override.Resonance : 1.0f; @@ -200,6 +207,12 @@ // calculate influence of EG1 controller on EG1's parameters EGInfo egInfo = CalculateEG1ControllerInfluence(eg1controllervalue); + if (pNote) { + egInfo.Attack *= pNote->Override.Attack; + egInfo.Decay *= pNote->Override.Decay; + egInfo.Release *= pNote->Override.Release; + } + TriggerEG1(egInfo, velrelease, velocityAttenuation, GetEngine()->SampleRate, itNoteOnEvent->Param.Note.Velocity); } else { pSignalUnitRack->Trigger(); @@ -210,11 +223,11 @@ NotePanRight = (pNote) ? AbstractEngine::PanCurveValueNorm(pNote->Override.Pan, 1 /*right*/) : 1.f; PanLeftSmoother.trigger( AbstractEngine::PanCurve[128 - pan] * NotePanLeft, - subfragmentRate + 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) ); PanRightSmoother.trigger( AbstractEngine::PanCurve[pan] * NotePanRight, - subfragmentRate + 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) ); #ifdef CONFIG_INTERPOLATE_VOLUME @@ -409,7 +422,7 @@ } } - uint killPos; + uint killPos = 0; if (itKillEvent) { int maxFadeOutPos = Samples - GetEngine()->GetMinFadeOutSamples(); if (maxFadeOutPos < 0) { @@ -445,9 +458,9 @@ PanLeftSmoother.update(AbstractEngine::PanCurve[128 - pan] * NotePanLeft); PanRightSmoother.update(AbstractEngine::PanCurve[pan] * NotePanRight); - finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch; + finalSynthesisParameters.fFinalPitch = Pitch.PitchBase * Pitch.PitchBend * NotePitch.render(); - float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolumeSmoother.render(); + float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render() * NoteVolume.render(); #ifdef CONFIG_PROCESS_MUTED_CHANNELS if (pChannel->GetMute()) fFinalVolume = 0; #endif @@ -633,22 +646,29 @@ */ void AbstractVoice::processCCEvents(RTList::Iterator& itEvent, uint End) { for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { - 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) + && itEvent->Param.CC.Controller) // if (valid) MIDI control change event + { if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { ProcessCutoffEvent(itEvent); } if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { processResonanceEvent(itEvent); } + if (itEvent->Param.CC.Controller == CTRL_TABLE_IDX_AFTERTOUCH || + itEvent->Type == Event::type_channel_pressure) + { + ProcessChannelPressureEvent(itEvent); + } if (pSignalUnitRack == NULL) { if (itEvent->Param.CC.Controller == pLFO1->ExtController) { - pLFO1->update(itEvent->Param.CC.Value); + pLFO1->updateByMIDICtrlValue(itEvent->Param.CC.Value); } if (itEvent->Param.CC.Controller == pLFO2->ExtController) { - pLFO2->update(itEvent->Param.CC.Value); + pLFO2->updateByMIDICtrlValue(itEvent->Param.CC.Value); } if (itEvent->Param.CC.Controller == pLFO3->ExtController) { - pLFO3->update(itEvent->Param.CC.Value); + pLFO3->updateByMIDICtrlValue(itEvent->Param.CC.Value); } } if (itEvent->Param.CC.Controller == 7) { // volume @@ -658,8 +678,6 @@ } } else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event processPitchEvent(itEvent); - } else if (itEvent->Type == Event::type_channel_pressure) { - ProcessChannelPressureEvent(itEvent); } else if (itEvent->Type == Event::type_note_pressure) { ProcessPolyphonicKeyPressureEvent(itEvent); } @@ -696,9 +714,9 @@ for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { // some voice types ignore note off if (!(Type & (Voice::type_one_shot | Voice::type_release_trigger | Voice::type_controller_triggered))) { - if (itEvent->Type == Event::type_release) { + if (itEvent->Type == Event::type_release_key) { EnterReleaseStage(); - } else if (itEvent->Type == Event::type_cancel_release) { + } else if (itEvent->Type == Event::type_cancel_release_key) { if (pSignalUnitRack == NULL) { pEG1->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); pEG2->update(EG::event_cancel_release, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); @@ -707,16 +725,34 @@ } } } + // process stop-note events (caused by built-in instrument script function note_off()) + if (itEvent->Type == Event::type_release_note && pNote && + pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote) + { + EnterReleaseStage(); + } + // process kill-note events (caused by built-in instrument script function fade_out()) + if (itEvent->Type == Event::type_kill_note && pNote && + pEngineChannel->pEngine->NoteByID( itEvent->Param.Note.ID ) == pNote) + { + Kill(itEvent); + } // process synthesis parameter events (caused by built-in realt-time instrument script functions) if (itEvent->Type == Event::type_note_synth_param && pNote && pEngineChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID ) == pNote) { switch (itEvent->Param.NoteSynthParam.Type) { case Event::synth_param_volume: - NoteVolumeSmoother.update(itEvent->Param.NoteSynthParam.AbsValue); + NoteVolume.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + break; + case Event::synth_param_volume_time: + NoteVolume.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue); break; case Event::synth_param_pitch: - NotePitch = itEvent->Param.NoteSynthParam.AbsValue; + NotePitch.fadeTo(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + break; + case Event::synth_param_pitch_time: + NotePitch.setDefaultDuration(itEvent->Param.NoteSynthParam.AbsValue); break; case Event::synth_param_pan: NotePanLeft = AbstractEngine::PanCurveValueNorm(itEvent->Param.NoteSynthParam.AbsValue, 0 /*left*/); @@ -728,6 +764,23 @@ case Event::synth_param_resonance: NoteResonance = itEvent->Param.NoteSynthParam.AbsValue; break; + case Event::synth_param_amp_lfo_depth: + pLFO1->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue); + break; + case Event::synth_param_amp_lfo_freq: + pLFO1->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + break; + case Event::synth_param_pitch_lfo_depth: + pLFO3->setScriptDepthFactor(itEvent->Param.NoteSynthParam.AbsValue); + break; + case Event::synth_param_pitch_lfo_freq: + pLFO3->setScriptFrequencyFactor(itEvent->Param.NoteSynthParam.AbsValue, GetEngine()->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); + break; + + case Event::synth_param_attack: + case Event::synth_param_decay: + case Event::synth_param_release: + break; // noop } } }