--- linuxsampler/trunk/src/engines/gig/Voice.cpp 2006/06/25 13:54:17 877 +++ linuxsampler/trunk/src/engines/gig/Voice.cpp 2007/09/04 01:12:49 1321 @@ -3,7 +3,7 @@ * LinuxSampler - modular, streaming capable sampler * * * * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * - * Copyright (C) 2005, 2006 Christian Schoenebeck * + * Copyright (C) 2005 - 2007 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 * @@ -38,8 +38,8 @@ pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range) KeyGroup = 0; SynthesisMode = 0; // set all mode bits to 0 first - // select synthesis implementation (currently either pure C++ or MMX+SSE(1)) - #if CONFIG_ASM && ARCH_X86 + // select synthesis implementation (asm core is not supported ATM) + #if 0 // CONFIG_ASM && ARCH_X86 SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE()); #else SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false); @@ -79,6 +79,7 @@ int Voice::Trigger(EngineChannel* pEngineChannel, Pool::Iterator& itNoteOnEvent, int PitchBend, ::gig::DimensionRegion* pDimRgn, type_t VoiceType, int iKeyGroup) { this->pEngineChannel = pEngineChannel; this->pDimRgn = pDimRgn; + Orphan = false; #if CONFIG_DEVMODE if (itNoteOnEvent->FragmentPos() > pEngine->MaxSamplesPerCycle) { // just a sanity check for debugging @@ -98,9 +99,12 @@ // calculate volume const double velocityAttenuation = pDimRgn->GetVelocityAttenuation(itNoteOnEvent->Param.Note.Velocity); - float volume = velocityAttenuation / 32768.0f; // we downscale by 32768 to convert from int16 value range to DSP value range (which is -1.0..1.0) + // For 16 bit samples, we downscale by 32768 to convert from + // int16 value range to DSP value range (which is + // -1.0..1.0). For 24 bit, we downscale from int32. + float volume = velocityAttenuation / (pSample->BitDepth == 16 ? 32768.0f : 32768.0f * 65536.0f); - volume *= pDimRgn->SampleAttenuation; + volume *= pDimRgn->SampleAttenuation * pEngineChannel->GlobalVolume * GLOBAL_VOLUME; // the volume of release triggered samples depends on note length if (Type == type_release_trigger) { @@ -113,12 +117,14 @@ // select channel mode (mono or stereo) SYNTHESIS_MODE_SET_CHANNELS(SynthesisMode, pSample->Channels == 2); + // select bit depth (16 or 24) + SYNTHESIS_MODE_SET_BITDEPTH24(SynthesisMode, pSample->BitDepth == 24); // get starting crossfade volume level float crossfadeVolume; switch (pDimRgn->AttenuationController.type) { case ::gig::attenuation_ctrl_t::type_channelaftertouch: - crossfadeVolume = 1.0f; //TODO: aftertouch not supported yet + crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(pEngineChannel->ControllerTable[128])]; break; case ::gig::attenuation_ctrl_t::type_velocity: crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(itNoteOnEvent->Param.Note.Velocity)]; @@ -136,7 +142,7 @@ float subfragmentRate = pEngine->SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE; CrossfadeSmoother.trigger(crossfadeVolume, subfragmentRate); - VolumeSmoother.trigger(pEngineChannel->GlobalVolume, subfragmentRate); + VolumeSmoother.trigger(pEngineChannel->MidiVolume, subfragmentRate); PanLeftSmoother.trigger(pEngineChannel->GlobalPanLeft, subfragmentRate); PanRightSmoother.trigger(pEngineChannel->GlobalPanRight, subfragmentRate); @@ -195,7 +201,7 @@ eg1controllervalue = 0; break; case ::gig::eg1_ctrl_t::type_channelaftertouch: - eg1controllervalue = 0; // TODO: aftertouch not yet supported + eg1controllervalue = pEngineChannel->ControllerTable[128]; break; case ::gig::eg1_ctrl_t::type_velocity: eg1controllervalue = itNoteOnEvent->Param.Note.Velocity; @@ -236,7 +242,7 @@ else #else { - float finalVolume = pEngineChannel->GlobalVolume * crossfadeVolume * EG1.getLevel(); + float finalVolume = pEngineChannel->MidiVolume * crossfadeVolume * EG1.getLevel(); finalSynthesisParameters.fFinalVolumeLeft = finalVolume * VolumeLeft * pEngineChannel->GlobalPanLeft; finalSynthesisParameters.fFinalVolumeRight = finalVolume * VolumeRight * pEngineChannel->GlobalPanRight; @@ -253,7 +259,7 @@ eg2controllervalue = 0; break; case ::gig::eg2_ctrl_t::type_channelaftertouch: - eg2controllervalue = 0; // TODO: aftertouch not yet supported + eg2controllervalue = pEngineChannel->ControllerTable[128]; break; case ::gig::eg2_ctrl_t::type_velocity: eg2controllervalue = itNoteOnEvent->Param.Note.Velocity; @@ -333,7 +339,7 @@ } if (bLFO1Enabled) { pLFO1->trigger(pDimRgn->LFO1Frequency, - start_level_max, + start_level_min, lfo1_internal_depth, pDimRgn->LFO1ControlDepth, pDimRgn->LFO1FlipPhase, @@ -405,8 +411,8 @@ 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 + pLFO3->ExtController = 128; + bLFO3Enabled = true; break; case ::gig::lfo3_ctrl_internal_modwheel: lfo3_internal_depth = pDimRgn->LFO3InternalDepth; @@ -415,8 +421,8 @@ 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 + pLFO1->ExtController = 128; + bLFO3Enabled = (lfo3_internal_depth > 0 || pDimRgn->LFO3ControlDepth > 0); break; default: lfo3_internal_depth = 0; @@ -473,7 +479,9 @@ case ::gig::vcf_cutoff_ctrl_genpurpose8: VCFCutoffCtrl.controller = 83; break; - case ::gig::vcf_cutoff_ctrl_aftertouch: //TODO: not implemented yet + case ::gig::vcf_cutoff_ctrl_aftertouch: + VCFCutoffCtrl.controller = 128; + break; case ::gig::vcf_cutoff_ctrl_none: default: VCFCutoffCtrl.controller = 0; @@ -507,8 +515,8 @@ finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); #else // override filter type - FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); - FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); + finalSynthesisParameters.filterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); + finalSynthesisParameters.filterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); #endif // CONFIG_OVERRIDE_FILTER_TYPE VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; @@ -614,7 +622,7 @@ } } - sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from + sample_t* ptr = (sample_t*)DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from // render current audio fragment Synthesize(Samples, ptr, Delay); @@ -712,7 +720,7 @@ CrossfadeSmoother.update(Engine::CrossfadeCurve[CrossfadeAttenuation(itEvent->Param.CC.Value)]); } if (itEvent->Param.CC.Controller == 7) { // volume - VolumeSmoother.update(Engine::VolumeCurve[itEvent->Param.CC.Value] * CONFIG_GLOBAL_ATTENUATION); + VolumeSmoother.update(Engine::VolumeCurve[itEvent->Param.CC.Value]); } else if (itEvent->Param.CC.Controller == 10) { // panpot PanLeftSmoother.update(Engine::PanCurve[128 - itEvent->Param.CC.Value]); PanRightSmoother.update(Engine::PanCurve[itEvent->Param.CC.Value]); @@ -761,8 +769,8 @@ * @param Skip - number of sample points to skip in output buffer */ void Voice::Synthesize(uint Samples, sample_t* pSrc, uint Skip) { - finalSynthesisParameters.pOutLeft = &pEngineChannel->pOutputLeft[Skip]; - finalSynthesisParameters.pOutRight = &pEngineChannel->pOutputRight[Skip]; + finalSynthesisParameters.pOutLeft = &pEngineChannel->pChannelLeft->Buffer()[Skip]; + finalSynthesisParameters.pOutRight = &pEngineChannel->pChannelRight->Buffer()[Skip]; finalSynthesisParameters.pSrc = pSrc; RTList::Iterator itCCEvent = pEngineChannel->pEvents->first(); @@ -796,8 +804,11 @@ // process transition events (note on, note off & sustain pedal) processTransitionEvents(itNoteEvent, iSubFragmentEnd); - // if the voice was killed in this subfragment switch EG1 to fade out stage - if (itKillEvent && killPos <= iSubFragmentEnd) { + // if the voice was killed in this subfragment, or if the + // filter EG is finished, switch EG1 to fade out stage + if ((itKillEvent && killPos <= iSubFragmentEnd) || + (SYNTHESIS_MODE_GET_FILTER(SynthesisMode) && + EG2.getSegmentType() == EGADSR::segment_end)) { EG1.enterFadeOutStage(); itKillEvent = Pool::Iterator(); } @@ -828,7 +839,7 @@ if (EG3.active()) finalSynthesisParameters.fFinalPitch *= EG3.render(); // process low frequency oscillators - if (bLFO1Enabled) fFinalVolume *= pLFO1->render(); + if (bLFO1Enabled) fFinalVolume *= (1.0f - pLFO1->render()); if (bLFO2Enabled) fFinalCutoff *= pLFO2->render(); if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render()); @@ -910,13 +921,30 @@ * fading down the volume level to avoid clicks and regular processing * until the kill event actually occured! * - * @see Kill() + * If it's necessary to know when the voice's disk stream was actually + * deleted, then one can set the optional @a bRequestNotification + * parameter and this method will then return the handle of the disk + * stream (unique identifier) and one can use this handle to poll the + * disk thread if this stream has been deleted. In any case this method + * will return immediately and will not block until the stream actually + * was deleted. + * + * @param bRequestNotification - (optional) whether the disk thread shall + * provide a notification once it deleted + * the respective disk stream + * (default=false) + * @returns handle to the voice's disk stream or @c Stream::INVALID_HANDLE + * if the voice did not use a disk stream at all + * @see Kill() */ - void Voice::KillImmediately() { + Stream::Handle Voice::KillImmediately(bool bRequestNotification) { + Stream::Handle hStream = Stream::INVALID_HANDLE; if (DiskVoice && DiskStreamRef.State != Stream::state_unused) { - pDiskThread->OrderDeletionOfStream(&DiskStreamRef); + pDiskThread->OrderDeletionOfStream(&DiskStreamRef, bRequestNotification); + hStream = DiskStreamRef.hStream; } Reset(); + return hStream; } /**