--- linuxsampler/trunk/src/engines/gig/Voice.cpp 2004/12/13 00:46:42 319 +++ linuxsampler/trunk/src/engines/gig/Voice.cpp 2005/03/09 22:12:15 438 @@ -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 * @@ -58,9 +59,17 @@ pLFO2 = NULL; pLFO3 = NULL; KeyGroup = 0; - + SynthesisMode = 0; // set all mode bits to 0 first // select synthesis implementation (currently either pure C++ or MMX+SSE(1)) + #if ARCH_X86 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); + #else + SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); + #endif + SYNTHESIS_MODE_SET_PROFILING(SynthesisMode, true); + + FilterLeft.Reset(); + FilterRight.Reset(); } Voice::~Voice() { @@ -108,15 +117,19 @@ * Initializes and triggers the voice, a disk stream will be launched if * needed. * + * @param pEngineChannel - engine channel on which this voice was ordered * @param itNoteOnEvent - event that caused triggering of this voice * @param PitchBend - MIDI detune factor (-8192 ... +8191) * @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data * @param iLayer - layer number this voice refers to (only if this is a layered sound of course) * @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false) * @param VoiceStealing - wether the voice is allowed to steal voices for further subvoices - * @returns 0 on success, a value < 0 if something failed + * @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) { + int Voice::Trigger(EngineChannel* pEngineChannel, Pool::Iterator& itNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice, bool VoiceStealing) { + this->pEngineChannel = pEngineChannel; if (!pInstrument) { dmsg(1,("voice::trigger: !pInstrument\n")); exit(EXIT_FAILURE); @@ -135,8 +148,7 @@ itChildVoice = Pool::Iterator(); if (!pRegion) { - std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush; - KillImmediately(); + dmsg(4, ("gig::Voice: No Region defined for MIDI key %d\n", MIDIKey)); return -1; } @@ -144,7 +156,7 @@ // 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}; + uint DimValues[8] = { 0 }; for (int i = pRegion->Dimensions - 1; i >= 0; i--) { switch (pRegion->pDimensionDefinitions[i].dimension) { case ::gig::dimension_samplechannel: @@ -155,7 +167,7 @@ // 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); + itChildVoice = pEngine->LaunchVoice(pEngineChannel, itNoteOnEvent, iNewLayer, ReleaseTriggerVoice, VoiceStealing); break; case ::gig::dimension_velocity: DimValues[i] = itNoteOnEvent->Param.Note.Velocity; @@ -168,76 +180,83 @@ DimValues[i] = (uint) ReleaseTriggerVoice; break; case ::gig::dimension_keyboard: - DimValues[i] = (uint) itNoteOnEvent->Param.Note.Key; + 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] = pEngine->ControllerTable[1]; + DimValues[i] = pEngineChannel->ControllerTable[1]; break; case ::gig::dimension_breath: - DimValues[i] = pEngine->ControllerTable[2]; + DimValues[i] = pEngineChannel->ControllerTable[2]; break; case ::gig::dimension_foot: - DimValues[i] = pEngine->ControllerTable[4]; + DimValues[i] = pEngineChannel->ControllerTable[4]; break; case ::gig::dimension_portamentotime: - DimValues[i] = pEngine->ControllerTable[5]; + DimValues[i] = pEngineChannel->ControllerTable[5]; break; case ::gig::dimension_effect1: - DimValues[i] = pEngine->ControllerTable[12]; + DimValues[i] = pEngineChannel->ControllerTable[12]; break; case ::gig::dimension_effect2: - DimValues[i] = pEngine->ControllerTable[13]; + DimValues[i] = pEngineChannel->ControllerTable[13]; break; case ::gig::dimension_genpurpose1: - DimValues[i] = pEngine->ControllerTable[16]; + DimValues[i] = pEngineChannel->ControllerTable[16]; break; case ::gig::dimension_genpurpose2: - DimValues[i] = pEngine->ControllerTable[17]; + DimValues[i] = pEngineChannel->ControllerTable[17]; break; case ::gig::dimension_genpurpose3: - DimValues[i] = pEngine->ControllerTable[18]; + DimValues[i] = pEngineChannel->ControllerTable[18]; break; case ::gig::dimension_genpurpose4: - DimValues[i] = pEngine->ControllerTable[19]; + DimValues[i] = pEngineChannel->ControllerTable[19]; break; case ::gig::dimension_sustainpedal: - DimValues[i] = pEngine->ControllerTable[64]; + DimValues[i] = pEngineChannel->ControllerTable[64]; break; case ::gig::dimension_portamento: - DimValues[i] = pEngine->ControllerTable[65]; + DimValues[i] = pEngineChannel->ControllerTable[65]; break; case ::gig::dimension_sostenutopedal: - DimValues[i] = pEngine->ControllerTable[66]; + DimValues[i] = pEngineChannel->ControllerTable[66]; break; case ::gig::dimension_softpedal: - DimValues[i] = pEngine->ControllerTable[67]; + DimValues[i] = pEngineChannel->ControllerTable[67]; break; case ::gig::dimension_genpurpose5: - DimValues[i] = pEngine->ControllerTable[80]; + DimValues[i] = pEngineChannel->ControllerTable[80]; break; case ::gig::dimension_genpurpose6: - DimValues[i] = pEngine->ControllerTable[81]; + DimValues[i] = pEngineChannel->ControllerTable[81]; break; case ::gig::dimension_genpurpose7: - DimValues[i] = pEngine->ControllerTable[82]; + DimValues[i] = pEngineChannel->ControllerTable[82]; break; case ::gig::dimension_genpurpose8: - DimValues[i] = pEngine->ControllerTable[83]; + DimValues[i] = pEngineChannel->ControllerTable[83]; break; case ::gig::dimension_effect1depth: - DimValues[i] = pEngine->ControllerTable[91]; + DimValues[i] = pEngineChannel->ControllerTable[91]; break; case ::gig::dimension_effect2depth: - DimValues[i] = pEngine->ControllerTable[92]; + DimValues[i] = pEngineChannel->ControllerTable[92]; break; case ::gig::dimension_effect3depth: - DimValues[i] = pEngine->ControllerTable[93]; + DimValues[i] = pEngineChannel->ControllerTable[93]; break; case ::gig::dimension_effect4depth: - DimValues[i] = pEngine->ControllerTable[94]; + DimValues[i] = pEngineChannel->ControllerTable[94]; break; case ::gig::dimension_effect5depth: - DimValues[i] = pEngine->ControllerTable[95]; + DimValues[i] = pEngineChannel->ControllerTable[95]; break; case ::gig::dimension_none: std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush; @@ -246,9 +265,10 @@ std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush; } } - pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]); + pDimRgn = pRegion->GetDimensionRegionByValue(DimValues); pSample = pDimRgn->pSample; // sample won't change until the voice is finished + if (!pSample || !pSample->SamplesTotal) return -1; // no need to continue if sample is silent // select channel mode (mono or stereo) SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); @@ -262,7 +282,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: @@ -308,7 +328,7 @@ // 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 @@ -316,6 +336,8 @@ 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) + Volume *= pDimRgn->SampleAttenuation; + // setup EG 1 (VCA EG) { // get current value of EG1 controller @@ -331,7 +353,7 @@ 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; @@ -350,7 +372,10 @@ pDimRgn->EG1InfiniteSustain, pDimRgn->EG1Sustain, pDimRgn->EG1Release + eg1release, - Delay); + // the SSE synthesis implementation requires + // the vca start to be 16 byte aligned + SYNTHESIS_MODE_GET_IMPLEMENTATION(SynthesisMode) ? + Delay & 0xfffffffc : Delay); } @@ -369,7 +394,7 @@ 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; @@ -430,7 +455,7 @@ pLFO1->Trigger(pDimRgn->LFO1Frequency, lfo1_internal_depth, pDimRgn->LFO1ControlDepth, - pEngine->ControllerTable[pLFO1->ExtController], + pEngineChannel->ControllerTable[pLFO1->ExtController], pDimRgn->LFO1FlipPhase, pEngine->SampleRate, Delay); @@ -468,7 +493,7 @@ pLFO2->Trigger(pDimRgn->LFO2Frequency, lfo2_internal_depth, pDimRgn->LFO2ControlDepth, - pEngine->ControllerTable[pLFO2->ExtController], + pEngineChannel->ControllerTable[pLFO2->ExtController], pDimRgn->LFO2FlipPhase, pEngine->SampleRate, Delay); @@ -506,7 +531,7 @@ pLFO3->Trigger(pDimRgn->LFO3Frequency, lfo3_internal_depth, pDimRgn->LFO3ControlDepth, - pEngine->ControllerTable[pLFO3->ExtController], + pEngineChannel->ControllerTable[pLFO3->ExtController], false, pEngine->SampleRate, Delay); @@ -514,11 +539,12 @@ #if FORCE_FILTER_USAGE - SYNTHESIS_MODE_SET_FILTER(SynthesisMode, true); + const bool bUseFilter = true; #else // use filter only if instrument file told so - SYNTHESIS_MODE_SET_FILTER(SynthesisMode, pDimRgn->VCFEnabled); + const bool bUseFilter = pDimRgn->VCFEnabled; #endif // FORCE_FILTER_USAGE - if (pDimRgn->VCFEnabled) { + SYNTHESIS_MODE_SET_FILTER(SynthesisMode, bUseFilter); + if (bUseFilter) { #ifdef OVERRIDE_FILTER_CUTOFF_CTRL VCFCutoffCtrl.controller = OVERRIDE_FILTER_CUTOFF_CTRL; #else // use the one defined in the instrument file @@ -588,8 +614,8 @@ FilterRight.SetType(OVERRIDE_FILTER_TYPE); #endif // 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) @@ -636,7 +662,7 @@ // Reset the synthesis parameter matrix - pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume); + 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); @@ -645,8 +671,8 @@ 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); @@ -659,7 +685,7 @@ } 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) { @@ -693,12 +719,19 @@ } DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (int(Pos) - MaxRAMPos)); Pos -= int(Pos); + RealSampleWordsLeftToRead = -1; // -1 means no silence has been added yet } + const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace(); + // add silence sample at the end if we reached the end of the stream (for the interpolator) - if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) { - DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels); - this->PlaybackState = playback_state_end; + if (DiskStreamRef.State == Stream::state_end) { + const int maxSampleWordsPerCycle = (pEngine->MaxSamplesPerCycle << 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; + DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead); + } } sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from @@ -706,8 +739,16 @@ // render current audio fragment Synthesize(Samples, ptr, Delay); - DiskStreamRef.pStream->IncrementReadPos(int(Pos) * pSample->Channels); - Pos -= int(Pos); + const int iPos = (int) Pos; + const int readSampleWords = iPos * pSample->Channels; // amount of sample words actually been read + DiskStreamRef.pStream->IncrementReadPos(readSampleWords); + Pos -= iPos; // just keep fractional part of Pos + + // change state of voice to 'end' if we really reached the end of the sample data + if (RealSampleWordsLeftToRead >= 0) { + RealSampleWordsLeftToRead -= readSampleWords; + if (RealSampleWordsLeftToRead <= 0) this->PlaybackState = playback_state_end; + } } break; @@ -845,7 +886,7 @@ crossfadevolume = CrossfadeAttenuation(itVCAEvent->Param.CC.Value); - float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume; + float effective_volume = crossfadevolume * this->Volume * pEngineChannel->GlobalVolume; // apply volume value to the volume parameter sequence for (uint i = itVCAEvent->FragmentPos(); i < end; i++) { @@ -925,7 +966,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); + FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); + FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); pEngine->pBasicFilterParameters[0] = bqbase; pEngine->pMainFilterParameters[0] = bqmain; @@ -938,25 +980,26 @@ { 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); + FilterLeft.SetParameters( &bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); + FilterRight.SetParameters(&bqbase, &bqmain, prev_cutoff + FILTER_CUTOFF_MIN, prev_res, pEngine->SampleRate); } } //same as 'pEngine->pBasicFilterParameters[i] = bqbase;' bq = (float*) &pEngine->pBasicFilterParameters[i]; - bq[0] = bqbase.a1; - bq[1] = bqbase.a2; - bq[2] = bqbase.b0; - bq[3] = bqbase.b1; - bq[4] = bqbase.b2; + 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.a1; - bq[1] = bqmain.a2; - bq[2] = bqmain.b0; - bq[3] = bqmain.b1; - bq[4] = bqmain.b2; + bq[0] = bqmain.b0; + bq[1] = bqmain.b1; + bq[2] = bqmain.b2; + bq[3] = bqmain.a1; + bq[4] = bqmain.a2; } } @@ -968,18 +1011,8 @@ * @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, int Skip) { - UpdateSynthesisMode(); - SynthesizeFragment_Fn* f = (SynthesizeFragment_Fn*) SynthesizeFragmentFnPtr; - f(*this, Samples, pSrc, Skip); - } - - /** - * Determine the respective synthesis function for the given synthesis - * mode. - */ - void Voice::UpdateSynthesisMode() { - SynthesizeFragmentFnPtr = GetSynthesisFunction(SynthesisMode); + void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { + RunSynthesisFunction(SynthesisMode, *this, Samples, pSrc, Skip); } /**