--- linuxsampler/trunk/src/engines/common/AbstractVoice.h 2014/05/18 17:38:25 2559 +++ linuxsampler/trunk/src/engines/common/AbstractVoice.h 2019/09/30 18:03:43 3612 @@ -29,7 +29,8 @@ #include "../../common/global_private.h" #include "../AbstractEngineChannel.h" -#include "../common/LFOBase.h" +#include "LFOBase.h" +#include "Fade.h" #include "../EngineBase.h" #include "EG.h" #include "../gig/EGADSR.h" @@ -38,54 +39,16 @@ #include "../gig/Synthesizer.h" #include "../gig/Profiler.h" #include "SignalUnitRack.h" - -// include the appropriate (unsigned) triangle LFO implementation -#if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION -# include "../common/LFOTriangleIntMath.h" -#elif CONFIG_UNSIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION -# include "../common/LFOTriangleIntAbsMath.h" -#elif CONFIG_UNSIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION -# include "../common/LFOTriangleDiHarmonic.h" -#else -# error "Unknown or no (unsigned) triangle LFO implementation selected!" -#endif - -// include the appropriate (signed) triangle LFO implementation -#if CONFIG_SIGNED_TRIANG_ALGO == INT_MATH_SOLUTION -# include "../common/LFOTriangleIntMath.h" -#elif CONFIG_SIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION -# include "../common/LFOTriangleIntAbsMath.h" -#elif CONFIG_SIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION -# include "../common/LFOTriangleDiHarmonic.h" -#else -# error "Unknown or no (signed) triangle LFO implementation selected!" -#endif +#include "LFOAll.h" namespace LinuxSampler { - #if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION - typedef LFOTriangleIntMath LFOUnsigned; - #elif CONFIG_UNSIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION - typedef LFOTriangleIntAbsMath LFOUnsigned; - #elif CONFIG_UNSIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION - typedef LFOTriangleDiHarmonic LFOUnsigned; - #endif - - #if CONFIG_SIGNED_TRIANG_ALGO == INT_MATH_SOLUTION - typedef LFOTriangleIntMath LFOSigned; - #elif CONFIG_SIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION - typedef LFOTriangleIntAbsMath LFOSigned; - #elif CONFIG_SIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION - typedef LFOTriangleDiHarmonic LFOSigned; - #endif - class AbstractVoice : public Voice { public: type_t Type; ///< Voice Type (bit field, a voice may have several types) - int MIDIKey; ///< MIDI key number of the key that triggered the voice - uint8_t MIDIVelocity; ///< MIDI velocity of the key that triggered the voice + NoteBase* pNote; ///< Note this voice belongs to and was caused by. int MIDIPan; ///< the current MIDI pan value plus the value from RegionInfo - + SignalUnitRack* const pSignalUnitRack; AbstractVoice(SignalUnitRack* pRack); @@ -108,13 +71,22 @@ virtual void VoiceFreed() { } virtual void Synthesize(uint Samples, sample_t* pSrc, uint Skip); - + + virtual release_trigger_t GetReleaseTriggerFlags() = 0; + uint GetSampleRate() { return GetEngine()->SampleRate; } uint8_t GetControllerValue(uint8_t Controller) { return (Controller > 128) ? 0 : pEngineChannel->ControllerTable[Controller]; } + /// Keyboard key on which this voice should listen to transitional events (i.e. note-off events to release the voice). + inline uint8_t HostKey() const { return pNote->hostKey; } + /// Keyboard key which the voice should use for calculating any synthesis relevant parameters (i.e. pitch). + inline uint8_t MIDIKey() const { return pNote->cause.Param.Note.Key; } + /// MIDI note-on velocity value which the voice should use for calculating any synthesis relevant parameters (i.e. amplitude). + inline uint8_t MIDIVelocity() const { return pNote->cause.Param.Note.Velocity; } + void processCCEvents(RTList::Iterator& itEvent, uint End); void processPitchEvent(RTList::Iterator& itEvent); void processResonanceEvent(RTList::Iterator& itEvent); @@ -131,7 +103,11 @@ template friend class EngineBase; + #if CONFIG_DEVMODE + public: + #else protected: + #endif SampleInfo SmplInfo; RegionInfo RgnInfo; InstrumentInfo InstrInfo; @@ -139,13 +115,18 @@ double Pos; ///< Current playback position in sample PitchInfo Pitch; + Fade NotePitch; ///< Updated by calls to built-in instrument script function change_tune() (defaults to 1.0, that is neutral). float CutoffBase; ///< Cutoff frequency before control change, EG and LFO are applied float VolumeLeft; ///< Left channel volume. This factor is calculated when the voice is triggered and doesn't change after that. float VolumeRight; ///< Right channel volume. This factor is calculated when the voice is triggered and doesn't change after that. + Fade NotePan[2]; ///< Updated by calls to built-in instrument script function change_pan() (defaults to 1.0, that is neutral, index 0 for left pan, index 1 for right). + NoteBase::Norm NoteCutoff; ///< Updated by calls to built-in instrument script function change_cutoff() (defaults to 1.0, that is neutral). + NoteBase::Norm NoteResonance; ///< Updated by calls to built-in instrument script function change_reso() (defaults to 1.0, that is neutral). gig::SmoothVolume CrossfadeSmoother; ///< Crossfade volume, updated by crossfade CC events gig::SmoothVolume VolumeSmoother; ///< Volume, updated by CC 7 (volume) events - gig::SmoothVolume PanLeftSmoother; ///< Left channel volume, updated by CC 10 (pan) events - gig::SmoothVolume PanRightSmoother; ///< Right channel volume, updated by CC 10 (pan) events + gig::SmoothVolume PanLeftSmoother; ///< Left channel volume, updated by CC 10 (pan) events and change_pan() real-time instrument script calls. + gig::SmoothVolume PanRightSmoother; ///< Right channel volume, updated by CC 10 (pan) events and change_pan() real-time instrument script calls. + Fade NoteVolume; ///< Note's global volume, updated by change_vol() real-time instrument script calls (defaults to 1.0, that is neutral). bool DiskVoice; ///< If the sample is very short it completely fits into the RAM cache and doesn't need to be streamed from disk, in that case this flag is set to false bool RAMLoop; ///< If this voice has a loop defined which completely fits into the cached RAM part of the sample, in this case we handle the looping within the voice class, else if the loop is located in the disk stream part, we let the disk stream handle the looping unsigned long MaxRAMPos; ///< The upper allowed limit (not actually the end) in the RAM sample cache, after that point it's not safe to chase the interpolator another time over over the current cache position, instead we switch to disk then.