24 |
#define __VOICE_H__ |
#define __VOICE_H__ |
25 |
|
|
26 |
#include "global.h" |
#include "global.h" |
27 |
|
#include "rtmath.h" |
28 |
#include "diskthread.h" |
#include "diskthread.h" |
29 |
#include "ringbuffer.h" |
#include "ringbuffer.h" |
30 |
#include "stream.h" |
#include "stream.h" |
31 |
#include "gig.h" |
#include "gig.h" |
32 |
#include "eg_vca.h" |
#include "eg_vca.h" |
33 |
|
#include "eg_d.h" |
34 |
#include "rtelmemorypool.h" |
#include "rtelmemorypool.h" |
35 |
#include "audiothread.h" |
#include "audiothread.h" |
36 |
#include "filter.h" |
#include "filter.h" |
37 |
#include "lfo.h" |
#include "lfo.h" |
38 |
|
|
|
#define MAX_PITCH 4 //FIXME: at the moment in octaves, should be changed into semitones |
|
39 |
#define USE_LINEAR_INTERPOLATION 1 ///< set to 0 if you prefer cubic interpolation (slower, better quality) |
#define USE_LINEAR_INTERPOLATION 1 ///< set to 0 if you prefer cubic interpolation (slower, better quality) |
40 |
#define ENABLE_FILTER 0 ///< if set to 0 then filter (VCF) code is ignored on compile time |
#define ENABLE_FILTER 0 ///< if set to 0 then filter (VCF) code is ignored on compile time |
41 |
#define FILTER_UPDATE_PERIOD 64 ///< amount of sample points after which filter parameters (cutoff, resonance) are going to be updated (higher value means less CPU load, but also worse parameter resolution) |
#define FILTER_UPDATE_PERIOD 64 ///< amount of sample points after which filter parameters (cutoff, resonance) are going to be updated (higher value means less CPU load, but also worse parameter resolution) |
42 |
#define FORCE_FILTER_USAGE 0 ///< if set to 1 then filter is always used, if set to 0 filter is used only in case the instrument file defined one |
#define FORCE_FILTER_USAGE 0 ///< if set to 1 then filter is always used, if set to 0 filter is used only in case the instrument file defined one |
43 |
|
#define FILTER_CUTOFF_MAX 10000.0f ///< maximum cutoff frequency (10kHz) |
44 |
|
#define FILTER_CUTOFF_MIN 100.0f ///< minimum cutoff frequency (100Hz) |
45 |
|
|
46 |
// Uncomment following line to override external cutoff controller |
// Uncomment following line to override external cutoff controller |
47 |
//#define OVERRIDE_FILTER_CUTOFF_CTRL 1 ///< set to an arbitrary MIDI control change controller (e.g. 1 for 'modulation wheel') |
//#define OVERRIDE_FILTER_CUTOFF_CTRL 1 ///< set to an arbitrary MIDI control change controller (e.g. 1 for 'modulation wheel') |
76 |
void Kill(); |
void Kill(); |
77 |
void Render(uint Samples); |
void Render(uint Samples); |
78 |
void Reset(); |
void Reset(); |
79 |
int Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument); |
int Trigger(ModulationSystem::Event* pNoteOnEvent, int PitchBend, gig::Instrument* pInstrument); |
80 |
inline bool IsActive() { return Active; } |
inline bool IsActive() { return Active; } |
81 |
inline void SetOutputLeft(float* pOutput, uint MaxSamplesPerCycle) { this->pOutputLeft = pOutput; this->MaxSamplesPerCycle = MaxSamplesPerCycle; } |
inline void SetOutputLeft(float* pOutput, uint MaxSamplesPerCycle) { this->pOutputLeft = pOutput; this->MaxSamplesPerCycle = MaxSamplesPerCycle; } |
82 |
inline void SetOutputRight(float* pOutput, uint MaxSamplesPerCycle) { this->pOutputRight = pOutput; this->MaxSamplesPerCycle = MaxSamplesPerCycle; } |
inline void SetOutputRight(float* pOutput, uint MaxSamplesPerCycle) { this->pOutputRight = pOutput; this->MaxSamplesPerCycle = MaxSamplesPerCycle; } |
94 |
float* pOutputRight; ///< Audio output buffer (right channel) |
float* pOutputRight; ///< Audio output buffer (right channel) |
95 |
uint MaxSamplesPerCycle; ///< Size of each audio output buffer |
uint MaxSamplesPerCycle; ///< Size of each audio output buffer |
96 |
double Pos; ///< Current playback position in sample |
double Pos; ///< Current playback position in sample |
97 |
double Pitch; ///< Current pitch depth (number of sample points to move on with each render step) |
double PitchBase; ///< Basic pitch depth, stays the same for the whole life time of the voice |
98 |
|
double PitchBend; ///< Current pitch value of the pitchbend wheel |
99 |
gig::Sample* pSample; ///< Pointer to the sample to be played back |
gig::Sample* pSample; ///< Pointer to the sample to be played back |
100 |
gig::Region* pRegion; ///< Pointer to the articulation information of the respective keyboard region of this voice |
gig::Region* pRegion; ///< Pointer to the articulation information of the respective keyboard region of this voice |
101 |
bool Active; ///< If this voice object is currently in usage |
bool Active; ///< If this voice object is currently in usage |
106 |
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 |
107 |
int LoopCyclesLeft; ///< In case there is a RAMLoop and it's not an endless loop; reflects number of loop cycles left to be passed |
int LoopCyclesLeft; ///< In case there is a RAMLoop and it's not an endless loop; reflects number of loop cycles left to be passed |
108 |
uint Delay; ///< Number of sample points the rendering process of this voice should be delayed (jitter correction), will be set to 0 after the first audio fragment cycle |
uint Delay; ///< Number of sample points the rendering process of this voice should be delayed (jitter correction), will be set to 0 after the first audio fragment cycle |
109 |
EG_VCA EG1; |
EG_VCA* pEG1; ///< Envelope Generator 1 (Amplification) |
110 |
|
EG_VCA* pEG2; ///< Envelope Generator 2 (Filter cutoff frequency) |
111 |
|
EG_D* pEG3; ///< Envelope Generator 3 (Pitch) |
112 |
GigFilter FilterLeft; |
GigFilter FilterLeft; |
113 |
GigFilter FilterRight; |
GigFilter FilterRight; |
114 |
midi_ctrl VCFCutoffCtrl; |
midi_ctrl VCFCutoffCtrl; |
115 |
midi_ctrl VCFResonanceCtrl; |
midi_ctrl VCFResonanceCtrl; |
116 |
LFO* pLFO1; |
int FilterUpdateCounter; ///< Used to update filter parameters all FILTER_UPDATE_PERIOD samples |
117 |
LFO* pLFO2; |
static const float FILTER_CUTOFF_COEFF; |
118 |
LFO* pLFO3; |
LFO<VCAManipulator>* pLFO1; ///< Low Frequency Oscillator 1 (Amplification) |
119 |
ModulationSystem::Event* pTriggerEvent; ///< First event on the key's list the voice should process (only needed for the first audio fragment in which voice was triggered, after that it will be set to NULL). |
LFO<VCFCManipulator>* pLFO2; ///< Low Frequency Oscillator 2 (Filter cutoff frequency) |
120 |
|
LFO<VCOManipulator>* pLFO3; ///< Low Frequency Oscillator 3 (Pitch) |
121 |
|
ModulationSystem::Event* pTriggerEvent; ///< First event on the key's list the voice should process (only needed for the first audio fragment in which voice was triggered, after that it will be set to NULL). |
122 |
|
|
123 |
|
// Static Methods |
124 |
|
static float CalculateFilterCutoffCoeff(); |
125 |
|
|
126 |
// Methods |
// Methods |
127 |
void ProcessEvents(uint Samples); |
void ProcessEvents(uint Samples); |
128 |
void Interpolate(uint Samples, sample_t* pSrc, uint Skip); |
void Interpolate(uint Samples, sample_t* pSrc, uint Skip); |
129 |
void InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip); |
void InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip); |
130 |
inline void InterpolateOneStep_Stereo(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) { |
inline void InterpolateOneStep_Stereo(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) { |
131 |
int pos_int = double_to_int(this->Pos); // integer position |
int pos_int = RTMath::DoubleToInt(this->Pos); // integer position |
132 |
float pos_fract = this->Pos - pos_int; // fractional part of position |
float pos_fract = this->Pos - pos_int; // fractional part of position |
133 |
pos_int <<= 1; |
pos_int <<= 1; |
134 |
|
|
135 |
#if ENABLE_FILTER |
#if ENABLE_FILTER |
136 |
UpdateFilter_Stereo(cutoff + 20.0f, resonance); // 20Hz min. |
UpdateFilter_Stereo(cutoff + FILTER_CUTOFF_MIN, resonance); |
137 |
#endif // ENABLE_FILTER |
#endif // ENABLE_FILTER |
138 |
|
|
139 |
#if USE_LINEAR_INTERPOLATION |
#if USE_LINEAR_INTERPOLATION |
181 |
this->Pos += pitch; |
this->Pos += pitch; |
182 |
} |
} |
183 |
inline void InterpolateOneStep_Mono(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) { |
inline void InterpolateOneStep_Mono(sample_t* pSrc, int& i, float& effective_volume, float& pitch, float& cutoff, float& resonance) { |
184 |
int pos_int = double_to_int(this->Pos); // integer position |
int pos_int = RTMath::DoubleToInt(this->Pos); // integer position |
185 |
float pos_fract = this->Pos - pos_int; // fractional part of position |
float pos_fract = this->Pos - pos_int; // fractional part of position |
186 |
|
|
187 |
#if ENABLE_FILTER |
#if ENABLE_FILTER |
188 |
UpdateFilter_Mono(cutoff + 20.0f, resonance); // 20Hz min. |
UpdateFilter_Mono(cutoff + FILTER_CUTOFF_MIN, resonance); |
189 |
#endif // ENABLE_FILTER |
#endif // ENABLE_FILTER |
190 |
|
|
191 |
#if USE_LINEAR_INTERPOLATION |
#if USE_LINEAR_INTERPOLATION |
211 |
this->Pos += pitch; |
this->Pos += pitch; |
212 |
} |
} |
213 |
inline void UpdateFilter_Stereo(float cutoff, float& resonance) { |
inline void UpdateFilter_Stereo(float cutoff, float& resonance) { |
214 |
static int updatecounter = 0; // we update the filter all FILTER_UPDATE_PERIOD samples |
if (!(++FilterUpdateCounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) { |
|
if (!(++updatecounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) { |
|
215 |
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
216 |
FilterRight.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
FilterRight.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
217 |
} |
} |
218 |
} |
} |
219 |
inline void UpdateFilter_Mono(float cutoff, float& resonance) { |
inline void UpdateFilter_Mono(float cutoff, float& resonance) { |
220 |
static int updatecounter = 0; // we update the filter all FILTER_UPDATE_PERIOD samples |
if (!(++FilterUpdateCounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) { |
|
if (!(++updatecounter % FILTER_UPDATE_PERIOD) && (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance())) { |
|
|
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
|
|
} |
|
|
} |
|
|
inline void ForceUpdateFilter_Stereo(float cutoff, float& resonance) { |
|
|
if (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance()) { |
|
|
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
|
|
FilterRight.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
|
|
} |
|
|
} |
|
|
inline void ForceUpdateFilter_Mono(float cutoff, float& resonance) { |
|
|
if (cutoff != FilterLeft.Cutoff() || resonance != FilterLeft.Resonance()) { |
|
221 |
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
FilterLeft.SetParameters(cutoff, resonance, ModulationSystem::SampleRate()); |
222 |
} |
} |
223 |
} |
} |
226 |
else if (ValueToCheck < Min) ValueToCheck = Min; |
else if (ValueToCheck < Min) ValueToCheck = Min; |
227 |
return ValueToCheck; |
return ValueToCheck; |
228 |
} |
} |
|
inline int double_to_int(double f) { |
|
|
#if ARCH_X86 |
|
|
int i; |
|
|
__asm__ ("fistl %0" : "=m"(i) : "st"(f - 0.5) ); |
|
|
return i; |
|
|
#else |
|
|
return (int) f; |
|
|
#endif // ARCH_X86 |
|
|
} |
|
229 |
}; |
}; |
230 |
|
|
231 |
#endif // __VOICE_H__ |
#endif // __VOICE_H__ |