123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- /*******************************************************************************
- The content of this file includes portions of the AUDIOKINETIC Wwise Technology
- released in source code form as part of the SDK installer package.
- Commercial License Usage
- Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
- may use this file in accordance with the end user license agreement provided
- with the software or, alternatively, in accordance with the terms contained in a
- written agreement between you and Audiokinetic Inc.
- Apache License Usage
- Alternatively, this file may be used under the Apache License, Version 2.0 (the
- "Apache License"); you may not use this file except in compliance with the
- Apache License. You may obtain a copy of the Apache License at
- http://www.apache.org/licenses/LICENSE-2.0.
- Unless required by applicable law or agreed to in writing, software distributed
- under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
- OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
- the specific language governing permissions and limitations under the License.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- #ifndef _AK_MODULATOR_PROCESS_H_
- #define _AK_MODULATOR_PROCESS_H_
- #include <AK/SoundEngine/Common/AkSimd.h>
- #include "AkModulatorParams.h"
- #include "PrivateStructures.h"
- class CAkEnvelopeProcess
- {
- public:
- inline static void Process(const AkModulatorParams& in_Params, AkUInt32 in_uSamples, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer);
- private:
- template< typename tPolicy >
- inline static void _Process(const AkModulatorParams& in_Params, AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer );
- };
- class CAkLFOProcess
- {
- public:
- inline static void Process(const AkModulatorParams& in_Params, AkUInt32 in_uSamples, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer);
- };
- class CAkTimeModProcess
- {
- public:
- inline static void Process(const AkModulatorParams& in_Params, AkUInt32 in_uSamples, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer);
- private:
- template< typename tPolicy >
- inline static void _Process(const AkModulatorParams& in_Params, AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer );
- };
- inline void CAkLFOProcess::Process(const AkModulatorParams& in_Params, const AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer)
- {
- const AkLFOParams& params = (const AkLFOParams&) in_Params;
- ValidateState(params.m_eState);
- out_pOutput.m_eNextState = AkModulatorState_Invalid;
- AkLFOOutput& output = static_cast<AkLFOOutput&>(out_pOutput);
- DSP::LFO::State state;
- params.m_lfo.GetState(state);
- output.m_lfo.PutState(state);
- AkReal32 fDepthBegin = params.m_fDepth;
- AkUInt32 uStartFrame = in_Params.m_uElapsedFrames - in_uFrameSize;
- if (uStartFrame < params.m_uAttack)
- fDepthBegin = params.m_fDepth * ((AkReal32)uStartFrame)/((AkReal32)params.m_uAttack);
- DSP::ModulatorLFOOutputPolicy outputPolicy;
- if (in_Params.m_uBufferSize > 0)
- {
- AkReal32 fDepthEnd = params.m_fDepth;
- if (in_Params.m_uElapsedFrames < params.m_uAttack)
- fDepthEnd = params.m_fDepth * ((AkReal32)in_Params.m_uElapsedFrames)/((AkReal32)params.m_uAttack);
- output.m_lfo.ProduceBuffer(out_pOutputBuffer, in_uFrameSize, fDepthEnd, fDepthBegin, params.m_DspParams.fPWM, outputPolicy );
- out_pOutput.m_fOutput = out_pOutputBuffer[in_uFrameSize-1];
- out_pOutput.m_fPeak = fDepthEnd;
- }
- else
- {
- out_pOutput.m_pBuffer = NULL;
- output.m_lfo.SkipFrames(in_uFrameSize-1);
- output.m_lfo.ProduceBuffer(&out_pOutput.m_fOutput, 1, fDepthBegin, fDepthBegin, params.m_DspParams.fPWM, outputPolicy );
- out_pOutput.m_fPeak = out_pOutput.m_fOutput;
- }
- }
- class CommonOutputPolicy
- {
- public:
- inline static AkReal32 CalcDelta( AkReal32 in_fLevel, AkUInt32 in_uFrames )
- {
- AkReal32 fFrames = (AkReal32)in_uFrames;
- return AK_FSEL( -fFrames, 0.f, (in_fLevel/fFrames) );
- }
- };
- class BufferOutputPolicy: public CommonOutputPolicy
- {
- public:
- inline static AkUInt32 RoundNumFrames(AkUInt32 in_uNumFrames)
- {
- return ((in_uNumFrames + 2) & ~3);
- }
- inline static AkReal32 Ramp( AkReal32*& io_pBuffer, AkUInt32 in_uNumFrames, AkReal32 fStart, AkReal32 fDelta, AkReal32& io_fPeak )
- {
- if (in_uNumFrames != 0)
- {
- AKASSERT((AkUIntPtr)io_pBuffer % 4 == 0);
- AKASSERT(in_uNumFrames % 4 == 0);
- AK_ALIGN_SIMD( AkReal32 f4Ramp[4] ) = {0.f, fDelta, 2.f*fDelta, 3.f*fDelta};
- AKSIMD_V4F32* pStart = (AKSIMD_V4F32*)io_pBuffer;
- AKSIMD_V4F32* pEnd = (AKSIMD_V4F32*)(io_pBuffer + in_uNumFrames);
- AKSIMD_V4F32 s4Start = AKSIMD_LOAD1_V4F32(fStart);
- AkReal32 f4Delta = fDelta*4.f;
- AKSIMD_V4F32 s4Delta = AKSIMD_LOAD1_V4F32(f4Delta);
- *pStart = AKSIMD_ADD_V4F32( AKSIMD_LOAD_V4F32( f4Ramp ), s4Start);
- AKSIMD_V4F32* pPrev = pStart;
- pStart++;
- while(pStart < pEnd)
- {
- *pStart = AKSIMD_ADD_V4F32(s4Delta, *pPrev);
- pStart++;
- pPrev++;
- }
- union{ AkReal32 f4Value[4]; AKSIMD_V4F32 vValue; };
- vValue = AKSIMD_ADD_V4F32(s4Delta, *pPrev);
- //AKASSERT( f4Value[0] >= 0.0f && f4Value[0] <= 1.0f );
- io_pBuffer += in_uNumFrames;
- AkReal32 fOutput = AkClamp( f4Value[0], 0.0f, 1.0f);
- io_fPeak = AkMax( AkMax( fOutput, fStart ), io_fPeak);
- return fOutput;
- }
- return fStart;
- }
- inline static AkReal32 Set( AkReal32*& io_pBuffer, AkUInt32 in_uNumFrames, AkReal32 fVal, AkReal32& io_fPeak )
- {
- AKASSERT((AkUIntPtr)io_pBuffer % 4 == 0);
- AKASSERT(in_uNumFrames % 4 == 0);
- const AKSIMD_V4F32 vValue = AKSIMD_LOAD1_V4F32( fVal );
- for(AKSIMD_V4F32 *pStart = (AKSIMD_V4F32*)io_pBuffer, *pEnd = (AKSIMD_V4F32*)(io_pBuffer+in_uNumFrames);
- pStart < pEnd; pStart++)
- {
- *pStart = vValue;
- }
- io_fPeak = AkMax( fVal, io_fPeak);
- io_pBuffer += in_uNumFrames;
- return fVal;
- }
- };
- class SingleOutputPolicy: public CommonOutputPolicy
- {
- public:
- inline static AkUInt32 RoundNumFrames(AkUInt32 in_uNumFrames)
- {
- return in_uNumFrames;
- }
- inline static AkReal32 Ramp( AkReal32*, AkUInt32 in_uFrames, AkReal32 fStart, AkReal32 fDelta, AkReal32& io_fPeak )
- {
- AkReal32 fOutput = fStart + fDelta * (AkReal32)(in_uFrames);
- io_fPeak = AkMax( AkMax(fOutput, fStart), io_fPeak);
- return fOutput;
- }
- inline static AkReal32 Set( AkReal32*, AkUInt32, AkReal32 fVal, AkReal32& io_fPeak )
- {
- io_fPeak = AkMax( fVal, io_fPeak);
- return fVal;
- }
- };
- template< typename tPolicy >
- inline void CAkEnvelopeProcess::_Process(const AkModulatorParams& in_Params, const AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer )
- {
- const AkEnvelopeParams& params = (const AkEnvelopeParams&) in_Params;
- AKASSERT(params.m_fStartValue >= -0.0f && params.m_fStartValue <= 1.0f);
- AKASSERT(params.m_fCurve >= -0.0f && params.m_fCurve <= 1.0f);
- ValidateState(params.m_eState);
- out_pOutput.m_eNextState = AkModulatorState_Invalid;
- out_pOutput.m_fPeak = params.m_fStartValue;
-
- const AkUInt32 uStartOffset = (params.m_uStartOffsetFrames & ~(0x3));
- const AkUInt32 uHalfAttack = tPolicy::RoundNumFrames(params.m_uAttack / 2);
- const AkUInt32 uDecay = tPolicy::RoundNumFrames(params.m_uDecay);
- const AkUInt32 uRelease = tPolicy::RoundNumFrames(params.m_uRelease);
- AkUInt32 uReleaseFrame = uStartOffset + tPolicy::RoundNumFrames(params.m_uReleaseFrame);
- AkUInt32 uCurrentFrame = in_Params.m_uElapsedFrames - in_uFrameSize;
- if (params.m_fStartValue > 0.f)
- {
- AkUInt32 uEffectiveStartFrame = 0;
- if (params.m_fStartValue < params.m_fCurve && params.m_fCurve > 0.f)
- {
- uEffectiveStartFrame = (AkUInt32)((AkReal32)uHalfAttack * (params.m_fStartValue/params.m_fCurve));
- }
- else
- {
- uEffectiveStartFrame = uHalfAttack + (AkUInt32)((AkReal32)uHalfAttack * ((params.m_fStartValue - params.m_fCurve)/( 1.0f - params.m_fCurve )));
- }
- uEffectiveStartFrame = tPolicy::RoundNumFrames(uEffectiveStartFrame);
- uCurrentFrame += uEffectiveStartFrame;
- uReleaseFrame += uEffectiveStartFrame;
- }
- AkReal32 fValue = uCurrentFrame > 0 ? params.m_fPreviousOutput : params.m_fStartValue;
- AkReal32* pBuffer = out_pOutputBuffer;
- AkUInt32 uRemainingFrames = in_uFrameSize;
- // START OFFSET
- if ( uCurrentFrame < uStartOffset )
- {
- //Zero out the offset part of the first buffer
- AkUInt32 uStartOffsetFrames = AkMin( uStartOffset-uCurrentFrame, in_uFrameSize );
- tPolicy::Set( pBuffer, uStartOffsetFrames, 0.f, out_pOutput.m_fPeak );
- uCurrentFrame += uStartOffsetFrames;
- uRemainingFrames -= uStartOffsetFrames;
- }
- //ATTACK -- part 1
- AkUInt32 uAttackP1End = AkMin( uStartOffset + uHalfAttack, uReleaseFrame );
- if (uCurrentFrame < uAttackP1End)
- {
- AkReal32 fAttackP1Delta = tPolicy::CalcDelta( params.m_fCurve , uHalfAttack );
- AkUInt32 uNumAttackP1Frames = AkMin(uRemainingFrames, uAttackP1End-uCurrentFrame);
- fValue = tPolicy::Ramp( pBuffer, uNumAttackP1Frames, fValue, fAttackP1Delta, out_pOutput.m_fPeak);
- uCurrentFrame += uNumAttackP1Frames;
- uRemainingFrames -= uNumAttackP1Frames;
- }
- //ATTACK -- part 2
- AkUInt32 uAttackP2End = AkMin( uStartOffset + 2*uHalfAttack, uReleaseFrame );
- if (uCurrentFrame < uAttackP2End)
- {
- AkReal32 fAttackP2Delta = tPolicy::CalcDelta( (1.0f - params.m_fCurve), uHalfAttack );
- AkUInt32 uNumAttackP2Frames = AkMin(uRemainingFrames, uAttackP2End-uCurrentFrame);
- fValue = tPolicy::Ramp( pBuffer, uNumAttackP2Frames, fValue, fAttackP2Delta, out_pOutput.m_fPeak);
- uCurrentFrame += uNumAttackP2Frames;
- uRemainingFrames -= uNumAttackP2Frames;
- }
- //DECAY -- pre release
- AkUInt32 uDecayEndNormal = (uAttackP2End + uDecay);
- AkUInt32 uDecayEndPreRelease = AkMin( uDecayEndNormal, uReleaseFrame );
- if (uCurrentFrame < uDecayEndPreRelease)
- {
- AkReal32 fDecayDelta = tPolicy::CalcDelta( params.m_fSustain - 1.0f, uDecay );
- AkUInt32 uNumDecayFrames = AkMin(uRemainingFrames, uDecayEndPreRelease-uCurrentFrame);
- fValue = tPolicy::Ramp( pBuffer, uNumDecayFrames, fValue, fDecayDelta, out_pOutput.m_fPeak);
- uCurrentFrame += uNumDecayFrames;
- uRemainingFrames -= uNumDecayFrames;
- }
- AkReal32 fLevelAtDecayEnd = params.m_fSustain;
- //DECAY -- post release
- AkUInt32 uPostReleaseDecayDur = 0;
- if ( uDecayEndNormal > uReleaseFrame )
- {
- AkReal32 fLvlAfterAttack = 1.f;
- if ( uHalfAttack > 0 )
- {
- // See how far the attack progressed, before we got the note-off.
- AkReal32 fAttackP1Delta = tPolicy::CalcDelta(params.m_fCurve, uHalfAttack);
- AkReal32 fAttackP2Delta = tPolicy::CalcDelta(1.0f - params.m_fCurve, uHalfAttack);
- fLvlAfterAttack = (fAttackP1Delta)*((AkReal32)(uAttackP1End - uStartOffset)) + (fAttackP2Delta)*((AkReal32)(uAttackP2End - uAttackP1End));
- }
- AkReal32 fLvlAboveSusAtAttackEnd = fLvlAfterAttack - params.m_fSustain;
- // See if we got to the point in the attack where we are above the sustain level.
- if (fLvlAboveSusAtAttackEnd > 0.0f)
- {
- AkReal32 fDecayDelta = tPolicy::CalcDelta( params.m_fSustain - 1.0f, uDecay );
- AkUInt32 uReleaseFromAttack = fDecayDelta != 0.f ? ((AkUInt32)(-fLvlAboveSusAtAttackEnd / fDecayDelta)) : 0;// release time taking into account a possibly truncated attack
- // the divide the release duration by two and use a steeper slope to get to the release slope faster.
- uPostReleaseDecayDur = tPolicy::RoundNumFrames( AkMin( uRelease, AkMin( (uDecayEndNormal-uReleaseFrame), uReleaseFromAttack )) / 2 );
- AkUInt32 uDecayEndPostRelease = uDecayEndPreRelease + uPostReleaseDecayDur;
- AkReal32 fReleaseDelta = tPolicy::CalcDelta( -(params.m_fSustain), uRelease );
- AkReal32 fLvlBelowSusAtDecayEnd = -1.f*(fReleaseDelta)*((AkReal32)(uPostReleaseDecayDur));
- //Update this for release slope calc
- fLevelAtDecayEnd = params.m_fSustain + fLvlBelowSusAtDecayEnd;
- if (uCurrentFrame < uDecayEndPostRelease )
- {
- AkReal32 fLvlAboveSusAtRelease = fLvlAboveSusAtAttackEnd + (fDecayDelta)*((AkReal32)uDecayEndPreRelease - (AkReal32)uAttackP2End);
- AkReal32 fDecayPostReleaseDelta = tPolicy::CalcDelta( -(fLvlAboveSusAtRelease + fLvlBelowSusAtDecayEnd), uPostReleaseDecayDur );
- AkUInt32 uNumDecayFrames = AkMin(uRemainingFrames, uDecayEndPostRelease-uCurrentFrame);
- fValue = tPolicy::Ramp( pBuffer, uNumDecayFrames, fValue, fDecayPostReleaseDelta, out_pOutput.m_fPeak);
- uCurrentFrame += uNumDecayFrames;
- uRemainingFrames -= uNumDecayFrames;
- }
- }
- else
- {
- fLevelAtDecayEnd = params.m_fSustain + fLvlAboveSusAtAttackEnd;
- }
- }
- //SUSTAIN
- AkUInt32 uNumSustainFrames = AkMax( (AkInt32)0, AkMin((AkInt32)uRemainingFrames, (AkInt32)uReleaseFrame-(AkInt32)uCurrentFrame) );
- if( uNumSustainFrames > 0 )
- {
- fValue = tPolicy::Set( pBuffer, uNumSustainFrames, params.m_fSustain, out_pOutput.m_fPeak );
- uCurrentFrame += uNumSustainFrames;
- uRemainingFrames -= uNumSustainFrames;
- }
- //RELEASE
- AkUInt32 uActualReleaseDur = uRelease - uPostReleaseDecayDur;
- AkUInt32 uReleaseEnd = uReleaseFrame + uActualReleaseDur;
- if (uCurrentFrame < uReleaseEnd)
- {
- AkReal32 fReleaseDelta = tPolicy::CalcDelta( -(fLevelAtDecayEnd), uActualReleaseDur );
- AkUInt32 uNumReleaseFrames = AkMin(uRemainingFrames, uReleaseEnd-uCurrentFrame);
- fValue = tPolicy::Ramp( pBuffer, uNumReleaseFrames, fValue, fReleaseDelta, out_pOutput.m_fPeak);
- uCurrentFrame += uNumReleaseFrames;
- uRemainingFrames -= uNumReleaseFrames;
- }
- //END
- if (uRemainingFrames > 0 && uCurrentFrame >= uReleaseEnd)
- {
- fValue = tPolicy::Set(pBuffer, uRemainingFrames, 0.f, out_pOutput.m_fPeak );
- out_pOutput.m_eNextState = AkModulatorState_Finished;
- }
- out_pOutput.m_fOutput = fValue;
- }
- inline void CAkEnvelopeProcess::Process(const AkModulatorParams& in_Params, const AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer)
- {
- if ( in_Params.m_uBufferSize == 0 )
- _Process<SingleOutputPolicy>(in_Params, in_uFrameSize, out_pOutput, out_pOutputBuffer );
- else
- _Process<BufferOutputPolicy>(in_Params, in_uFrameSize, out_pOutput, out_pOutputBuffer );
- }
- template< typename tPolicy >
- inline void CAkTimeModProcess::_Process(const AkModulatorParams& in_Params, const AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer)
- {
- const AkTimeModParams& params = (const AkTimeModParams&)in_Params;
- ValidateState(params.m_eState);
- out_pOutput.m_eNextState = AkModulatorState_Invalid;
- out_pOutput.m_fPeak = 0.0;
- AkUInt32 uCurrentFrame = in_Params.m_uElapsedFrames;
- AkReal32* pBuffer = out_pOutputBuffer;
- const AkUInt32 utotalFrames = params.m_uDuration;
- const AkUInt32 uloopFrames = params.m_uLoopsDuration;
- if (uCurrentFrame > utotalFrames)
- {
- if (uCurrentFrame < uloopFrames)
- uCurrentFrame = uCurrentFrame % utotalFrames;
- }
- AkReal32 fValue = (AkReal32)AkTimeConv::SamplesToSeconds(uCurrentFrame);
- AkReal32 finalValue = (AkReal32)AkTimeConv::SamplesToSeconds(utotalFrames);
- fValue = AkMin(fValue, finalValue);
- if (uCurrentFrame < in_Params.m_uReleaseFrame)
- tPolicy::Set(pBuffer, in_uFrameSize, fValue, out_pOutput.m_fPeak);
- else
- {
- // avoid a spike at end by specifying to use the last value
- fValue = tPolicy::Set(pBuffer, in_uFrameSize, finalValue, out_pOutput.m_fPeak);
- out_pOutput.m_eNextState = AkModulatorState_Finished;
- }
- out_pOutput.m_fOutput = fValue;
- }
- inline void CAkTimeModProcess::Process(const AkModulatorParams& in_Params, const AkUInt32 in_uFrameSize, AkModulatorOutput& out_pOutput, AkReal32* out_pOutputBuffer)
- {
- if (in_Params.m_uBufferSize == 0)
- _Process<SingleOutputPolicy>(in_Params, in_uFrameSize, out_pOutput, out_pOutputBuffer);
- else
- _Process<BufferOutputPolicy>(in_Params, in_uFrameSize, out_pOutput, out_pOutputBuffer);
- }
- #endif
|