61 |
KeyGroup = 0; |
KeyGroup = 0; |
62 |
SynthesisMode = 0; // set all mode bits to 0 first |
SynthesisMode = 0; // set all mode bits to 0 first |
63 |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
// select synthesis implementation (currently either pure C++ or MMX+SSE(1)) |
64 |
#if ARCH_X86 |
#if CONFIG_ASM && ARCH_X86 |
65 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); |
66 |
#else |
#else |
67 |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); |
117 |
* Initializes and triggers the voice, a disk stream will be launched if |
* Initializes and triggers the voice, a disk stream will be launched if |
118 |
* needed. |
* needed. |
119 |
* |
* |
120 |
* @param pEngineChannel - engine channel on which this voice was ordered |
* @param pEngineChannel - engine channel on which this voice was ordered |
121 |
* @param itNoteOnEvent - event that caused triggering of this voice |
* @param itNoteOnEvent - event that caused triggering of this voice |
122 |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
* @param PitchBend - MIDI detune factor (-8192 ... +8191) |
123 |
* @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 |
124 |
* @param iLayer - layer number this voice refers to (only if this is a layered sound of course) |
* @param VoiceType - type of this voice |
125 |
* @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 |
|
126 |
* @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 |
127 |
* (either due to an error or e.g. because no region is |
* (either due to an error or e.g. because no region is |
128 |
* defined for the given key) |
* defined for the given key) |
129 |
*/ |
*/ |
130 |
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) { |
131 |
this->pEngineChannel = pEngineChannel; |
this->pEngineChannel = pEngineChannel; |
132 |
if (!pInstrument) { |
this->pDimRgn = pDimRgn; |
133 |
dmsg(1,("voice::trigger: !pInstrument\n")); |
|
134 |
exit(EXIT_FAILURE); |
#if CONFIG_DEVMODE |
135 |
} |
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging |
|
if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging) |
|
136 |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); |
137 |
} |
} |
138 |
|
#endif // CONFIG_DEVMODE |
139 |
|
|
140 |
Type = type_normal; |
Type = VoiceType; |
141 |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
MIDIKey = itNoteOnEvent->Param.Note.Key; |
142 |
pRegion = pInstrument->GetRegion(MIDIKey); |
PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet |
|
PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
|
143 |
Delay = itNoteOnEvent->FragmentPos(); |
Delay = itNoteOnEvent->FragmentPos(); |
144 |
itTriggerEvent = itNoteOnEvent; |
itTriggerEvent = itNoteOnEvent; |
145 |
itKillEvent = Pool<Event>::Iterator(); |
itKillEvent = Pool<Event>::Iterator(); |
146 |
|
KeyGroup = iKeyGroup; |
147 |
|
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
148 |
|
|
149 |
if (!pRegion) { |
// calculate volume |
150 |
dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey)); |
const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); |
|
return -1; |
|
|
} |
|
151 |
|
|
152 |
// 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; |
|
153 |
|
|
154 |
// 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); |
|
155 |
|
|
156 |
pSample = pDimRgn->pSample; // sample won't change until the voice is finished |
// the volume of release triggered samples depends on note length |
157 |
if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent |
if (Type == type_release_trigger) { |
158 |
|
float noteLength = float(pEngine->FrameTime + Delay - |
159 |
|
pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; |
160 |
|
float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; |
161 |
|
if (attenuation <= 0) return -1; |
162 |
|
Volume *= attenuation; |
163 |
|
} |
164 |
|
|
165 |
// select channel mode (mono or stereo) |
// select channel mode (mono or stereo) |
166 |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); |
226 |
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 |
227 |
} |
} |
228 |
|
|
229 |
Volume = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity) / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) |
// the length of the decay and release curves are dependent on the velocity |
230 |
|
const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); |
|
Volume *= pDimRgn->SampleAttenuation; |
|
231 |
|
|
232 |
// setup EG 1 (VCA EG) |
// setup EG 1 (VCA EG) |
233 |
{ |
{ |
258 |
pDimRgn->EG1Attack + eg1attack, |
pDimRgn->EG1Attack + eg1attack, |
259 |
pDimRgn->EG1Hold, |
pDimRgn->EG1Hold, |
260 |
pSample->LoopStart, |
pSample->LoopStart, |
261 |
pDimRgn->EG1Decay1 + eg1decay, |
(pDimRgn->EG1Decay1 + eg1decay) * velrelease, |
262 |
pDimRgn->EG1Decay2 + eg1decay, |
(pDimRgn->EG1Decay2 + eg1decay) * velrelease, |
263 |
pDimRgn->EG1InfiniteSustain, |
pDimRgn->EG1InfiniteSustain, |
264 |
pDimRgn->EG1Sustain, |
pDimRgn->EG1Sustain, |
265 |
pDimRgn->EG1Release + eg1release, |
(pDimRgn->EG1Release + eg1release) * velrelease, |
266 |
// the SSE synthesis implementation requires |
// the SSE synthesis implementation requires |
267 |
// the vca start to be 16 byte aligned |
// the vca start to be 16 byte aligned |
268 |
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? |
269 |
Delay & 0xfffffffc : Delay); |
Delay & 0xfffffffc : Delay, |
270 |
|
velocityAttenuation); |
271 |
} |
} |
272 |
|
|
273 |
|
|
300 |
pDimRgn->EG2Attack + eg2attack, |
pDimRgn->EG2Attack + eg2attack, |
301 |
false, |
false, |
302 |
pSample->LoopStart, |
pSample->LoopStart, |
303 |
pDimRgn->EG2Decay1 + eg2decay, |
(pDimRgn->EG2Decay1 + eg2decay) * velrelease, |
304 |
pDimRgn->EG2Decay2 + eg2decay, |
(pDimRgn->EG2Decay2 + eg2decay) * velrelease, |
305 |
pDimRgn->EG2InfiniteSustain, |
pDimRgn->EG2InfiniteSustain, |
306 |
pDimRgn->EG2Sustain, |
pDimRgn->EG2Sustain, |
307 |
pDimRgn->EG2Release + eg2release, |
(pDimRgn->EG2Release + eg2release) * velrelease, |
308 |
Delay); |
Delay, |
309 |
|
velocityAttenuation); |
310 |
} |
} |
311 |
|
|
312 |
|
|
582 |
|
|
583 |
switch (this->PlaybackState) { |
switch (this->PlaybackState) { |
584 |
|
|
585 |
|
case playback_state_init: |
586 |
|
this->PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed |
587 |
|
// no break - continue with playback_state_ram |
588 |
|
|
589 |
case playback_state_ram: { |
case playback_state_ram: { |
590 |
if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping |
if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping |
591 |
|
|