29 |
|
|
30 |
#include "../../common/global_private.h" |
#include "../../common/global_private.h" |
31 |
#include "../AbstractEngineChannel.h" |
#include "../AbstractEngineChannel.h" |
32 |
#include "../common/LFOBase.h" |
#include "LFOBase.h" |
33 |
|
#include "Fade.h" |
34 |
#include "../EngineBase.h" |
#include "../EngineBase.h" |
35 |
#include "EG.h" |
#include "EG.h" |
36 |
#include "../gig/EGADSR.h" |
#include "../gig/EGADSR.h" |
42 |
|
|
43 |
// include the appropriate (unsigned) triangle LFO implementation |
// include the appropriate (unsigned) triangle LFO implementation |
44 |
#if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
#if CONFIG_UNSIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
45 |
# include "../common/LFOTriangleIntMath.h" |
# include "LFOTriangleIntMath.h" |
46 |
#elif CONFIG_UNSIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION |
#elif CONFIG_UNSIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION |
47 |
# include "../common/LFOTriangleIntAbsMath.h" |
# include "LFOTriangleIntAbsMath.h" |
48 |
#elif CONFIG_UNSIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION |
#elif CONFIG_UNSIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION |
49 |
# include "../common/LFOTriangleDiHarmonic.h" |
# include "LFOTriangleDiHarmonic.h" |
50 |
#else |
#else |
51 |
# error "Unknown or no (unsigned) triangle LFO implementation selected!" |
# error "Unknown or no (unsigned) triangle LFO implementation selected!" |
52 |
#endif |
#endif |
53 |
|
|
54 |
// include the appropriate (signed) triangle LFO implementation |
// include the appropriate (signed) triangle LFO implementation |
55 |
#if CONFIG_SIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
#if CONFIG_SIGNED_TRIANG_ALGO == INT_MATH_SOLUTION |
56 |
# include "../common/LFOTriangleIntMath.h" |
# include "LFOTriangleIntMath.h" |
57 |
#elif CONFIG_SIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION |
#elif CONFIG_SIGNED_TRIANG_ALGO == INT_ABS_MATH_SOLUTION |
58 |
# include "../common/LFOTriangleIntAbsMath.h" |
# include "LFOTriangleIntAbsMath.h" |
59 |
#elif CONFIG_SIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION |
#elif CONFIG_SIGNED_TRIANG_ALGO == DI_HARMONIC_SOLUTION |
60 |
# include "../common/LFOTriangleDiHarmonic.h" |
# include "LFOTriangleDiHarmonic.h" |
61 |
#else |
#else |
62 |
# error "Unknown or no (signed) triangle LFO implementation selected!" |
# error "Unknown or no (signed) triangle LFO implementation selected!" |
63 |
#endif |
#endif |
83 |
class AbstractVoice : public Voice { |
class AbstractVoice : public Voice { |
84 |
public: |
public: |
85 |
type_t Type; ///< Voice Type (bit field, a voice may have several types) |
type_t Type; ///< Voice Type (bit field, a voice may have several types) |
86 |
int MIDIKey; ///< MIDI key number of the key that triggered the voice |
NoteBase* pNote; ///< Note this voice belongs to and was caused by. |
|
uint8_t MIDIVelocity; ///< MIDI velocity of the key that triggered the voice |
|
87 |
int MIDIPan; ///< the current MIDI pan value plus the value from RegionInfo |
int MIDIPan; ///< the current MIDI pan value plus the value from RegionInfo |
88 |
|
|
89 |
SignalUnitRack* const pSignalUnitRack; |
SignalUnitRack* const pSignalUnitRack; |
90 |
|
|
91 |
AbstractVoice(SignalUnitRack* pRack); |
AbstractVoice(SignalUnitRack* pRack); |
115 |
return (Controller > 128) ? 0 : pEngineChannel->ControllerTable[Controller]; |
return (Controller > 128) ? 0 : pEngineChannel->ControllerTable[Controller]; |
116 |
} |
} |
117 |
|
|
118 |
|
/// Keyboard key on which this voice should listen to transitional events (i.e. note-off events to release the voice). |
119 |
|
inline uint8_t HostKey() const { return pNote->hostKey; } |
120 |
|
/// Keyboard key which the voice should use for calculating any synthesis relevant parameters (i.e. pitch). |
121 |
|
inline uint8_t MIDIKey() const { return pNote->cause.Param.Note.Key; } |
122 |
|
/// MIDI note-on velocity value which the voice should use for calculating any synthesis relevant parameters (i.e. amplitude). |
123 |
|
inline uint8_t MIDIVelocity() const { return pNote->cause.Param.Note.Velocity; } |
124 |
|
|
125 |
void processCCEvents(RTList<Event>::Iterator& itEvent, uint End); |
void processCCEvents(RTList<Event>::Iterator& itEvent, uint End); |
126 |
void processPitchEvent(RTList<Event>::Iterator& itEvent); |
void processPitchEvent(RTList<Event>::Iterator& itEvent); |
127 |
void processResonanceEvent(RTList<Event>::Iterator& itEvent); |
void processResonanceEvent(RTList<Event>::Iterator& itEvent); |
138 |
|
|
139 |
template<class TV, class TRR, class TR, class TD, class TIM, class TI> friend class EngineBase; |
template<class TV, class TRR, class TR, class TD, class TIM, class TI> friend class EngineBase; |
140 |
|
|
141 |
|
#if CONFIG_DEVMODE |
142 |
|
public: |
143 |
|
#else |
144 |
protected: |
protected: |
145 |
|
#endif |
146 |
SampleInfo SmplInfo; |
SampleInfo SmplInfo; |
147 |
RegionInfo RgnInfo; |
RegionInfo RgnInfo; |
148 |
InstrumentInfo InstrInfo; |
InstrumentInfo InstrInfo; |
150 |
|
|
151 |
double Pos; ///< Current playback position in sample |
double Pos; ///< Current playback position in sample |
152 |
PitchInfo Pitch; |
PitchInfo Pitch; |
153 |
|
Fade NotePitch; ///< Updated by calls to built-in instrument script function change_tune() (defaults to 1.0, that is neutral). |
154 |
float CutoffBase; ///< Cutoff frequency before control change, EG and LFO are applied |
float CutoffBase; ///< Cutoff frequency before control change, EG and LFO are applied |
155 |
float VolumeLeft; ///< Left channel volume. This factor is calculated when the voice is triggered and doesn't change after that. |
float VolumeLeft; ///< Left channel volume. This factor is calculated when the voice is triggered and doesn't change after that. |
156 |
float VolumeRight; ///< Right 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. |
157 |
|
float NotePanLeft; ///< Updated by calls to built-in instrument script function change_pan() (defaults to 1.0, that is neutral). |
158 |
|
float NotePanRight; ///< Updated by calls to built-in instrument script function change_pan() (defaults to 1.0, that is neutral). |
159 |
|
float NoteCutoff; ///< Updated by calls to built-in instrument script function change_cutoff() (defaults to 1.0, that is neutral). |
160 |
|
float NoteResonance; ///< Updated by calls to built-in instrument script function change_reso() (defaults to 1.0, that is neutral). |
161 |
gig::SmoothVolume CrossfadeSmoother; ///< Crossfade volume, updated by crossfade CC events |
gig::SmoothVolume CrossfadeSmoother; ///< Crossfade volume, updated by crossfade CC events |
162 |
gig::SmoothVolume VolumeSmoother; ///< Volume, updated by CC 7 (volume) events |
gig::SmoothVolume VolumeSmoother; ///< Volume, updated by CC 7 (volume) events |
163 |
gig::SmoothVolume PanLeftSmoother; ///< Left 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. |
164 |
gig::SmoothVolume PanRightSmoother; ///< Right channel volume, updated by CC 10 (pan) events |
gig::SmoothVolume PanRightSmoother; ///< Right channel volume, updated by CC 10 (pan) events and change_pan() real-time instrument script calls. |
165 |
|
Fade NoteVolume; ///< Note's global volume, updated by change_vol() real-time instrument script calls (defaults to 1.0, that is neutral). |
166 |
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 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 |
167 |
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 |
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 |
168 |
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. |
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. |