21 |
* MA 02111-1307 USA * |
* MA 02111-1307 USA * |
22 |
***************************************************************************/ |
***************************************************************************/ |
23 |
|
|
|
#include "EGADSR.h" |
|
|
#include "Manipulator.h" |
|
24 |
#include "../../common/Features.h" |
#include "../../common/Features.h" |
25 |
#include "Synthesizer.h" |
#include "Synthesizer.h" |
26 |
|
#include "Profiler.h" |
27 |
|
|
28 |
#include "Voice.h" |
#include "Voice.h" |
29 |
|
|
31 |
|
|
32 |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff()); |
33 |
|
|
|
const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask()); |
|
|
|
|
34 |
float Voice::CalculateFilterCutoffCoeff() { |
float Voice::CalculateFilterCutoffCoeff() { |
35 |
return log(CONFIG_FILTER_CUTOFF_MIN / CONFIG_FILTER_CUTOFF_MAX); |
return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN); |
|
} |
|
|
|
|
|
int Voice::CalculateFilterUpdateMask() { |
|
|
if (CONFIG_FILTER_UPDATE_STEPS <= 0) return 0; |
|
|
int power_of_two; |
|
|
for (power_of_two = 0; 1<<power_of_two < CONFIG_FILTER_UPDATE_STEPS; power_of_two++); |
|
|
return (1 << power_of_two) - 1; |
|
36 |
} |
} |
37 |
|
|
38 |
Voice::Voice() { |
Voice::Voice() { |
39 |
pEngine = NULL; |
pEngine = NULL; |
40 |
pDiskThread = NULL; |
pDiskThread = NULL; |
41 |
PlaybackState = playback_state_end; |
PlaybackState = playback_state_end; |
42 |
pEG1 = NULL; |
pLFO1 = new LFOUnsigned(1.0f); // amplitude EG (0..1 range) |
43 |
pEG2 = NULL; |
pLFO2 = new LFOUnsigned(1.0f); // filter EG (0..1 range) |
44 |
pEG3 = NULL; |
pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range) |
|
pVCAManipulator = NULL; |
|
|
pVCFCManipulator = NULL; |
|
|
pVCOManipulator = NULL; |
|
|
pLFO1 = NULL; |
|
|
pLFO2 = NULL; |
|
|
pLFO3 = NULL; |
|
45 |
KeyGroup = 0; |
KeyGroup = 0; |
46 |
SynthesisMode = 0; // set all mode bits to 0 first |
SynthesisMode = 0; // set all mode bits to 0 first |
47 |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
50 |
#else |
#else |
51 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
52 |
#endif |
#endif |
53 |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true); |
SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, Profiler::isEnabled()); |
54 |
|
|
55 |
FilterLeft.Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
56 |
FilterRight.Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
57 |
} |
} |
58 |
|
|
59 |
Voice::~Voice() { |
Voice::~Voice() { |
|
if (pEG1) delete pEG1; |
|
|
if (pEG2) delete pEG2; |
|
|
if (pEG3) delete pEG3; |
|
60 |
if (pLFO1) delete pLFO1; |
if (pLFO1) delete pLFO1; |
61 |
if (pLFO2) delete pLFO2; |
if (pLFO2) delete pLFO2; |
62 |
if (pLFO3) delete pLFO3; |
if (pLFO3) delete pLFO3; |
|
if (pVCAManipulator) delete pVCAManipulator; |
|
|
if (pVCFCManipulator) delete pVCFCManipulator; |
|
|
if (pVCOManipulator) delete pVCOManipulator; |
|
63 |
} |
} |
64 |
|
|
65 |
void Voice::SetEngine(Engine* pEngine) { |
void Voice::SetEngine(Engine* pEngine) { |
66 |
this->pEngine = pEngine; |
this->pEngine = pEngine; |
|
|
|
|
// delete old objects |
|
|
if (pEG1) delete pEG1; |
|
|
if (pEG2) delete pEG2; |
|
|
if (pEG3) delete pEG3; |
|
|
if (pVCAManipulator) delete pVCAManipulator; |
|
|
if (pVCFCManipulator) delete pVCFCManipulator; |
|
|
if (pVCOManipulator) delete pVCOManipulator; |
|
|
if (pLFO1) delete pLFO1; |
|
|
if (pLFO2) delete pLFO2; |
|
|
if (pLFO3) delete pLFO3; |
|
|
|
|
|
// create new ones |
|
|
pEG1 = new EGADSR(pEngine, Event::destination_vca); |
|
|
pEG2 = new EGADSR(pEngine, Event::destination_vcfc); |
|
|
pEG3 = new EGDecay(pEngine, Event::destination_vco); |
|
|
pVCAManipulator = new VCAManipulator(pEngine); |
|
|
pVCFCManipulator = new VCFCManipulator(pEngine); |
|
|
pVCOManipulator = new VCOManipulator(pEngine); |
|
|
pLFO1 = new LFO<gig::VCAManipulator>(0.0f, 1.0f, LFO<VCAManipulator>::propagation_top_down, pVCAManipulator, pEngine->pEventPool); |
|
|
pLFO2 = new LFO<gig::VCFCManipulator>(0.0f, 1.0f, LFO<VCFCManipulator>::propagation_top_down, pVCFCManipulator, pEngine->pEventPool); |
|
|
pLFO3 = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max. |
|
|
|
|
67 |
this->pDiskThread = pEngine->pDiskThread; |
this->pDiskThread = pEngine->pDiskThread; |
68 |
dmsg(6,("Voice::SetEngine()\n")); |
dmsg(6,("Voice::SetEngine()\n")); |
69 |
} |
} |
72 |
* Initializes and triggers the voice, a disk stream will be launched if |
* Initializes and triggers the voice, a disk stream will be launched if |
73 |
* needed. |
* needed. |
74 |
* |
* |
75 |
* @param pEngineChannel - engine channel on which this voice was ordered |
* @param pEngineChannel - engine channel on which this voice was ordered |
76 |
* @param itNoteOnEvent - event that caused triggering of this voice |
* @param itNoteOnEvent - event that caused triggering of this voice |
77 |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
78 |
* @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data |
* @param pDimRgn - points to the dimension region which provides sample wave(s) and articulation data |
79 |
* @param iLayer - layer number this voice refers to (only if this is a layered sound of course) |
* @param VoiceType - type of this voice |
80 |
* @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false) |
* @param iKeyGroup - a value > 0 defines a key group in which this voice is member of |
|
* @param VoiceStealingAllowed - wether the voice is allowed to steal voices for further subvoices |
|
81 |
* @returns 0 on success, a value < 0 if the voice wasn't triggered |
* @returns 0 on success, a value < 0 if the voice wasn't triggered |
82 |
* (either due to an error or e.g. because no region is |
* (either due to an error or e.g. because no region is |
83 |
* defined for the given key) |
* defined for the given key) |
84 |
*/ |
*/ |
85 |
int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealingAllowed) { |
int Voice::Trigger(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup) { |
86 |
this->pEngineChannel = pEngineChannel; |
this->pEngineChannel = pEngineChannel; |
87 |
if (!pInstrument) { |
this->pDimRgn = pDimRgn; |
88 |
dmsg(1,("voice::trigger: !pInstrument\n")); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
89 |
#if CONFIG_DEVMODE |
#if CONFIG_DEVMODE |
90 |
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging |
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging |
91 |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
92 |
} |
} |
93 |
#endif // CONFIG_DEVMODE |
#endif // CONFIG_DEVMODE |
94 |
|
|
95 |
Type = type_normal; |
Type = VoiceType; |
96 |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
|
pRegion = pInstrument->GetRegion(MIDIKey); |
|
97 |
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 |
98 |
Delay = itNoteOnEvent->FragmentPos(); |
Delay = itNoteOnEvent->FragmentPos(); |
99 |
itTriggerEvent = itNoteOnEvent; |
itTriggerEvent = itNoteOnEvent; |
100 |
itKillEvent = Pool<Event>::Iterator(); |
itKillEvent = Pool<Event>::Iterator(); |
101 |
|
KeyGroup = iKeyGroup; |
102 |
|
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
103 |
|
|
104 |
if (!pRegion) { |
// calculate volume |
105 |
dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey)); |
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
|
return -1; |
|
|
} |
|
106 |
|
|
107 |
// only mark the first voice of a layered voice (group) to be in a |
Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
|
// key group, so the layered voices won't kill each other |
|
|
KeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0; |
|
108 |
|
|
109 |
// get current dimension values to select the right dimension region |
Volume *= pDimRgn->SampleAttenuation; |
|
//FIXME: controller values for selecting the dimension region here are currently not sample accurate |
|
|
uint DimValues[8] = { 0 }; |
|
|
for (int i = pRegion->Dimensions - 1; i >= 0; i--) { |
|
|
switch (pRegion->pDimensionDefinitions[i].dimension) { |
|
|
case ::gig::dimension_samplechannel: |
|
|
DimValues[i] = 0; //TODO: we currently ignore this dimension |
|
|
break; |
|
|
case ::gig::dimension_layer: |
|
|
DimValues[i] = iLayer; |
|
|
break; |
|
|
case ::gig::dimension_velocity: |
|
|
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
|
|
break; |
|
|
case ::gig::dimension_channelaftertouch: |
|
|
DimValues[i] = 0; //TODO: we currently ignore this dimension |
|
|
break; |
|
|
case ::gig::dimension_releasetrigger: |
|
|
Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal; |
|
|
DimValues[i] = (uint) ReleaseTriggerVoice; |
|
|
break; |
|
|
case ::gig::dimension_keyboard: |
|
|
DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension; |
|
|
break; |
|
|
case ::gig::dimension_roundrobin: |
|
|
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
|
|
break; |
|
|
case ::gig::dimension_random: |
|
|
pEngine->RandomSeed = pEngine->RandomSeed * 1103515245 + 12345; // classic pseudo random number generator |
|
|
DimValues[i] = (uint) pEngine->RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random |
|
|
break; |
|
|
case ::gig::dimension_modwheel: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[1]; |
|
|
break; |
|
|
case ::gig::dimension_breath: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[2]; |
|
|
break; |
|
|
case ::gig::dimension_foot: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[4]; |
|
|
break; |
|
|
case ::gig::dimension_portamentotime: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[5]; |
|
|
break; |
|
|
case ::gig::dimension_effect1: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[12]; |
|
|
break; |
|
|
case ::gig::dimension_effect2: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[13]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose1: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[16]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose2: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[17]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose3: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[18]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose4: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[19]; |
|
|
break; |
|
|
case ::gig::dimension_sustainpedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[64]; |
|
|
break; |
|
|
case ::gig::dimension_portamento: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[65]; |
|
|
break; |
|
|
case ::gig::dimension_sostenutopedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[66]; |
|
|
break; |
|
|
case ::gig::dimension_softpedal: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[67]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose5: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[80]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose6: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[81]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose7: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[82]; |
|
|
break; |
|
|
case ::gig::dimension_genpurpose8: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[83]; |
|
|
break; |
|
|
case ::gig::dimension_effect1depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[91]; |
|
|
break; |
|
|
case ::gig::dimension_effect2depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[92]; |
|
|
break; |
|
|
case ::gig::dimension_effect3depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[93]; |
|
|
break; |
|
|
case ::gig::dimension_effect4depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[94]; |
|
|
break; |
|
|
case ::gig::dimension_effect5depth: |
|
|
DimValues[i] = pEngineChannel->ControllerTable[95]; |
|
|
break; |
|
|
case ::gig::dimension_none: |
|
|
std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush; |
|
|
break; |
|
|
default: |
|
|
std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush; |
|
|
} |
|
|
} |
|
|
pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); |
|
110 |
|
|
111 |
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
// the volume of release triggered samples depends on note length |
112 |
if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent |
if (Type == type_release_trigger) { |
113 |
|
float noteLength = float(pEngine->FrameTime + Delay - |
114 |
|
pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; |
115 |
|
float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; |
116 |
|
if (attenuation <= 0) return -1; |
117 |
|
Volume *= attenuation; |
118 |
|
} |
119 |
|
|
120 |
// select channel mode (mono or stereo) |
// select channel mode (mono or stereo) |
121 |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
139 |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
PanLeft = 1.0f - float(RTMath::Max(pDimRgn->Pan, 0)) / 63.0f; |
140 |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
PanRight = 1.0f - float(RTMath::Min(pDimRgn->Pan, 0)) / -64.0f; |
141 |
|
|
142 |
Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
finalSynthesisParameters.dPos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points) |
143 |
|
Pos = pDimRgn->SampleStartOffset; |
144 |
|
|
145 |
// 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 |
146 |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
long cachedsamples = pSample->GetCache().Size / pSample->FrameSize; |
151 |
|
|
152 |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
// check if there's a loop defined which completely fits into the cached (RAM) part of the sample |
153 |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { |
154 |
RAMLoop = true; |
RAMLoop = true; |
155 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiTotalCycles = pSample->LoopPlayCount; |
156 |
|
loop.uiCyclesLeft = pSample->LoopPlayCount; |
157 |
|
loop.uiStart = pSample->LoopStart; |
158 |
|
loop.uiEnd = pSample->LoopEnd; |
159 |
|
loop.uiSize = pSample->LoopSize; |
160 |
} |
} |
161 |
else RAMLoop = false; |
else RAMLoop = false; |
162 |
|
|
170 |
else { // RAM only voice |
else { // RAM only voice |
171 |
MaxRAMPos = cachedsamples; |
MaxRAMPos = cachedsamples; |
172 |
if (pSample->Loops) { |
if (pSample->Loops) { |
173 |
RAMLoop = true; |
RAMLoop = true; |
174 |
LoopCyclesLeft = pSample->LoopPlayCount; |
loop.uiCyclesLeft = pSample->LoopPlayCount; |
175 |
} |
} |
176 |
else RAMLoop = false; |
else RAMLoop = false; |
177 |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no")); |
182 |
{ |
{ |
183 |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
184 |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
185 |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate())); |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate)); |
186 |
this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents |
this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents |
187 |
} |
} |
188 |
|
|
|
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
|
|
|
|
|
Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
|
|
|
|
|
Volume *= pDimRgn->SampleAttenuation; |
|
|
|
|
189 |
// 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 |
190 |
const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
191 |
|
|
209 |
} |
} |
210 |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; |
211 |
|
|
212 |
// calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG1 controller on EG1's parameters |
213 |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0; |
// (eg1attack is different from the others) |
214 |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0; |
double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? |
215 |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0; |
1 + 0.031 * (double) (pDimRgn->EG1ControllerAttackInfluence == 1 ? |
216 |
|
1 : 1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 1.0; |
217 |
pEG1->Trigger(pDimRgn->EG1PreAttack, |
double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; |
218 |
pDimRgn->EG1Attack + eg1attack, |
double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; |
219 |
pDimRgn->EG1Hold, |
|
220 |
pSample->LoopStart, |
EG1.trigger(pDimRgn->EG1PreAttack, |
221 |
(pDimRgn->EG1Decay1 + eg1decay) * velrelease, |
pDimRgn->EG1Attack * eg1attack, |
222 |
(pDimRgn->EG1Decay2 + eg1decay) * velrelease, |
pDimRgn->EG1Hold, |
223 |
pDimRgn->EG1InfiniteSustain, |
pDimRgn->EG1Decay1 * eg1decay * velrelease, |
224 |
pDimRgn->EG1Sustain, |
pDimRgn->EG1Decay2 * eg1decay * velrelease, |
225 |
(pDimRgn->EG1Release + eg1release) * velrelease, |
pDimRgn->EG1InfiniteSustain, |
226 |
// the SSE synthesis implementation requires |
pDimRgn->EG1Sustain, |
227 |
// the vca start to be 16 byte aligned |
pDimRgn->EG1Release * eg1release * velrelease, |
228 |
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
velocityAttenuation, |
229 |
Delay & 0xfffffffc : Delay, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
velocityAttenuation); |
|
230 |
} |
} |
231 |
|
|
232 |
|
|
250 |
} |
} |
251 |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; |
252 |
|
|
253 |
// calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned) |
// calculate influence of EG2 controller on EG2's parameters |
254 |
double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0; |
double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 1.0; |
255 |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0; |
double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 1.0; |
256 |
double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0; |
double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0; |
257 |
|
|
258 |
pEG2->Trigger(pDimRgn->EG2PreAttack, |
EG2.trigger(pDimRgn->EG2PreAttack, |
259 |
pDimRgn->EG2Attack + eg2attack, |
pDimRgn->EG2Attack * eg2attack, |
260 |
false, |
false, |
261 |
pSample->LoopStart, |
pDimRgn->EG2Decay1 * eg2decay * velrelease, |
262 |
(pDimRgn->EG2Decay1 + eg2decay) * velrelease, |
pDimRgn->EG2Decay2 * eg2decay * velrelease, |
263 |
(pDimRgn->EG2Decay2 + eg2decay) * velrelease, |
pDimRgn->EG2InfiniteSustain, |
264 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2Sustain, |
265 |
pDimRgn->EG2Sustain, |
pDimRgn->EG2Release * eg2release * velrelease, |
266 |
(pDimRgn->EG2Release + eg2release) * velrelease, |
velocityAttenuation, |
267 |
Delay, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
velocityAttenuation); |
|
268 |
} |
} |
269 |
|
|
270 |
|
|
271 |
// setup EG 3 (VCO EG) |
// setup EG 3 (VCO EG) |
272 |
{ |
{ |
273 |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
double eg3depth = RTMath::CentsToFreqRatio(pDimRgn->EG3Depth); |
274 |
pEG3->Trigger(eg3depth, pDimRgn->EG3Attack, Delay); |
EG3.trigger(eg3depth, pDimRgn->EG3Attack, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
275 |
} |
} |
276 |
|
|
277 |
|
|
282 |
case ::gig::lfo1_ctrl_internal: |
case ::gig::lfo1_ctrl_internal: |
283 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
284 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
285 |
|
bLFO1Enabled = (lfo1_internal_depth > 0); |
286 |
break; |
break; |
287 |
case ::gig::lfo1_ctrl_modwheel: |
case ::gig::lfo1_ctrl_modwheel: |
288 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
289 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
290 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
291 |
break; |
break; |
292 |
case ::gig::lfo1_ctrl_breath: |
case ::gig::lfo1_ctrl_breath: |
293 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
294 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
295 |
|
bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); |
296 |
break; |
break; |
297 |
case ::gig::lfo1_ctrl_internal_modwheel: |
case ::gig::lfo1_ctrl_internal_modwheel: |
298 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
299 |
pLFO1->ExtController = 1; // MIDI controller 1 |
pLFO1->ExtController = 1; // MIDI controller 1 |
300 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
301 |
break; |
break; |
302 |
case ::gig::lfo1_ctrl_internal_breath: |
case ::gig::lfo1_ctrl_internal_breath: |
303 |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
lfo1_internal_depth = pDimRgn->LFO1InternalDepth; |
304 |
pLFO1->ExtController = 2; // MIDI controller 2 |
pLFO1->ExtController = 2; // MIDI controller 2 |
305 |
|
bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); |
306 |
break; |
break; |
307 |
default: |
default: |
308 |
lfo1_internal_depth = 0; |
lfo1_internal_depth = 0; |
309 |
pLFO1->ExtController = 0; // no external controller |
pLFO1->ExtController = 0; // no external controller |
310 |
|
bLFO1Enabled = false; |
311 |
} |
} |
312 |
pLFO1->Trigger(pDimRgn->LFO1Frequency, |
if (bLFO1Enabled) pLFO1->trigger(pDimRgn->LFO1Frequency, |
313 |
lfo1_internal_depth, |
start_level_max, |
314 |
pDimRgn->LFO1ControlDepth, |
lfo1_internal_depth, |
315 |
pEngineChannel->ControllerTable[pLFO1->ExtController], |
pDimRgn->LFO1ControlDepth, |
316 |
pDimRgn->LFO1FlipPhase, |
pDimRgn->LFO1FlipPhase, |
317 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
318 |
} |
} |
319 |
|
|
320 |
|
|
325 |
case ::gig::lfo2_ctrl_internal: |
case ::gig::lfo2_ctrl_internal: |
326 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
327 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
328 |
|
bLFO2Enabled = (lfo2_internal_depth > 0); |
329 |
break; |
break; |
330 |
case ::gig::lfo2_ctrl_modwheel: |
case ::gig::lfo2_ctrl_modwheel: |
331 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
332 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
333 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
334 |
break; |
break; |
335 |
case ::gig::lfo2_ctrl_foot: |
case ::gig::lfo2_ctrl_foot: |
336 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
337 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
338 |
|
bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); |
339 |
break; |
break; |
340 |
case ::gig::lfo2_ctrl_internal_modwheel: |
case ::gig::lfo2_ctrl_internal_modwheel: |
341 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
342 |
pLFO2->ExtController = 1; // MIDI controller 1 |
pLFO2->ExtController = 1; // MIDI controller 1 |
343 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
344 |
break; |
break; |
345 |
case ::gig::lfo2_ctrl_internal_foot: |
case ::gig::lfo2_ctrl_internal_foot: |
346 |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
lfo2_internal_depth = pDimRgn->LFO2InternalDepth; |
347 |
pLFO2->ExtController = 4; // MIDI controller 4 |
pLFO2->ExtController = 4; // MIDI controller 4 |
348 |
|
bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); |
349 |
break; |
break; |
350 |
default: |
default: |
351 |
lfo2_internal_depth = 0; |
lfo2_internal_depth = 0; |
352 |
pLFO2->ExtController = 0; // no external controller |
pLFO2->ExtController = 0; // no external controller |
353 |
|
bLFO2Enabled = false; |
354 |
} |
} |
355 |
pLFO2->Trigger(pDimRgn->LFO2Frequency, |
if (bLFO2Enabled) pLFO2->trigger(pDimRgn->LFO2Frequency, |
356 |
lfo2_internal_depth, |
start_level_max, |
357 |
pDimRgn->LFO2ControlDepth, |
lfo2_internal_depth, |
358 |
pEngineChannel->ControllerTable[pLFO2->ExtController], |
pDimRgn->LFO2ControlDepth, |
359 |
pDimRgn->LFO2FlipPhase, |
pDimRgn->LFO2FlipPhase, |
360 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
361 |
} |
} |
362 |
|
|
363 |
|
|
368 |
case ::gig::lfo3_ctrl_internal: |
case ::gig::lfo3_ctrl_internal: |
369 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
370 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
371 |
|
bLFO3Enabled = (lfo3_internal_depth > 0); |
372 |
break; |
break; |
373 |
case ::gig::lfo3_ctrl_modwheel: |
case ::gig::lfo3_ctrl_modwheel: |
374 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
375 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
376 |
|
bLFO3Enabled = (pDimRgn->LFO3ControlDepth > 0); |
377 |
break; |
break; |
378 |
case ::gig::lfo3_ctrl_aftertouch: |
case ::gig::lfo3_ctrl_aftertouch: |
379 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
380 |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet |
381 |
|
bLFO3Enabled = false; // see TODO comment in line above |
382 |
break; |
break; |
383 |
case ::gig::lfo3_ctrl_internal_modwheel: |
case ::gig::lfo3_ctrl_internal_modwheel: |
384 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
385 |
pLFO3->ExtController = 1; // MIDI controller 1 |
pLFO3->ExtController = 1; // MIDI controller 1 |
386 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0); |
387 |
break; |
break; |
388 |
case ::gig::lfo3_ctrl_internal_aftertouch: |
case ::gig::lfo3_ctrl_internal_aftertouch: |
389 |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
lfo3_internal_depth = pDimRgn->LFO3InternalDepth; |
390 |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet |
391 |
|
bLFO3Enabled = (lfo3_internal_depth > 0 /*|| pDimRgn->LFO3ControlDepth > 0*/); // see TODO comment in line above |
392 |
break; |
break; |
393 |
default: |
default: |
394 |
lfo3_internal_depth = 0; |
lfo3_internal_depth = 0; |
395 |
pLFO3->ExtController = 0; // no external controller |
pLFO3->ExtController = 0; // no external controller |
396 |
|
bLFO3Enabled = false; |
397 |
} |
} |
398 |
pLFO3->Trigger(pDimRgn->LFO3Frequency, |
if (bLFO3Enabled) pLFO3->trigger(pDimRgn->LFO3Frequency, |
399 |
lfo3_internal_depth, |
start_level_mid, |
400 |
pDimRgn->LFO3ControlDepth, |
lfo3_internal_depth, |
401 |
pEngineChannel->ControllerTable[pLFO3->ExtController], |
pDimRgn->LFO3ControlDepth, |
402 |
false, |
false, |
403 |
pEngine->SampleRate, |
pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
Delay); |
|
404 |
} |
} |
405 |
|
|
406 |
|
|
473 |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
#endif // CONFIG_OVERRIDE_RESONANCE_CTRL |
474 |
|
|
475 |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
#ifndef CONFIG_OVERRIDE_FILTER_TYPE |
476 |
FilterLeft.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); |
477 |
FilterRight.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); |
478 |
#else // override filter type |
#else // override filter type |
479 |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
480 |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
484 |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; |
485 |
|
|
486 |
// calculate cutoff frequency |
// calculate cutoff frequency |
487 |
float cutoff = (!VCFCutoffCtrl.controller) |
float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity); |
488 |
? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX |
if (pDimRgn->VCFKeyboardTracking) { |
489 |
: exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX; |
cutoff *= exp((itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.057762265f); // (ln(2) / 12) |
490 |
|
} |
491 |
|
CutoffBase = cutoff; |
492 |
|
|
493 |
|
int cvalue; |
494 |
|
if (VCFCutoffCtrl.controller) { |
495 |
|
cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
496 |
|
if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; |
497 |
|
if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; |
498 |
|
} |
499 |
|
else { |
500 |
|
cvalue = pDimRgn->VCFCutoff; |
501 |
|
} |
502 |
|
cutoff *= float(cvalue) * 0.00787402f; // (1 / 127) |
503 |
|
if (cutoff > 1.0) cutoff = 1.0; |
504 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN; |
505 |
|
|
506 |
// calculate resonance |
// calculate resonance |
507 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 |
512 |
|
|
513 |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; |
514 |
VCFResonanceCtrl.fvalue = resonance; |
VCFResonanceCtrl.fvalue = resonance; |
|
|
|
|
FilterUpdateCounter = -1; |
|
515 |
} |
} |
516 |
else { |
else { |
517 |
VCFCutoffCtrl.controller = 0; |
VCFCutoffCtrl.controller = 0; |
535 |
void Voice::Render(uint Samples) { |
void Voice::Render(uint Samples) { |
536 |
|
|
537 |
// select default values for synthesis mode bits |
// select default values for synthesis mode bits |
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, (PitchBase * PitchBend) != 1.0f); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, true); |
|
538 |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false); |
539 |
|
|
|
// Reset the synthesis parameter matrix |
|
|
|
|
|
pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume); |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase); |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue); |
|
|
pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue); |
|
|
|
|
|
// Apply events to the synthesis parameter matrix |
|
|
ProcessEvents(Samples); |
|
|
|
|
|
// Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment |
|
|
pEG1->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent); |
|
|
pEG2->Process(Samples, pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend); |
|
|
if (pEG3->Process(Samples)) { // if pitch EG is active |
|
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
|
|
} |
|
|
pLFO1->Process(Samples); |
|
|
pLFO2->Process(Samples); |
|
|
if (pLFO3->Process(Samples)) { // if pitch LFO modulation is active |
|
|
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
|
|
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
|
|
} |
|
|
|
|
|
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) |
|
|
CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters |
|
|
|
|
540 |
switch (this->PlaybackState) { |
switch (this->PlaybackState) { |
541 |
|
|
542 |
case playback_state_init: |
case playback_state_init: |
551 |
|
|
552 |
if (DiskVoice) { |
if (DiskVoice) { |
553 |
// check if we reached the allowed limit of the sample RAM cache |
// check if we reached the allowed limit of the sample RAM cache |
554 |
if (Pos > MaxRAMPos) { |
if (finalSynthesisParameters.dPos > MaxRAMPos) { |
555 |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos)); |
dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos)); |
556 |
this->PlaybackState = playback_state_disk; |
this->PlaybackState = playback_state_disk; |
557 |
} |
} |
558 |
} |
} else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) { |
|
559 |
this->PlaybackState = playback_state_end; |
this->PlaybackState = playback_state_end; |
560 |
} |
} |
561 |
} |
} |
570 |
KillImmediately(); |
KillImmediately(); |
571 |
return; |
return; |
572 |
} |
} |
573 |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos)); |
DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(finalSynthesisParameters.dPos) - MaxRAMPos)); |
574 |
Pos -= int(Pos); |
finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos); |
575 |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet |
576 |
} |
} |
577 |
|
|
592 |
// render current audio fragment |
// render current audio fragment |
593 |
Synthesize(Samples, ptr, Delay); |
Synthesize(Samples, ptr, Delay); |
594 |
|
|
595 |
const int iPos = (int) Pos; |
const int iPos = (int) finalSynthesisParameters.dPos; |
596 |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read |
597 |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
DiskStreamRef.pStream->IncrementReadPos(readSampleWords); |
598 |
Pos -= iPos; // just keep fractional part of Pos |
finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position |
599 |
|
|
600 |
// change state of voice to 'end' if we really reached the end of the sample data |
// change state of voice to 'end' if we really reached the end of the sample data |
601 |
if (RealSampleWordsLeftToRead >= 0) { |
if (RealSampleWordsLeftToRead >= 0) { |
610 |
break; |
break; |
611 |
} |
} |
612 |
|
|
|
// Reset synthesis event lists (except VCO, as VCO events apply channel wide currently) |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear(); |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear(); |
|
|
pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear(); |
|
|
|
|
613 |
// Reset delay |
// Reset delay |
614 |
Delay = 0; |
Delay = 0; |
615 |
|
|
616 |
itTriggerEvent = Pool<Event>::Iterator(); |
itTriggerEvent = Pool<Event>::Iterator(); |
617 |
|
|
618 |
// If sample stream or release stage finished, kill the voice |
// If sample stream or release stage finished, kill the voice |
619 |
if (PlaybackState == playback_state_end || pEG1->GetStage() == EGADSR::stage_end) KillImmediately(); |
if (PlaybackState == playback_state_end || EG1.getSegmentType() == EGADSR::segment_end) KillImmediately(); |
620 |
} |
} |
621 |
|
|
622 |
/** |
/** |
624 |
* suspended / not running. |
* suspended / not running. |
625 |
*/ |
*/ |
626 |
void Voice::Reset() { |
void Voice::Reset() { |
627 |
pLFO1->Reset(); |
finalSynthesisParameters.filterLeft.Reset(); |
628 |
pLFO2->Reset(); |
finalSynthesisParameters.filterRight.Reset(); |
|
pLFO3->Reset(); |
|
|
FilterLeft.Reset(); |
|
|
FilterRight.Reset(); |
|
629 |
DiskStreamRef.pStream = NULL; |
DiskStreamRef.pStream = NULL; |
630 |
DiskStreamRef.hStream = 0; |
DiskStreamRef.hStream = 0; |
631 |
DiskStreamRef.State = Stream::state_unused; |
DiskStreamRef.State = Stream::state_unused; |
636 |
} |
} |
637 |
|
|
638 |
/** |
/** |
639 |
* Process the control change event lists of the engine for the current |
* Process given list of MIDI note on, note off and sustain pedal events |
640 |
* audio fragment. Event values will be applied to the synthesis parameter |
* for the given time. |
|
* matrix. |
|
641 |
* |
* |
642 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
* @param itEvent - iterator pointing to the next event to be processed |
643 |
|
* @param End - youngest time stamp where processing should be stopped |
644 |
*/ |
*/ |
645 |
void Voice::ProcessEvents(uint Samples) { |
void Voice::processTransitionEvents(RTList<Event>::Iterator& itEvent, uint End) { |
646 |
|
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
647 |
|
if (itEvent->Type == Event::type_release) { |
648 |
|
EG1.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
649 |
|
EG2.update(EGADSR::event_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
650 |
|
} else if (itEvent->Type == Event::type_cancel_release) { |
651 |
|
EG1.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
652 |
|
EG2.update(EGADSR::event_cancel_release, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
653 |
|
} |
654 |
|
} |
655 |
|
} |
656 |
|
|
657 |
// dispatch control change events |
/** |
658 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pCCEvents->first(); |
* Process given list of MIDI control change and pitch bend events for |
659 |
if (Delay) { // skip events that happened before this voice was triggered |
* the given time. |
660 |
while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent; |
* |
661 |
} |
* @param itEvent - iterator pointing to the next event to be processed |
662 |
while (itCCEvent) { |
* @param End - youngest time stamp where processing should be stopped |
663 |
if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller |
*/ |
664 |
if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
void Voice::processCCEvents(RTList<Event>::Iterator& itEvent, uint End) { |
665 |
*pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent; |
for (; itEvent && itEvent->FragmentPos() <= End; ++itEvent) { |
666 |
} |
if (itEvent->Type == Event::type_control_change && |
667 |
if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
itEvent->Param.CC.Controller) { // if (valid) MIDI control change event |
668 |
*pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent; |
if (itEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { |
669 |
|
processCutoffEvent(itEvent); |
670 |
|
} |
671 |
|
if (itEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { |
672 |
|
processResonanceEvent(itEvent); |
673 |
} |
} |
674 |
if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO1->ExtController) { |
675 |
pLFO1->SendEvent(itCCEvent); |
pLFO1->update(itEvent->Param.CC.Value); |
676 |
} |
} |
677 |
if (itCCEvent->Param.CC.Controller == pLFO2->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO2->ExtController) { |
678 |
pLFO2->SendEvent(itCCEvent); |
pLFO2->update(itEvent->Param.CC.Value); |
679 |
} |
} |
680 |
if (itCCEvent->Param.CC.Controller == pLFO3->ExtController) { |
if (itEvent->Param.CC.Controller == pLFO3->ExtController) { |
681 |
pLFO3->SendEvent(itCCEvent); |
pLFO3->update(itEvent->Param.CC.Value); |
682 |
} |
} |
683 |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && |
684 |
itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event |
itEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { |
685 |
*pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent; |
processCrossFadeEvent(itEvent); |
686 |
} |
} |
687 |
|
} else if (itEvent->Type == Event::type_pitchbend) { // if pitch bend event |
688 |
|
processPitchEvent(itEvent); |
689 |
} |
} |
690 |
|
} |
691 |
|
} |
692 |
|
|
693 |
|
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
694 |
|
const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
695 |
|
finalSynthesisParameters.fFinalPitch *= pitch; |
696 |
|
PitchBend = pitch; |
697 |
|
} |
698 |
|
|
699 |
|
void Voice::processCrossFadeEvent(RTList<Event>::Iterator& itEvent) { |
700 |
|
CrossfadeVolume = CrossfadeAttenuation(itEvent->Param.CC.Value); |
701 |
|
#if CONFIG_PROCESS_MUTED_CHANNELS |
702 |
|
const float effectiveVolume = CrossfadeVolume * Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
703 |
|
#else |
704 |
|
const float effectiveVolume = CrossfadeVolume * Volume * pEngineChannel->GlobalVolume; |
705 |
|
#endif |
706 |
|
fFinalVolume = effectiveVolume; |
707 |
|
} |
708 |
|
|
709 |
|
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
710 |
|
int ccvalue = itEvent->Param.CC.Value; |
711 |
|
if (VCFCutoffCtrl.value == ccvalue) return; |
712 |
|
VCFCutoffCtrl.value == ccvalue; |
713 |
|
if (pDimRgn->VCFCutoffControllerInvert) ccvalue = 127 - ccvalue; |
714 |
|
if (ccvalue < pDimRgn->VCFVelocityScale) ccvalue = pDimRgn->VCFVelocityScale; |
715 |
|
float cutoff = CutoffBase * float(ccvalue) * 0.00787402f; // (1 / 127) |
716 |
|
if (cutoff > 1.0) cutoff = 1.0; |
717 |
|
cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN; |
718 |
|
VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of fFinalCutoff next time |
719 |
|
fFinalCutoff = cutoff; |
720 |
|
} |
721 |
|
|
722 |
|
void Voice::processResonanceEvent(RTList<Event>::Iterator& itEvent) { |
723 |
|
// convert absolute controller value to differential |
724 |
|
const int ctrldelta = itEvent->Param.CC.Value - VCFResonanceCtrl.value; |
725 |
|
VCFResonanceCtrl.value = itEvent->Param.CC.Value; |
726 |
|
const float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0 |
727 |
|
fFinalResonance += resonancedelta; |
728 |
|
// needed for initialization of parameter |
729 |
|
VCFResonanceCtrl.fvalue = itEvent->Param.CC.Value * 0.00787f; |
730 |
|
} |
731 |
|
|
732 |
++itCCEvent; |
/** |
733 |
|
* Synthesizes the current audio fragment for this voice. |
734 |
|
* |
735 |
|
* @param Samples - number of sample points to be rendered in this audio |
736 |
|
* fragment cycle |
737 |
|
* @param pSrc - pointer to input sample data |
738 |
|
* @param Skip - number of sample points to skip in output buffer |
739 |
|
*/ |
740 |
|
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
741 |
|
finalSynthesisParameters.pOutLeft = &pEngineChannel->pOutputLeft[Skip]; |
742 |
|
finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip]; |
743 |
|
finalSynthesisParameters.pSrc = pSrc; |
744 |
|
|
745 |
|
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
746 |
|
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
747 |
|
|
748 |
|
if (Skip) { // skip events that happened before this voice was triggered |
749 |
|
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
750 |
|
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
751 |
} |
} |
752 |
|
|
753 |
|
uint i = Skip; |
754 |
|
while (i < Samples) { |
755 |
|
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
756 |
|
|
757 |
// process pitch events |
// initialize all final synthesis parameters |
758 |
{ |
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
759 |
RTList<Event>* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco]; |
#if CONFIG_PROCESS_MUTED_CHANNELS |
760 |
RTList<Event>::Iterator itVCOEvent = pVCOEventList->first(); |
fFinalVolume = this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); |
761 |
if (Delay) { // skip events that happened before this voice was triggered |
#else |
762 |
while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent; |
fFinalVolume = this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume; |
763 |
} |
#endif |
764 |
// apply old pitchbend value until first pitch event occurs |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
765 |
if (this->PitchBend != 1.0) { |
fFinalResonance = VCFResonanceCtrl.fvalue; |
766 |
uint end = (itVCOEvent) ? itVCOEvent->FragmentPos() : Samples; |
|
767 |
for (uint i = Delay; i < end; i++) { |
// process MIDI control change and pitchbend events for this subfragment |
768 |
pEngine->pSynthesisParameters[Event::destination_vco][i] *= this->PitchBend; |
processCCEvents(itCCEvent, iSubFragmentEnd); |
769 |
} |
|
770 |
} |
// process transition events (note on, note off & sustain pedal) |
771 |
float pitch; |
processTransitionEvents(itNoteEvent, iSubFragmentEnd); |
|
while (itVCOEvent) { |
|
|
RTList<Event>::Iterator itNextVCOEvent = itVCOEvent; |
|
|
++itNextVCOEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextVCOEvent) ? itNextVCOEvent->FragmentPos() : Samples; |
|
|
|
|
|
pitch = RTMath::CentsToFreqRatio(((double) itVCOEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents |
|
|
|
|
|
// apply pitch value to the pitch parameter sequence |
|
|
for (uint i = itVCOEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vco][i] *= pitch; |
|
|
} |
|
772 |
|
|
773 |
itVCOEvent = itNextVCOEvent; |
// process envelope generators |
774 |
|
switch (EG1.getSegmentType()) { |
775 |
|
case EGADSR::segment_lin: |
776 |
|
fFinalVolume *= EG1.processLin(); |
777 |
|
break; |
778 |
|
case EGADSR::segment_exp: |
779 |
|
fFinalVolume *= EG1.processExp(); |
780 |
|
break; |
781 |
|
case EGADSR::segment_end: |
782 |
|
fFinalVolume *= EG1.getLevel(); |
783 |
|
break; // noop |
784 |
} |
} |
785 |
if (!pVCOEventList->isEmpty()) { |
switch (EG2.getSegmentType()) { |
786 |
this->PitchBend = pitch; |
case EGADSR::segment_lin: |
787 |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, true); |
fFinalCutoff *= EG2.processLin(); |
788 |
SYNTHESIS_MODE_SET_CONSTPITCH(SynthesisMode, false); |
break; |
789 |
|
case EGADSR::segment_exp: |
790 |
|
fFinalCutoff *= EG2.processExp(); |
791 |
|
break; |
792 |
|
case EGADSR::segment_end: |
793 |
|
fFinalCutoff *= EG2.getLevel(); |
794 |
|
break; // noop |
795 |
} |
} |
796 |
} |
if (EG3.active()) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(EG3.render()); |
797 |
|
|
798 |
// process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !) |
// process low frequency oscillators |
799 |
{ |
if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); |
800 |
RTList<Event>* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca]; |
if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); |
801 |
RTList<Event>::Iterator itVCAEvent = pVCAEventList->first(); |
if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); |
|
if (Delay) { // skip events that happened before this voice was triggered |
|
|
while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent; |
|
|
} |
|
|
float crossfadevolume; |
|
|
while (itVCAEvent) { |
|
|
RTList<Event>::Iterator itNextVCAEvent = itVCAEvent; |
|
|
++itNextVCAEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextVCAEvent) ? itNextVCAEvent->FragmentPos() : Samples; |
|
|
|
|
|
crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value); |
|
|
|
|
|
float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume; |
|
|
|
|
|
// apply volume value to the volume parameter sequence |
|
|
for (uint i = itVCAEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume; |
|
|
} |
|
802 |
|
|
803 |
itVCAEvent = itNextVCAEvent; |
// if filter enabled then update filter coefficients |
804 |
|
if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) { |
805 |
|
finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
806 |
|
finalSynthesisParameters.filterRight.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate); |
807 |
} |
} |
|
if (!pVCAEventList->isEmpty()) this->CrossfadeVolume = crossfadevolume; |
|
|
} |
|
808 |
|
|
809 |
// process filter cutoff events |
// do we need resampling? |
810 |
{ |
const float __PLUS_ONE_CENT = 1.000577789506554859250142541782224725466f; |
811 |
RTList<Event>* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc]; |
const float __MINUS_ONE_CENT = 0.9994225441413807496009516495583113737666f; |
812 |
RTList<Event>::Iterator itCutoffEvent = pCutoffEventList->first(); |
const bool bResamplingRequired = !(finalSynthesisParameters.fFinalPitch <= __PLUS_ONE_CENT && |
813 |
if (Delay) { // skip events that happened before this voice was triggered |
finalSynthesisParameters.fFinalPitch >= __MINUS_ONE_CENT); |
814 |
while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent; |
SYNTHESIS_MODE_SET_INTERPOLATE(SynthesisMode, bResamplingRequired); |
|
} |
|
|
float cutoff; |
|
|
while (itCutoffEvent) { |
|
|
RTList<Event>::Iterator itNextCutoffEvent = itCutoffEvent; |
|
|
++itNextCutoffEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextCutoffEvent) ? itNextCutoffEvent->FragmentPos() : Samples; |
|
|
|
|
|
cutoff = exp((float) itCutoffEvent->Param.CC.Value * 0.00787402f * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MAX - CONFIG_FILTER_CUTOFF_MIN; |
|
|
|
|
|
// apply cutoff frequency to the cutoff parameter sequence |
|
|
for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfc][i] = cutoff; |
|
|
} |
|
815 |
|
|
816 |
itCutoffEvent = itNextCutoffEvent; |
// prepare final synthesis parameters structure |
817 |
} |
finalSynthesisParameters.fFinalVolumeLeft = fFinalVolume * PanLeft; |
818 |
if (!pCutoffEventList->isEmpty()) VCFCutoffCtrl.fvalue = cutoff; // needed for initialization of parameter matrix next time |
finalSynthesisParameters.fFinalVolumeRight = fFinalVolume * PanRight; |
819 |
} |
finalSynthesisParameters.uiToGo = iSubFragmentEnd - i; |
820 |
|
|
821 |
// process filter resonance events |
// render audio for one subfragment |
822 |
{ |
RunSynthesisFunction(SynthesisMode, &finalSynthesisParameters, &loop); |
|
RTList<Event>* pResonanceEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfr]; |
|
|
RTList<Event>::Iterator itResonanceEvent = pResonanceEventList->first(); |
|
|
if (Delay) { // skip events that happened before this voice was triggered |
|
|
while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent; |
|
|
} |
|
|
while (itResonanceEvent) { |
|
|
RTList<Event>::Iterator itNextResonanceEvent = itResonanceEvent; |
|
|
++itNextResonanceEvent; |
|
|
|
|
|
// calculate the influence length of this event (in sample points) |
|
|
uint end = (itNextResonanceEvent) ? itNextResonanceEvent->FragmentPos() : Samples; |
|
|
|
|
|
// convert absolute controller value to differential |
|
|
int ctrldelta = itResonanceEvent->Param.CC.Value - VCFResonanceCtrl.value; |
|
|
VCFResonanceCtrl.value = itResonanceEvent->Param.CC.Value; |
|
|
|
|
|
float resonancedelta = (float) ctrldelta * 0.00787f; // 0.0..1.0 |
|
|
|
|
|
// apply cutoff frequency to the cutoff parameter sequence |
|
|
for (uint i = itResonanceEvent->FragmentPos(); i < end; i++) { |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfr][i] += resonancedelta; |
|
|
} |
|
823 |
|
|
824 |
itResonanceEvent = itNextResonanceEvent; |
const double newPos = Pos + (iSubFragmentEnd - i) * finalSynthesisParameters.fFinalPitch; |
|
} |
|
|
if (!pResonanceEventList->isEmpty()) VCFResonanceCtrl.fvalue = pResonanceEventList->last()->Param.CC.Value * 0.00787f; // needed for initialization of parameter matrix next time |
|
|
} |
|
|
} |
|
825 |
|
|
826 |
/** |
// increment envelopes' positions |
827 |
* Calculate all necessary, final biquad filter parameters. |
if (EG1.active()) { |
828 |
* |
|
829 |
* @param Samples - number of samples to be rendered in this audio fragment cycle |
// if sample has a loop and loop start has been reached in this subfragment, send a special event to EG1 to let it finish the attack hold stage |
830 |
*/ |
if (pSample->Loops && Pos <= pSample->LoopStart && pSample->LoopStart < newPos) { |
831 |
void Voice::CalculateBiquadParameters(uint Samples) { |
EG1.update(EGADSR::event_hold_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
|
biquad_param_t bqbase; |
|
|
biquad_param_t bqmain; |
|
|
float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0]; |
|
|
float prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][0]; |
|
|
FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
pEngine->pBasicFilterParameters[0] = bqbase; |
|
|
pEngine->pMainFilterParameters[0] = bqmain; |
|
|
|
|
|
float* bq; |
|
|
for (int i = 1; i < Samples; i++) { |
|
|
// recalculate biquad parameters if cutoff or resonance differ from previous sample point |
|
|
if (!(i & FILTER_UPDATE_MASK)) { |
|
|
if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res || |
|
|
pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) |
|
|
{ |
|
|
prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i]; |
|
|
prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i]; |
|
|
FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
|
FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + CONFIG_FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); |
|
832 |
} |
} |
833 |
|
|
834 |
|
EG1.increment(1); |
835 |
|
if (!EG1.toStageEndLeft()) EG1.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
836 |
} |
} |
837 |
|
if (EG2.active()) { |
838 |
|
EG2.increment(1); |
839 |
|
if (!EG2.toStageEndLeft()) EG2.update(EGADSR::event_stage_end, pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
840 |
|
} |
841 |
|
EG3.increment(1); |
842 |
|
if (!EG3.toEndLeft()) EG3.update(); // neutralize envelope coefficient if end reached |
843 |
|
|
844 |
//same as 'pEngine->pBasicFilterParameters[i] = bqbase;' |
Pos = newPos; |
845 |
bq = (float*) &pEngine->pBasicFilterParameters[i]; |
i = iSubFragmentEnd; |
|
bq[0] = bqbase.b0; |
|
|
bq[1] = bqbase.b1; |
|
|
bq[2] = bqbase.b2; |
|
|
bq[3] = bqbase.a1; |
|
|
bq[4] = bqbase.a2; |
|
|
|
|
|
// same as 'pEngine->pMainFilterParameters[i] = bqmain;' |
|
|
bq = (float*) &pEngine->pMainFilterParameters[i]; |
|
|
bq[0] = bqmain.b0; |
|
|
bq[1] = bqmain.b1; |
|
|
bq[2] = bqmain.b2; |
|
|
bq[3] = bqmain.a1; |
|
|
bq[4] = bqmain.a2; |
|
846 |
} |
} |
847 |
} |
} |
848 |
|
|
849 |
/** |
/** |
|
* Synthesizes the current audio fragment for this voice. |
|
|
* |
|
|
* @param Samples - number of sample points to be rendered in this audio |
|
|
* fragment cycle |
|
|
* @param pSrc - pointer to input sample data |
|
|
* @param Skip - number of sample points to skip in output buffer |
|
|
*/ |
|
|
void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { |
|
|
RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); |
|
|
} |
|
|
|
|
|
/** |
|
850 |
* Immediately kill the voice. This method should not be used to kill |
* Immediately kill the voice. This method should not be used to kill |
851 |
* a normal, active voice, because it doesn't take care of things like |
* a normal, active voice, because it doesn't take care of things like |
852 |
* fading down the volume level to avoid clicks and regular processing |
* fading down the volume level to avoid clicks and regular processing |