--- linuxsampler/trunk/src/engines/gig/Voice.cpp 2005/01/01 03:06:06 332 +++ linuxsampler/trunk/src/engines/gig/Voice.cpp 2005/07/26 11:18:46 729 @@ -3,6 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * + * Copyright (C) 2005 Christian Schoenebeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -34,13 +35,13 @@ const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask()); float Voice::CalculateFilterCutoffCoeff() { - return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX); + return log(CONFIG_FILTER_CUTOFF_MAX / CONFIG_FILTER_CUTOFF_MIN); } int Voice::CalculateFilterUpdateMask() { - if (FILTER_UPDATE_PERIOD <= 0) return 0; + if (CONFIG_FILTER_UPDATE_STEPS <= 0) return 0; int power_of_two; - for (power_of_two = 0; 1< 0 defines a key group in which this voice is member of + * @returns 0 on success, a value < 0 if the voice wasn't triggered + * (either due to an error or e.g. because no region is + * defined for the given key) */ - int Voice::Trigger(Pool::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { - if (!pInstrument) { - dmsg(1,("voice::trigger: !pInstrument\n")); - exit(EXIT_FAILURE); - } - if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // FIXME: should be removed before the final release (purpose: just a sanity check for debugging) + int Voice::Trigger(EngineChannel* pEngineChannel, Pool::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup) { + this->pEngineChannel = pEngineChannel; + this->pDimRgn = pDimRgn; + + #if CONFIG_DEVMODE + if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging dmsg(1,("Voice::Trigger(): ERROR, TriggerDelay > Totalsamples\n")); } + #endif // CONFIG_DEVMODE - Type = type_normal; + Type = VoiceType; MIDIKey = itNoteOnEvent->Param.Note.Key; - pRegion = pInstrument->GetRegion(MIDIKey); - PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed + PlaybackState = playback_state_init; // mark voice as triggered, but no audio rendered yet Delay = itNoteOnEvent->FragmentPos(); itTriggerEvent = itNoteOnEvent; itKillEvent = Pool::Iterator(); - itChildVoice = Pool::Iterator(); + KeyGroup = iKeyGroup; + pSample = pDimRgn->pSample; // sample won't change until the voice is finished - if (!pRegion) { - std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush; - KillImmediately(); - return -1; - } + // calculate volume + const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); - KeyGroup = pRegion->KeyGroup; + Volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) - // get current dimension values to select the right dimension region - //FIXME: controller values for selecting the dimension region here are currently not sample accurate - uint DimValues[5] = {0,0,0,0,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; - // if this is the 1st layer then spawn further voices for all the other layers - if (iLayer == 0) - for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++) - itChildVoice = pEngine->LaunchVoice(itNoteOnEvent, iNewLayer, ReleaseTriggerVoice, VoiceStealing); - 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) itNoteOnEvent->Param.Note.Key; - break; - case ::gig::dimension_modwheel: - DimValues[i] = pEngine->ControllerTable[1]; - break; - case ::gig::dimension_breath: - DimValues[i] = pEngine->ControllerTable[2]; - break; - case ::gig::dimension_foot: - DimValues[i] = pEngine->ControllerTable[4]; - break; - case ::gig::dimension_portamentotime: - DimValues[i] = pEngine->ControllerTable[5]; - break; - case ::gig::dimension_effect1: - DimValues[i] = pEngine->ControllerTable[12]; - break; - case ::gig::dimension_effect2: - DimValues[i] = pEngine->ControllerTable[13]; - break; - case ::gig::dimension_genpurpose1: - DimValues[i] = pEngine->ControllerTable[16]; - break; - case ::gig::dimension_genpurpose2: - DimValues[i] = pEngine->ControllerTable[17]; - break; - case ::gig::dimension_genpurpose3: - DimValues[i] = pEngine->ControllerTable[18]; - break; - case ::gig::dimension_genpurpose4: - DimValues[i] = pEngine->ControllerTable[19]; - break; - case ::gig::dimension_sustainpedal: - DimValues[i] = pEngine->ControllerTable[64]; - break; - case ::gig::dimension_portamento: - DimValues[i] = pEngine->ControllerTable[65]; - break; - case ::gig::dimension_sostenutopedal: - DimValues[i] = pEngine->ControllerTable[66]; - break; - case ::gig::dimension_softpedal: - DimValues[i] = pEngine->ControllerTable[67]; - break; - case ::gig::dimension_genpurpose5: - DimValues[i] = pEngine->ControllerTable[80]; - break; - case ::gig::dimension_genpurpose6: - DimValues[i] = pEngine->ControllerTable[81]; - break; - case ::gig::dimension_genpurpose7: - DimValues[i] = pEngine->ControllerTable[82]; - break; - case ::gig::dimension_genpurpose8: - DimValues[i] = pEngine->ControllerTable[83]; - break; - case ::gig::dimension_effect1depth: - DimValues[i] = pEngine->ControllerTable[91]; - break; - case ::gig::dimension_effect2depth: - DimValues[i] = pEngine->ControllerTable[92]; - break; - case ::gig::dimension_effect3depth: - DimValues[i] = pEngine->ControllerTable[93]; - break; - case ::gig::dimension_effect4depth: - DimValues[i] = pEngine->ControllerTable[94]; - break; - case ::gig::dimension_effect5depth: - DimValues[i] = pEngine->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; - } + Volume *= pDimRgn->SampleAttenuation; + + // the volume of release triggered samples depends on note length + if (Type == type_release_trigger) { + float noteLength = float(pEngine->FrameTime + Delay - + pEngineChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime) / pEngine->SampleRate; + float attenuation = 1 - 0.01053 * (256 >> pDimRgn->ReleaseTriggerDecay) * noteLength; + if (attenuation <= 0) return -1; + Volume *= attenuation; } - pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]); - - pSample = pDimRgn->pSample; // sample won't change until the voice is finished // select channel mode (mono or stereo) SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); @@ -264,7 +174,7 @@ CrossfadeVolume = CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity); break; case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate - CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]); + CrossfadeVolume = CrossfadeAttenuation(pEngineChannel->ControllerTable[pDimRgn->AttenuationController.controller_number]); break; case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined default: @@ -281,7 +191,7 @@ DiskVoice = cachedsamples < pSample->SamplesTotal; if (DiskVoice) { // voice to be streamed from disk - MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK) + MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK) // check if there's a loop defined which completely fits into the cached (RAM) part of the sample if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) { @@ -310,13 +220,14 @@ // calculate initial pitch value { - double pitchbasecents = pDimRgn->FineTune * 10 + (int) pEngine->ScaleTuning[MIDIKey % 12]; + double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate())); this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents } - 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 + const double velrelease = 1 / pDimRgn->GetVelocityRelease(itNoteOnEvent->Param.Note.Velocity); // setup EG 1 (VCA EG) { @@ -333,26 +244,33 @@ eg1controllervalue = itNoteOnEvent->Param.Note.Velocity; break; case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller - eg1controllervalue = pEngine->ControllerTable[pDimRgn->EG1Controller.controller_number]; + eg1controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG1Controller.controller_number]; break; } if (pDimRgn->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue; - // calculate influence of EG1 controller on EG1's parameters (TODO: needs to be fine tuned) - double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 0.0; - double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 0.0; - double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 0.0; + // calculate influence of EG1 controller on EG1's parameters + // (eg1attack is different from the others) + double eg1attack = (pDimRgn->EG1ControllerAttackInfluence) ? + 1 + 0.031 * (double) (pDimRgn->EG1ControllerAttackInfluence == 1 ? + 1 : 1 << pDimRgn->EG1ControllerAttackInfluence) * eg1controllervalue : 1.0; + double eg1decay = (pDimRgn->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerDecayInfluence) * eg1controllervalue : 1.0; + double eg1release = (pDimRgn->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG1ControllerReleaseInfluence) * eg1controllervalue : 1.0; pEG1->Trigger(pDimRgn->EG1PreAttack, - pDimRgn->EG1Attack + eg1attack, + pDimRgn->EG1Attack * eg1attack, pDimRgn->EG1Hold, pSample->LoopStart, - pDimRgn->EG1Decay1 + eg1decay, - pDimRgn->EG1Decay2 + eg1decay, + pDimRgn->EG1Decay1 * eg1decay * velrelease, + pDimRgn->EG1Decay2 * eg1decay * velrelease, pDimRgn->EG1InfiniteSustain, pDimRgn->EG1Sustain, - pDimRgn->EG1Release + eg1release, - Delay); + pDimRgn->EG1Release * eg1release * velrelease, + // the SSE synthesis implementation requires + // the vca start to be 16 byte aligned + SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? + Delay & 0xfffffffc : Delay, + velocityAttenuation); } @@ -371,26 +289,27 @@ eg2controllervalue = itNoteOnEvent->Param.Note.Velocity; break; case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller - eg2controllervalue = pEngine->ControllerTable[pDimRgn->EG2Controller.controller_number]; + eg2controllervalue = pEngineChannel->ControllerTable[pDimRgn->EG2Controller.controller_number]; break; } if (pDimRgn->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue; - // calculate influence of EG2 controller on EG2's parameters (TODO: needs to be fine tuned) - double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 0.0; - double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 0.0; - double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 0.0001 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 0.0; + // calculate influence of EG2 controller on EG2's parameters + double eg2attack = (pDimRgn->EG2ControllerAttackInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerAttackInfluence) * eg2controllervalue : 1.0; + double eg2decay = (pDimRgn->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerDecayInfluence) * eg2controllervalue : 1.0; + double eg2release = (pDimRgn->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pDimRgn->EG2ControllerReleaseInfluence) * eg2controllervalue : 1.0; pEG2->Trigger(pDimRgn->EG2PreAttack, - pDimRgn->EG2Attack + eg2attack, + pDimRgn->EG2Attack * eg2attack, false, pSample->LoopStart, - pDimRgn->EG2Decay1 + eg2decay, - pDimRgn->EG2Decay2 + eg2decay, + pDimRgn->EG2Decay1 * eg2decay * velrelease, + pDimRgn->EG2Decay2 * eg2decay * velrelease, pDimRgn->EG2InfiniteSustain, pDimRgn->EG2Sustain, - pDimRgn->EG2Release + eg2release, - Delay); + pDimRgn->EG2Release * eg2release * velrelease, + Delay, + velocityAttenuation); } @@ -408,34 +327,40 @@ case ::gig::lfo1_ctrl_internal: lfo1_internal_depth = pDimRgn->LFO1InternalDepth; pLFO1->ExtController = 0; // no external controller + bLFO1Enabled = (lfo1_internal_depth > 0); break; case ::gig::lfo1_ctrl_modwheel: lfo1_internal_depth = 0; pLFO1->ExtController = 1; // MIDI controller 1 + bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); break; case ::gig::lfo1_ctrl_breath: lfo1_internal_depth = 0; pLFO1->ExtController = 2; // MIDI controller 2 + bLFO1Enabled = (pDimRgn->LFO1ControlDepth > 0); break; case ::gig::lfo1_ctrl_internal_modwheel: lfo1_internal_depth = pDimRgn->LFO1InternalDepth; pLFO1->ExtController = 1; // MIDI controller 1 + bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); break; case ::gig::lfo1_ctrl_internal_breath: lfo1_internal_depth = pDimRgn->LFO1InternalDepth; pLFO1->ExtController = 2; // MIDI controller 2 + bLFO1Enabled = (lfo1_internal_depth > 0 || pDimRgn->LFO1ControlDepth > 0); break; default: lfo1_internal_depth = 0; pLFO1->ExtController = 0; // no external controller + bLFO1Enabled = false; } - pLFO1->Trigger(pDimRgn->LFO1Frequency, - lfo1_internal_depth, - pDimRgn->LFO1ControlDepth, - pEngine->ControllerTable[pLFO1->ExtController], - pDimRgn->LFO1FlipPhase, - pEngine->SampleRate, - Delay); + if (bLFO1Enabled) pLFO1->Trigger(pDimRgn->LFO1Frequency, + lfo1_internal_depth, + pDimRgn->LFO1ControlDepth, + pEngineChannel->ControllerTable[pLFO1->ExtController], + pDimRgn->LFO1FlipPhase, + pEngine->SampleRate, + Delay); } @@ -446,34 +371,40 @@ case ::gig::lfo2_ctrl_internal: lfo2_internal_depth = pDimRgn->LFO2InternalDepth; pLFO2->ExtController = 0; // no external controller + bLFO2Enabled = (lfo2_internal_depth > 0); break; case ::gig::lfo2_ctrl_modwheel: lfo2_internal_depth = 0; pLFO2->ExtController = 1; // MIDI controller 1 + bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); break; case ::gig::lfo2_ctrl_foot: lfo2_internal_depth = 0; pLFO2->ExtController = 4; // MIDI controller 4 + bLFO2Enabled = (pDimRgn->LFO2ControlDepth > 0); break; case ::gig::lfo2_ctrl_internal_modwheel: lfo2_internal_depth = pDimRgn->LFO2InternalDepth; pLFO2->ExtController = 1; // MIDI controller 1 + bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); break; case ::gig::lfo2_ctrl_internal_foot: lfo2_internal_depth = pDimRgn->LFO2InternalDepth; pLFO2->ExtController = 4; // MIDI controller 4 + bLFO2Enabled = (lfo2_internal_depth > 0 || pDimRgn->LFO2ControlDepth > 0); break; default: lfo2_internal_depth = 0; pLFO2->ExtController = 0; // no external controller + bLFO2Enabled = false; } - pLFO2->Trigger(pDimRgn->LFO2Frequency, - lfo2_internal_depth, - pDimRgn->LFO2ControlDepth, - pEngine->ControllerTable[pLFO2->ExtController], - pDimRgn->LFO2FlipPhase, - pEngine->SampleRate, - Delay); + if (bLFO2Enabled) pLFO2->Trigger(pDimRgn->LFO2Frequency, + lfo2_internal_depth, + pDimRgn->LFO2ControlDepth, + pEngineChannel->ControllerTable[pLFO2->ExtController], + pDimRgn->LFO2FlipPhase, + pEngine->SampleRate, + Delay); } @@ -484,45 +415,52 @@ case ::gig::lfo3_ctrl_internal: lfo3_internal_depth = pDimRgn->LFO3InternalDepth; pLFO3->ExtController = 0; // no external controller + bLFO3Enabled = (lfo3_internal_depth > 0); break; case ::gig::lfo3_ctrl_modwheel: lfo3_internal_depth = 0; pLFO3->ExtController = 1; // MIDI controller 1 + bLFO3Enabled = (pDimRgn->LFO3ControlDepth > 0); break; case ::gig::lfo3_ctrl_aftertouch: lfo3_internal_depth = 0; pLFO3->ExtController = 0; // TODO: aftertouch not implemented yet + bLFO3Enabled = false; // see TODO comment in line above break; case ::gig::lfo3_ctrl_internal_modwheel: lfo3_internal_depth = pDimRgn->LFO3InternalDepth; pLFO3->ExtController = 1; // MIDI controller 1 + bLFO3Enabled = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0); break; case ::gig::lfo3_ctrl_internal_aftertouch: lfo3_internal_depth = pDimRgn->LFO3InternalDepth; pLFO1->ExtController = 0; // TODO: aftertouch not implemented yet + bLFO3Enabled = (lfo3_internal_depth > 0 /*|| pDimRgn->LFO3ControlDepth > 0*/); // see TODO comment in line above break; default: lfo3_internal_depth = 0; pLFO3->ExtController = 0; // no external controller + bLFO3Enabled = false; } - pLFO3->Trigger(pDimRgn->LFO3Frequency, - lfo3_internal_depth, - pDimRgn->LFO3ControlDepth, - pEngine->ControllerTable[pLFO3->ExtController], - false, - pEngine->SampleRate, - Delay); + if (bLFO3Enabled) pLFO3->Trigger(pDimRgn->LFO3Frequency, + lfo3_internal_depth, + pDimRgn->LFO3ControlDepth, + pEngineChannel->ControllerTable[pLFO3->ExtController], + false, + pEngine->SampleRate, + Delay); } - #if FORCE_FILTER_USAGE - SYNTHESIS_MODE_SET_FILTER(SynthesisMode, true); + #if CONFIG_FORCE_FILTER + const bool bUseFilter = true; #else // use filter only if instrument file told so - SYNTHESIS_MODE_SET_FILTER(SynthesisMode, pDimRgn->VCFEnabled); - #endif // FORCE_FILTER_USAGE - if (pDimRgn->VCFEnabled) { - #ifdef OVERRIDE_FILTER_CUTOFF_CTRL - VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL; + const bool bUseFilter = pDimRgn->VCFEnabled; + #endif // CONFIG_FORCE_FILTER + SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter); + if (bUseFilter) { + #ifdef CONFIG_OVERRIDE_CUTOFF_CTRL + VCFCutoffCtrl.controller = CONFIG_OVERRIDE_CUTOFF_CTRL; #else // use the one defined in the instrument file switch (pDimRgn->VCFCutoffController) { case ::gig::vcf_cutoff_ctrl_modwheel: @@ -558,10 +496,10 @@ VCFCutoffCtrl.controller = 0; break; } - #endif // OVERRIDE_FILTER_CUTOFF_CTRL + #endif // CONFIG_OVERRIDE_CUTOFF_CTRL - #ifdef OVERRIDE_FILTER_RES_CTRL - VCFResonanceCtrl.controller = OVERRIDE_FILTER_RES_CTRL; + #ifdef CONFIG_OVERRIDE_RESONANCE_CTRL + VCFResonanceCtrl.controller = CONFIG_OVERRIDE_RESONANCE_CTRL; #else // use the one defined in the instrument file switch (pDimRgn->VCFResonanceController) { case ::gig::vcf_res_ctrl_genpurpose3: @@ -580,23 +518,38 @@ default: VCFResonanceCtrl.controller = 0; } - #endif // OVERRIDE_FILTER_RES_CTRL + #endif // CONFIG_OVERRIDE_RESONANCE_CTRL - #ifndef OVERRIDE_FILTER_TYPE + #ifndef CONFIG_OVERRIDE_FILTER_TYPE FilterLeft.SetType(pDimRgn->VCFType); FilterRight.SetType(pDimRgn->VCFType); #else // override filter type - FilterLeft.SetType(OVERRIDE_FILTER_TYPE); - FilterRight.SetType(OVERRIDE_FILTER_TYPE); - #endif // OVERRIDE_FILTER_TYPE + FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); + FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); + #endif // CONFIG_OVERRIDE_FILTER_TYPE - VCFCutoffCtrl.value = pEngine->ControllerTable[VCFCutoffCtrl.controller]; - VCFResonanceCtrl.value = pEngine->ControllerTable[VCFResonanceCtrl.controller]; + VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; + VCFResonanceCtrl.value = pEngineChannel->ControllerTable[VCFResonanceCtrl.controller]; // calculate cutoff frequency - float cutoff = (!VCFCutoffCtrl.controller) - ? exp((float) (127 - itNoteOnEvent->Param.Note.Velocity) * (float) pDimRgn->VCFVelocityScale * 6.2E-5f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX - : exp((float) VCFCutoffCtrl.value * 0.00787402f * FILTER_CUTOFF_COEFF) * FILTER_CUTOFF_MAX; + float cutoff = pDimRgn->GetVelocityCutoff(itNoteOnEvent->Param.Note.Velocity); + if (pDimRgn->VCFKeyboardTracking) { + cutoff *= exp((itNoteOnEvent->Param.Note.Key - pDimRgn->VCFKeyboardTrackingBreakpoint) * 0.057762265f); // (ln(2) / 12) + } + CutoffBase = cutoff; + + int cvalue; + if (VCFCutoffCtrl.controller) { + cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; + if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; + if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; + } + else { + cvalue = pDimRgn->VCFCutoff; + } + cutoff *= float(cvalue) * 0.00787402f; // (1 / 127) + if (cutoff > 1.0) cutoff = 1.0; + cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN; // calculate resonance float resonance = (float) VCFResonanceCtrl.value * 0.00787f; // 0.0..1.0 @@ -605,7 +558,7 @@ } Constrain(resonance, 0.0, 1.0); // correct resonance if outside allowed value range (0.0..1.0) - VCFCutoffCtrl.fvalue = cutoff - FILTER_CUTOFF_MIN; + VCFCutoffCtrl.fvalue = cutoff - CONFIG_FILTER_CUTOFF_MIN; VCFResonanceCtrl.fvalue = resonance; FilterUpdateCounter = -1; @@ -638,7 +591,11 @@ // Reset the synthesis parameter matrix - pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume); + #if CONFIG_PROCESS_MUTED_CHANNELS + pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume)); + #else + pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngineChannel->GlobalVolume); + #endif pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase); pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue); pEngine->ResetSynthesisParameters(Event::destination_vcfr, VCFResonanceCtrl.fvalue); @@ -647,24 +604,30 @@ ProcessEvents(Samples); // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment - pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, itKillEvent); - pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, itTriggerEvent, this->Pos, this->PitchBase * this->PitchBend); + 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 (bLFO1Enabled) pLFO1->Process(Samples); + if (bLFO2Enabled) pLFO2->Process(Samples); + if (bLFO3Enabled) { + 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 + CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters switch (this->PlaybackState) { + case playback_state_init: + this->PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed + // no break - continue with playback_state_ram + case playback_state_ram: { if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping @@ -702,7 +665,7 @@ // add silence sample at the end if we reached the end of the stream (for the interpolator) if (DiskStreamRef.State == Stream::state_end) { - const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm + const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH) * pSample->Channels + 6; // +6 for the interpolator algorithm if (sampleWordsLeftToRead <= maxSampleWordsPerCycle) { // remember how many sample words there are before any silence has been added if (RealSampleWordsLeftToRead < 0) RealSampleWordsLeftToRead = sampleWordsLeftToRead; @@ -734,9 +697,9 @@ } // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently) - pEngine->pSynthesisEvents[Event::destination_vca]->clear(); - pEngine->pSynthesisEvents[Event::destination_vcfc]->clear(); - pEngine->pSynthesisEvents[Event::destination_vcfr]->clear(); + pEngineChannel->pSynthesisEvents[Event::destination_vca]->clear(); + pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->clear(); + pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->clear(); // Reset delay Delay = 0; @@ -776,17 +739,17 @@ void Voice::ProcessEvents(uint Samples) { // dispatch control change events - RTList::Iterator itCCEvent = pEngine->pCCEvents->first(); + RTList::Iterator itCCEvent = pEngineChannel->pCCEvents->first(); if (Delay) { // skip events that happened before this voice was triggered while (itCCEvent && itCCEvent->FragmentPos() <= Delay) ++itCCEvent; } while (itCCEvent) { if (itCCEvent->Param.CC.Controller) { // if valid MIDI controller if (itCCEvent->Param.CC.Controller == VCFCutoffCtrl.controller) { - *pEngine->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent; + *pEngineChannel->pSynthesisEvents[Event::destination_vcfc]->allocAppend() = *itCCEvent; } if (itCCEvent->Param.CC.Controller == VCFResonanceCtrl.controller) { - *pEngine->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent; + *pEngineChannel->pSynthesisEvents[Event::destination_vcfr]->allocAppend() = *itCCEvent; } if (itCCEvent->Param.CC.Controller == pLFO1->ExtController) { pLFO1->SendEvent(itCCEvent); @@ -799,7 +762,7 @@ } if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange && itCCEvent->Param.CC.Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event - *pEngine->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent; + *pEngineChannel->pSynthesisEvents[Event::destination_vca]->allocAppend() = *itCCEvent; } } @@ -809,7 +772,7 @@ // process pitch events { - RTList* pVCOEventList = pEngine->pSynthesisEvents[Event::destination_vco]; + RTList* pVCOEventList = pEngineChannel->pSynthesisEvents[Event::destination_vco]; RTList::Iterator itVCOEvent = pVCOEventList->first(); if (Delay) { // skip events that happened before this voice was triggered while (itVCOEvent && itVCOEvent->FragmentPos() <= Delay) ++itVCOEvent; @@ -847,7 +810,7 @@ // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !) { - RTList* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca]; + RTList* pVCAEventList = pEngineChannel->pSynthesisEvents[Event::destination_vca]; RTList::Iterator itVCAEvent = pVCAEventList->first(); if (Delay) { // skip events that happened before this voice was triggered while (itVCAEvent && itVCAEvent->FragmentPos() <= Delay) ++itVCAEvent; @@ -862,7 +825,11 @@ crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value); - float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume; + #if CONFIG_PROCESS_MUTED_CHANNELS + float effective_volume = crossfadevolume * this->Volume * (pEngineChannel->GetMute() ? 0 : pEngineChannel->GlobalVolume); + #else + float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume; + #endif // apply volume value to the volume parameter sequence for (uint i = itVCAEvent->FragmentPos(); i < end; i++) { @@ -876,7 +843,7 @@ // process filter cutoff events { - RTList* pCutoffEventList = pEngine->pSynthesisEvents[Event::destination_vcfc]; + RTList* pCutoffEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfc]; RTList::Iterator itCutoffEvent = pCutoffEventList->first(); if (Delay) { // skip events that happened before this voice was triggered while (itCutoffEvent && itCutoffEvent->FragmentPos() <= Delay) ++itCutoffEvent; @@ -889,7 +856,12 @@ // 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) * FILTER_CUTOFF_MAX - FILTER_CUTOFF_MIN; + int cvalue = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; + if (pDimRgn->VCFCutoffControllerInvert) cvalue = 127 - cvalue; + if (cvalue < pDimRgn->VCFVelocityScale) cvalue = pDimRgn->VCFVelocityScale; + cutoff = CutoffBase * float(cvalue) * 0.00787402f; // (1 / 127) + if (cutoff > 1.0) cutoff = 1.0; + cutoff = exp(cutoff * FILTER_CUTOFF_COEFF) * CONFIG_FILTER_CUTOFF_MIN - CONFIG_FILTER_CUTOFF_MIN; // apply cutoff frequency to the cutoff parameter sequence for (uint i = itCutoffEvent->FragmentPos(); i < end; i++) { @@ -903,7 +875,7 @@ // process filter resonance events { - RTList* pResonanceEventList = pEngine->pSynthesisEvents[Event::destination_vcfr]; + RTList* pResonanceEventList = pEngineChannel->pSynthesisEvents[Event::destination_vcfr]; RTList::Iterator itResonanceEvent = pResonanceEventList->first(); if (Delay) { // skip events that happened before this voice was triggered while (itResonanceEvent && itResonanceEvent->FragmentPos() <= Delay) ++itResonanceEvent; @@ -942,8 +914,8 @@ 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, prev_res, pEngine->SampleRate); - FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); + 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; @@ -956,8 +928,8 @@ { prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i]; prev_res = pEngine->pSynthesisParameters[Event::destination_vcfr][i]; - FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); - FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate); + 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); } } @@ -1016,9 +988,10 @@ * @param itKillEvent - event which caused the voice to be killed */ void Voice::Kill(Pool::Iterator& itKillEvent) { - //FIXME: just two sanity checks for debugging, can be removed + #if CONFIG_DEVMODE if (!itKillEvent) dmsg(1,("gig::Voice::Kill(): ERROR, !itKillEvent !!!\n")); if (itKillEvent && !itKillEvent.isValid()) dmsg(1,("gig::Voice::Kill(): ERROR, itKillEvent invalid !!!\n")); + #endif // CONFIG_DEVMODE if (itTriggerEvent && itKillEvent->FragmentPos() <= itTriggerEvent->FragmentPos()) return; this->itKillEvent = itKillEvent;