chore(fmod): add files from Chensne/DragonNest

This commit is contained in:
phaneron 2025-08-19 10:12:56 -04:00
commit 50fb3c6b1c
544 changed files with 315778 additions and 0 deletions

218
lib/sfx/foreverb/3dl2.h Executable file
View file

@ -0,0 +1,218 @@
// 3DL2.H
//
// #ifndef 3DL2_H_INCLUDED
// #define 3DL2_H_INCLUDED
#ifndef __3DL2_H
#define __3DL2_H
// #include <dsound.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/*
#pragma pack(push, 4)
// I3DL2 listener property set {DA0F0520-300A-11D3-8A2B-0060970DB011}
DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties,
0xDA0F0520,
0x300A,
0x11D3,
0x8A2B,
0x0060970DB011);
*/
typedef enum
{
DSPROPERTY_I3DL2LISTENER_ALL, // sets all I3DL2 listener properties
DSPROPERTY_I3DL2LISTENER_ROOM, // room effect level at low frequencies
DSPROPERTY_I3DL2LISTENER_ROOMHF, // room effect high-frequency level re. low frequency level
DSPROPERTY_I3DL2LISTENER_ROOMROLLOFFFACTOR, // like DS3D flRolloffFactor but for room effect
DSPROPERTY_I3DL2LISTENER_DECAYTIME, // reverberation decay time at low-frequencies
DSPROPERTY_I3DL2LISTENER_DECAYHFRATIO, // high-frequency to low-frequency decay time ratio
DSPROPERTY_I3DL2LISTENER_REFLECTIONS, // early reflections level relative to room effect
DSPROPERTY_I3DL2LISTENER_REFLECTIONSDELAY, // delay time of first reflection
DSPROPERTY_I3DL2LISTENER_REVERB, // late reverberation level relative to room effect
DSPROPERTY_I3DL2LISTENER_REVERBDELAY, // late reverberation delay time relative to first reflection
DSPROPERTY_I3DL2LISTENER_DIFFUSION, // reverberation diffusion (echo density)
DSPROPERTY_I3DL2LISTENER_DENSITY, // reverberation density (modal density)
DSPROPERTY_I3DL2LISTENER_HFREFERENCE // reference high frequency
} DSPROPERTY_I3DL2_LISTENERPROPERTY;
// use this structure for DSPROPERTY_I3DL2LISTENER_ALL
// - all levels are hundredths of decibels (mB)
// - all times are in seconds (s)
typedef struct _I3DL2_LISTENERPROPERTIES
{
long lRoom; // [-10000, 0] default: -10000 mB
long lRoomHF; // [-10000, 0] default: 0 mB
float flRoomRolloffFactor; // [0.0, 10.0] default: 0.0
float flDecayTime; // [0.1, 20.0] default: 1.0 s
float flDecayHFRatio; // [0.1, 2.0] default: 0.5
long lReflections; // [-10000, 1000] default: -10000 mB
float flReflectionsDelay; // [0.0, 0.3] default: 0.02 s
long lReverb; // [-10000, 2000] default: -10000 mB
float flReverbDelay; // [0.0, 0.1] default: 0.04 s
float flDiffusion ; // [0.0, 100.0] default: 100.0 %
float flDensity; // [0.0, 100.0] default: 100.0 %
float flHFReference; // [20.0, 20000.0] default: 5000.0 Hz
} I3DL2_LISTENERPROPERTIES, *LPI3DL2_LISTENERPROPERTIES;
// property ranges and defaults:
#define I3DL2LISTENER_MINROOM -10000
#define I3DL2LISTENER_MAXROOM 0
#define I3DL2LISTENER_DEFAULTROOM -10000
#define I3DL2LISTENER_MINROOMHF -10000
#define I3DL2LISTENER_MAXROOMHF 0
#define I3DL2LISTENER_DEFAULTROOMHF 0
#define I3DL2LISTENER_MINROOMROLLOFFFACTOR 0.0f
#define I3DL2LISTENER_MAXROOMROLLOFFFACTOR 10.0f
#define I3DL2LISTENER_DEFAULTROOMROLLOFFFACTOR 0.0f
#define I3DL2LISTENER_MINDECAYTIME 0.1f
#define I3DL2LISTENER_MAXDECAYTIME 20.0f
#define I3DL2LISTENER_DEFAULTDECAYTIME 1.0f
#define I3DL2LISTENER_MINDECAYHFRATIO 0.1f
#define I3DL2LISTENER_MAXDECAYHFRATIO 2.0f
#define I3DL2LISTENER_DEFAULTDECAYHFRATIO 0.5f
#define I3DL2LISTENER_MINREFLECTIONS -10000
#define I3DL2LISTENER_MAXREFLECTIONS 1000
#define I3DL2LISTENER_DEFAULTREFLECTIONS -10000
#define I3DL2LISTENER_MINREFLECTIONSDELAY 0.0f
#define I3DL2LISTENER_MAXREFLECTIONSDELAY 0.3f
#define I3DL2LISTENER_DEFAULTREFLECTIONSDELAY 0.02f
#define I3DL2LISTENER_MINREVERB -10000
#define I3DL2LISTENER_MAXREVERB 2000
#define I3DL2LISTENER_DEFAULTREVERB 0 // -10000
#define I3DL2LISTENER_MINREVERBDELAY 0.0f
#define I3DL2LISTENER_MAXREVERBDELAY 0.1f
#define I3DL2LISTENER_DEFAULTREVERBDELAY 0.04f
#define I3DL2LISTENER_MINDIFFUSION 0.0f
#define I3DL2LISTENER_MAXDIFFUSION 100.0f
#define I3DL2LISTENER_DEFAULTDIFFUSION 100.0f
#define I3DL2LISTENER_MINDENSITY 0.0f
#define I3DL2LISTENER_MAXDENSITY 100.0f
#define I3DL2LISTENER_DEFAULTDENSITY 100.0f
#define I3DL2LISTENER_MINHFREFERENCE 20.0f
#define I3DL2LISTENER_MAXHFREFERENCE 20000.0f
#define I3DL2LISTENER_DEFAULTHFREFERENCE 5000.0f
// I3DL2 buffer property set {DA0F0521-300A-11D3-8A2B-0060970DB011}
/*
DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties,
0xDA0F0521,
0x300A,
0x11D3,
0x8A2B,
0x0060970DB011);
*/
/*
typedef enum
{
DSPROPERTY_I3DL2BUFFER_ALL, // sets all I3DL2 buffer properties
DSPROPERTY_I3DL2BUFFER_OBSTRUCTIONALL, // sets both obstruction properties
DSPROPERTY_I3DL2BUFFER_OCCLUSIONALL, // sets both occlusion properties
DSPROPERTY_I3DL2BUFFER_DIRECT, // additional direct path level correction
DSPROPERTY_I3DL2BUFFER_DIRECTHF, // additional direct path high-frequency re. low-frequency level correction
DSPROPERTY_I3DL2BUFFER_ROOM, // additional room effect level correction
DSPROPERTY_I3DL2BUFFER_ROOMHF, // additional room effect high-frequency re. low-frequency level correction
DSPROPERTY_I3DL2BUFFER_ROOMROLLOFFFACTOR, // like DS3D flRolloffFactor but for room effect
DSPROPERTY_I3DL2BUFFER_OBSTRUCTION, // main obstruction control (attenuation at high frequencies)
DSPROPERTY_I3DL2BUFFER_OBSTRUCTIONLFRATIO, // obstruction low-frequency re. high-frequency ratio
DSPROPERTY_I3DL2BUFFER_OCCLUSION, // main occlusion control (attenuation at high frequencies)
DSPROPERTY_I3DL2BUFFER_OCCLUSIONLFRATIO // occlusion low-frequency re. high-frequency ratio
} DSPROPERTY_I3DL2_BUFFERPROPERTY;
*/
/*
// use this structure for DSPROPERTY_I3DL2BUFFER_OBSTRUCTIONALL
// - all levels are hundredths of decibels (mB)
typedef struct _I3DL2_OBSTRUCTIONPROPERTIES
{
LONG lHFLevel; // [-10000, 0] default: 0 mB
FLOAT flLFRatio; // [0.0, 1.0] default: 0.0
} I3DL2_OBSTRUCTIONPROPERTIES, *LPI3DL2_OBSTRUCTIONPROPERTIES;
// use this structure for DSPROPERTY_I3DL2BUFFER_OCCLUSIONALL
// - all levels are hundredths of decibels (mB)
typedef struct _I3DL2_OCCLUSIONPROPERTIES
{
LONG lHFLevel; // [-10000, 0] default: 0 mB
FLOAT flLFRatio; // [0.0, 1.0] default: 0.25
} I3DL2_OCCLUSIONPROPERTIES, *LPI3DL2_OCCLUSIONPROPERTIES;
// use this structure for DSPROPERTY_I3DL2BUFFER_ALL
// - all levels are hundredths of decibels (mB)
typedef struct _I3DL2_BUFFERPROPERTIES
{
LONG lDirect; // [-10000, 1000] default: 0 mB
LONG lDirectHF; // [-10000, 0] default: 0 mB
LONG lRoom; // [-10000, 1000] default: 0 mB
LONG lRoomHF; // [-10000, 0] default: 0 mB
FLOAT flRoomRolloffFactor; // [0.0, 10.0] default: 0.0
I3DL2BUFFER_OBSTRUCTIONPROPERTIES Obstruction;
I3DL2BUFFER_OCCLUSIONPROPERTIES Occlusion;
} I3DL2_BUFFERPROPERTIES, *LPI3DL2_BUFFERPROPERTIES;
// property ranges and defaults:
#define I3DL2BUFFER_MINDIRECT -10000
#define I3DL2BUFFER_MAXDIRECT 1000
#define I3DL2BUFFER_DEFAULTDIRECT 0
#define I3DL2BUFFER_MINDIRECTHF -10000
#define I3DL2BUFFER_MAXDIRECTHF 0
#define I3DL2BUFFER_DEFAULTDIRECTHF 0
#define I3DL2BUFFER_MINROOM -10000
#define I3DL2BUFFER_MAXROOM 1000
#define I3DL2BUFFER_DEFAULTROOM 0
#define I3DL2BUFFER_MINROOMHF -10000
#define I3DL2BUFFER_MAXROOMHF 0
#define I3DL2BUFFER_DEFAULTROOMHF 0
#define I3DL2BUFFER_MINROOMROLLOFFFACTOR 0.0f
#define I3DL2BUFFER_MAXROOMROLLOFFFACTOR 10.f
#define I3DL2BUFFER_DEFAULTROOMROLLOFFFACTOR 0.0f
#define I3DL2BUFFER_MINOBSTRUCTION -10000
#define I3DL2BUFFER_MAXOBSTRUCTION 0
#define I3DL2BUFFER_DEFAULTOBSTRUCTION 0
#define I3DL2BUFFER_MINOBSTRUCTIONLFRATIO 0.0f
#define I3DL2BUFFER_MAXOBSTRUCTIONLFRATIO 1.0f
#define I3DL2BUFFER_DEFAULTOBSTRUCTIONLFRATIO 0.0f
#define I3DL2BUFFER_MINOCCLUSION -10000
#define I3DL2BUFFER_MAXOCCLUSION 0
#define I3DL2BUFFER_DEFAULTOCCLUSION 0
#define I3DL2BUFFER_MINOCCLUSIONLFRATIO 0.0f
#define I3DL2BUFFER_MAXOCCLUSIONLFRATIO 1.0f
#define I3DL2BUFFER_DEFAULTOCCLUSIONLFRATIO 0.25f
*/
// #pragma pack(pop)
#ifdef __cplusplus
}
#endif // __cplusplus
#endif

967
lib/sfx/foreverb/aSfxDsp.cpp Executable file
View file

@ -0,0 +1,967 @@
#include <stdio.h>
#include "aSfxDsp.hpp"
#include "3dl2.h"
#include <stdlib.h>
#include <string.h> // for memmove and FMOD_memcpy
#include "../../../src/fmod_memory.h"
#include "../../../src/fmod_types.h"
#define ADD_ANTI_DENORMALS_TO_INPUT
#define SfxDataMove(source, dest, bytes) memmove(dest, source, (unsigned)bytes)
//-----------------------------------------------------------------------------
int ASfxDsp::init(float rate)
{
int delayLine;
int error = 0;
mEarlyLateDelay = NULL;
mEarlyDelay = NULL;
ZeroWritePointers();
mEarlyLateSec[0] = 0.040f;
mEarlyLateSamples[0] = (int)(mEarlyLateSec[0] * rate);
SetLate_EarlyLateDelayTaps(0.060f, kEarlyLateNextLengthSec, kEarlyLateDelayRatio, rate);
for (delayLine=0; delayLine<kNumEarlyLateDelayTaps; delayLine++)
{
mOldEarlyLateSamples[delayLine] = mEarlyLateSamples[delayLine];
}
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
mLateMask[delayLine] = 0;
}
SetEarlyDelay(kEarlyFirstDelaySec, kEarlyDelayRatio, rate);
SetAllpassDelays(rate);
SetLateDelays(LOWEST_DELAY_LINE_LENGTH_SEC, DELAY_LINE_RATIO, LOWEST_DELAY_LINE_LENGTH_B_SEC, DELAY_LINE_RATIO_B, rate);
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
mOldLateDelayLenSamples[delayLine] = mLateDelayLenSamples[delayLine];
mLateChanged[delayLine] = false;
mDecayHFChanged[delayLine] = false;
}
if (error = AllocateLateDelays(kNumLateReverbDelays, mLateDelayLenSec, rate)) // assignment, not comparison!
{
return error;
}
if (error = AllocateEarlyLateDelay(mEarlyLateSec, rate))
{
return error;
}
if (error = AllocateAllpassDelays(kNumAllpassDelays, mAllpassDelayLenSec, rate))
{
return error;
}
if (error = AllocateEarlyDelay(mEarlyDelayLenSec[kNumEarlyDelayTaps-1], rate))
{
return error;
}
mNumAllocatedInBuffSamples = 0;
mInBuff = mInBuffMemory = 0;
mMatrix = (float *)FMOD_ALIGNPOINTER(mMatrixMem, 16);
mzDecayHF = (float *)FMOD_ALIGNPOINTER(mzDecayHFMem, 16);
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
mOldFeedback[delayLine] = mPrevFeedback[delayLine] = mLatchFeedback[delayLine] = mFeedback[delayLine] = 0.32f;
mLatchDecayHF[delayLine] = mPrevDecayHF[delayLine] = mOldDecayHF[delayLine] = mDecayHF[delayLine] = 0.40f;
mLatchOneMinusDecayHF[delayLine] = 1.0f - mDecayHF[delayLine];
}
mOldHadamard = mPrevHadamard = mLatchHadamard = mHadamard = 1.0f;
mOldDiffusionScale = mPrevDiffusionScale = mLatchDiffusionScale = mDiffusionScale = 1.0f;
mOldRoomHF = mPrevRoomHF = mLatchRoomHF = mRoomHF = 0.98f;
mRoomHFChanged = false;
//FMOD_memset(&mOldRoomLF, 0, sizeof(struct coeff2ndorder));
//FMOD_memset(&mPrevRoomLF, 0, sizeof(struct coeff2ndorder));
//FMOD_memset(&mLatchRoomLF, 0, sizeof(struct coeff2ndorder));
FMOD_memset(&mRoomLFcoeffs, 0, sizeof(struct coeff2ndorder));
// mOldRoomLF.a0 = mPrevRoomLF.a0 = mLatchRoomLF.a0 =
mRoomLFcoeffs.a0 = 1.0f;
mRoomLF = 0.0f;
//mRoomLFChanged = false;
mDiffusionScale = 0.25f; // 0.3535; // cos^4(PI/4)
mAllpassGain = 0.63f; // ?
mPrevLRgain = mOldLRgain = mLatchLRgain = mLRgain = 0.0f; // ?
mLRgainChanged = false;
mPrevERgain = mOldERgain = mLatchERgain = mERgain = 0.0f; // ?
mERgainChanged = false;
ClearReverbInternalBuffers();
return 0;
}
void ASfxDsp::close()
{
if (mInBuffMemory)
{
FMOD_Memory_Free(mInBuffMemory);
mInBuffMemory = mInBuff = 0;
}
DeallocateLateDelays();
DeallocateEarlyLateDelay();
DeallocateAllpassDelays();
DeallocateEarlyDelay();
}
int ASfxDsp::AllocateLateDelays(int numDelays, float *delaySec, float sampleRate)
{
int delaySamples;
DeallocateLateDelays(); // *** But if it hasn't changed, we may want to skip all this... ***
for (int delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
delaySamples = (int)(delaySec[delayLine] * sampleRate) + 1;
delaySamples = NextPowerOf2(delaySamples);
// Allocate delay
if ((mLateDelays[delayLine] = (float*) FMOD_Memory_Calloc(delaySamples * sizeof(float))) == NULL)
{
return REVERB_LATE_ALLOCATION_ERR;
}
mLateDelaySamplesAllocated[delayLine] = delaySamples;
mLateMask[delayLine] = delaySamples - 1;
mLateWritePointer[delayLine] = 0;
}
return 0;
}
int ASfxDsp::AllocateEarlyLateDelay(float *delaySec, float sampleRate)
{
// Allocate it to the max Ref & Rev delays, so we don't have to reallocate it if the delays change.
float maxDelaySec = I3DL2LISTENER_MAXREFLECTIONSDELAY + I3DL2LISTENER_MAXREVERBDELAY
+ delaySec[kNumEarlyLateDelayTaps-1] - delaySec[kNumEarly_EarlyLateDelayTaps];
int delaySamples = (int)(maxDelaySec * sampleRate) + 1;
delaySamples = NextPowerOf2(delaySamples);
DeallocateEarlyLateDelay(); // *** But if it hasn't changed, we may want to skip all this... ***
// Allocate delay
if ((mEarlyLateDelay = (float*) FMOD_Memory_Calloc(delaySamples * sizeof(float))) == NULL)
{
return REVERB_EARLYLATE_ALLOCATION_ERR;
}
mEarlyLateSamplesAllocated = delaySamples;
mEarlyLateMask = delaySamples - 1;
return 0;
}
int ASfxDsp::AllocateAllpassDelays(int numDelays, float *delaySec, float sampleRate)
{
int delaySamples;
DeallocateAllpassDelays(); // *** But if it hasn't changed, we may want to skip all this... ***
for (int delayLine=0; delayLine<kNumAllpassDelays; delayLine++)
{
delaySamples = (int)(delaySec[delayLine] * sampleRate) + 1;
delaySamples = NextPowerOf2(delaySamples);
// Allocate delay
if ((mAllpassDelays[delayLine] = (float*) FMOD_Memory_Calloc(delaySamples * sizeof(float))) == NULL)
{
return REVERB_ALLPASS_ALLOCATION_ERR;
}
mAllpassSamplesAllocated[delayLine] = delaySamples;
mAllpassMask[delayLine] = delaySamples - 1;
mAllpassWritePointer[delayLine] = 0; // Do this here?
}
return 0;
}
int ASfxDsp::AllocateEarlyDelay(float delaySec, float sampleRate)
{
int delaySamples = (int)(delaySec * sampleRate) + 1;
delaySamples = NextPowerOf2(delaySamples);
DeallocateEarlyDelay(); // *** But if it hasn't changed, we may want to skip all this... ***
// Allocate delay
if ((mEarlyDelay = (float*) FMOD_Memory_Calloc(delaySamples * sizeof(float))) == NULL)
{
return REVERB_EARLY_ALLOCATION_ERR;
}
mEarlyDelaySamplesAllocated = delaySamples;
mEarlyMask = delaySamples - 1;
return 0;
}
int ASfxDsp::NextPowerOf2(int delaySamples)
{
return 1 << ((int)(FMOD_LOG((float)delaySamples) / FMOD_LOG(2.0f)) + 1);
}
void ASfxDsp::DeallocateLateDelays()
{
for (int delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
if (mLateDelays[delayLine])
{
FMOD_Memory_Free(mLateDelays[delayLine]);
}
mLateDelays[delayLine] = NULL;
}
}
void ASfxDsp::DeallocateAllpassDelays()
{
for (int delayLine=0; delayLine<kNumAllpassDelays; delayLine++)
{
if (mAllpassDelays[delayLine])
{
FMOD_Memory_Free(mAllpassDelays[delayLine]);
}
mAllpassDelays[delayLine] = NULL;
}
}
void ASfxDsp::DeallocateEarlyDelay()
{
if (mEarlyDelay)
{
FMOD_Memory_Free(mEarlyDelay);
}
mEarlyDelay = NULL;
}
void ASfxDsp::DeallocateEarlyLateDelay()
{
if (mEarlyLateDelay)
{
FMOD_Memory_Free(mEarlyLateDelay);
}
mEarlyLateDelay = NULL;
}
//-----------------------------------------------------------------------------
//#pragma export(UpdateBufferSize)
int ASfxDsp::UpdateBufferSize(int newMaxBlockSize)
{
// nothing to do if the maximum number of samples per processing block hasn't changed
if (newMaxBlockSize == mNumAllocatedInBuffSamples)
{
return 0; // buffer size wasn't changed
}
// update with the new value
mNumAllocatedInBuffSamples = newMaxBlockSize;
// (re)allocate audio buffers in mInBuff
if (mInBuffMemory != NULL)
{
FMOD_Memory_Free(mInBuffMemory);
}
mInBuffMemory = (float*) FMOD_Memory_Alloc((newMaxBlockSize * sizeof(float)) + 16);
if (!mInBuffMemory)
{
return REVERB_INBUFF_ALLOCATION_ERR;
}
mInBuff = (float *)FMOD_ALIGNPOINTER(mInBuffMemory, 16);
return 0; // buffer size changed
}
//-----------------------------------------------------------------------------
//#pragma export (ASfxDsp::ClearBuffers)
void ASfxDsp::ClearBuffers()
{
ClearInBuff();
ClearReverbInternalBuffers();
}
//-----------------------------------------------------------------------------
void ASfxDsp::ClearInBuff()
{
if (mInBuff != NULL)
{
// CHANGE THIS TO A BLOCK MOVE
for (int i=0; i < mNumAllocatedInBuffSamples; i++)
{
mInBuff[i] = 0.0f;
}
}
}
//-----------------------------------------------------------------------------
void ASfxDsp::ClearReverbInternalBuffers()
{
int delayLine;
if (mLateDelays)
{
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
if (mLateDelays[delayLine])
{
// *** CHANGE THESE TO BLOCK MOVES FOR BETTER EFFICIENCY ***
for (int samp=0; samp<mLateDelaySamplesAllocated[delayLine]; samp++)
{
mLateDelays[delayLine][samp] = 0.0f;
}
}
}
}
// Clear earlyLate delay line.
// Replace this with a block move.
int samp;
for (samp=0; samp<mEarlyLateSamplesAllocated; samp++)
{
mEarlyLateDelay[samp] = 0.0f;
}
// Clear early delay line.
// Replace this with a block move.
for (samp=0; samp<mEarlyDelaySamplesAllocated; samp++)
{
mEarlyDelay[samp] = 0.0f;
}
// Clear allpass delays
for (delayLine=0; delayLine<kNumAllpassDelays; delayLine++)
{
for (int samp=0; samp<mAllpassSamplesAllocated[delayLine]; samp++)
{
mAllpassDelays[delayLine][samp] = 0.0f;
}
}
// Zero the internal variables
FMOD_memset(mzDecayHF, 0, kNumLateReverbDelays * sizeof(float));
FMOD_memset(mMatrix, 0, kNumMatrixStages * kNumLateReverbDelays * sizeof(float));
mzRoomHF0 = 0.0f;
mzRoomHF1 = 0.0f;
mzRoomLF0 = 0.0f;
mzRoomLF1 = 0.0f;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ DoDSPProcessing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ASfxDsp::DoDSPProcessing (float * inAudio, float * outAudio, int channels, unsigned int l_sampframes,
float rate, float drymix, unsigned short speakermask)
{
unsigned int i;
int ch;
float eruOut[kNumEarlyDelayTaps + 1];
float val, oldVal;
int delayLine, delayTap;
unsigned int sampframes = (unsigned int)l_sampframes;
unsigned int sampframesmi; // sampframes - i
float invSampframes = 1.0f / (float)sampframes;
#ifdef ADD_ANTI_DENORMALS_TO_INPUT
#define VERY_SMALL_BUT_NOT_DENORMAL_VALUE (1.0e-15f)
// mix very quiet noise (-300 dB) into the input signal to hopefully avoid any denormal values
for (ch=0; ch < channels; ch++)
{
for (i=0; i < sampframes; i += 2)
{
outAudio[ch+channels*i] = inAudio[ch+channels*i] + VERY_SMALL_BUT_NOT_DENORMAL_VALUE;
}
for (i=1; i < sampframes; i += 2)
{
outAudio[ch+channels*i] = inAudio[ch+channels*i] - VERY_SMALL_BUT_NOT_DENORMAL_VALUE;
}
}
#undef VERY_SMALL_BUT_NOT_DENORMAL_VALUE
#endif
// Copy input into our input buffer. This may be faster than doing it inside the big loop.
BlockProcessInput(sampframes, channels, outAudio, rate);
// Adjust the EarlyLate read pointers in case Ref or Rev delays have changed
for (delayTap=0; delayTap<kNumEarlyLateDelayTaps; delayTap++)
{
mEarlyLateReadPointer[delayTap] = (mEarlyLateSamples[delayTap] + mEarlyLateWritePointer - 1) & mEarlyLateMask;
if (mEarlyLateSamples[delayTap] == mOldEarlyLateSamples[delayTap])
{
mEarlyLateChanged[delayTap] = false;
}
else // If the delay has changed, we need to do two reads and crossfade them.
{
mEarlyLateChanged[delayTap] = true;
mOldEarlyLateReadPointer[delayTap] = (mOldEarlyLateSamples[delayTap] + mEarlyLateWritePointer - 1) & mEarlyLateMask;
mOldEarlyLateSamples[delayTap] = mEarlyLateSamples[delayTap]; // For next time...
}
}
// Deal with interpolations and crossfades
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
// Adjust the Late read pointers in case late delay sizes have changed
mLateReadPointer[delayLine] = (mLateDelayLenSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
mLateReadPointerB[delayLine] = (mLateDelayLenBSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
if (mLateDelayLenSamples[delayLine] == mOldLateDelayLenSamples[delayLine])
{
mLateChanged[delayLine] = false;
}
else // If the late delays changed, we need to do two reads and crossfade them.
{
mLateChanged[delayLine] = true;
mOldLateReadPointer[delayLine] = (mOldLateDelayLenSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
mOldLateDelayLenSamples[delayLine] = mLateDelayLenSamples[delayLine]; // For next time...
}
mLatchFeedback[delayLine] = mFeedback[delayLine]; // Latch it in case it changes in the interim.
if (mLatchFeedback[delayLine] == mOldFeedback[delayLine])
{
mPrevFeedback[delayLine] = mLatchFeedback[delayLine]; // Use it for our crossfade (in case mFeedback hasn't changed)
}
else
{
if (!mLateChanged[delayLine]) // if we haven't made these changes above
{
mLateChanged[delayLine] = true;
mOldLateReadPointer[delayLine] = (mOldLateDelayLenSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
// We do this inside the 'if', because mOldLateDelayLenSamples gets changed above,
// which would change mOldLateReadPointer back to mLateReadPointer.
}
mPrevFeedback[delayLine] = mOldFeedback[delayLine]; // For our crossfade
mOldFeedback[delayLine] = mLatchFeedback[delayLine]; // For next time...
}
mLatchDecayHF[delayLine] = mDecayHF[delayLine]; // Latch it for our interpolation.
mLatchOneMinusDecayHF[delayLine] = 1.0f - mLatchDecayHF[delayLine];
if (mLatchDecayHF[delayLine] == mOldDecayHF[delayLine])
{
mDecayHFChanged[delayLine] = false;
}
else
{
mDecayHFChanged[delayLine] = true;
mPrevDecayHF[delayLine] = mOldDecayHF[delayLine]; // For our interpolation
mOldDecayHF[delayLine] = mLatchDecayHF[delayLine]; // For next time...
}
}
mLatchLRgain = mLRgain;
if (mLatchLRgain == mOldLRgain)
{
mLRgainChanged = false;
}
else
{
mLRgainChanged = true;
mPrevLRgain = mOldLRgain; // For our interpolation
mOldLRgain = mLatchLRgain; // For next time
}
mLatchERgain = mERgain;
if (mLatchERgain == mOldERgain)
{
mERgainChanged = false;
}
else
{
mERgainChanged = true;
mPrevERgain = mOldERgain; // For our interpolation
mOldERgain = mLatchERgain; // For next time
}
mLatchRoomHF = mRoomHF;
if (mLatchRoomHF == mOldRoomHF)
{
mRoomHFChanged = false;
}
else
{
mRoomHFChanged = true;
mPrevRoomHF = mOldRoomHF; // For our interpolation
mOldRoomHF = mLatchRoomHF; // For next time
}
mLatchHadamard = mHadamard;
if (mLatchHadamard == mOldHadamard)
{
mHadamardChanged = false;
}
else
{
mHadamardChanged = true;
mPrevHadamard = mOldHadamard; // For our interpolation
mOldHadamard = mLatchHadamard; // For next time
}
mLatchDiffusionScale = mDiffusionScale;
if (mLatchDiffusionScale == mOldDiffusionScale)
{
mDiffusionScaleChanged = false;
}
else
{
mDiffusionScaleChanged = true;
mPrevDiffusionScale = mOldDiffusionScale; // For our interpolation
mOldDiffusionScale = mLatchDiffusionScale; // For next time
}
/*
mLatchRoomLF = mRoomLF;
if (mLatchRoomLF == mOldRoomLF)
{
mRoomLFChanged = false;
}
else
{
mRoomLFChanged = true;
mPrevRoomLF = mOldRoomLF; // For our interpolation
mOldRoomLF = mLatchRoomLF; // For next time
}
*/
// Now start the Big DSP Loop...
for (i=0; i<sampframes; i++) // for each sample
{
sampframesmi = sampframes - i;
val = (float)mInBuff[i];
// Room HF low-pass filters
float roomHF, hadamard, diffusionscale;
if (mRoomHFChanged)
{
roomHF = ((mPrevRoomHF * sampframesmi) + (mLatchRoomHF * i)) * invSampframes;
}
else
{
roomHF = mLatchRoomHF;
}
if (mHadamardChanged)
{
hadamard = ((mPrevHadamard * sampframesmi) + (mLatchHadamard * i)) * invSampframes;
}
else
{
hadamard = mLatchHadamard;
}
if (mDiffusionScaleChanged)
{
diffusionscale = ((mPrevDiffusionScale * sampframesmi) + (mLatchDiffusionScale * i)) * invSampframes;
}
else
{
diffusionscale = mLatchDiffusionScale;
}
/*
Room LF - 2nd order high pass filter, don't interpolate yet
if(mRoomLFChanged)
{
roomLF = ((mPrevRoomLF * sampframesmi) + (mLatchRoomLF * i)) * invSampframes;
}
else
{
roomLF = mLatchRoomLF;
}
*/
float oneMinusRoomHF = 1.0f - roomHF;
mzRoomHF0 = val*roomHF + mzRoomHF0*oneMinusRoomHF;
mzRoomHF1 = mzRoomHF0*roomHF + mzRoomHF1*oneMinusRoomHF;
float fout;
if(mRoomLF != 0.0f)
{
fout = mzRoomHF1 * mRoomLFcoeffs.a0 + mzRoomLF0;
mzRoomLF0 = mzRoomHF1 * mRoomLFcoeffs.a1 + mzRoomLF1 + fout * mRoomLFcoeffs.b1;
mzRoomLF1 = mzRoomHF1 * mRoomLFcoeffs.a2 + fout * mRoomLFcoeffs.b2;
}
else
{
fout = mzRoomHF1;
}
// Insert Delay here
mEarlyLateWritePointer = --mEarlyLateWritePointer & mEarlyLateMask;
mEarlyLateDelay[mEarlyLateWritePointer] = fout;
// ================== Early Reflections ==================
mEarlyLateReadPointer[0] = --mEarlyLateReadPointer[0] & mEarlyLateMask;
float input, output, ERgain;
if (mERgainChanged)
{
ERgain = ((mPrevERgain * sampframesmi) + (mLatchERgain * i)) * invSampframes;
}
else
{
ERgain = mLatchERgain;
}
input = mEarlyLateDelay[mEarlyLateReadPointer[0]] * ERgain;
if (mEarlyLateChanged[0]) // Crossfade the old and new reads
{
mOldEarlyLateReadPointer[0] = --mOldEarlyLateReadPointer[0] & mEarlyLateMask;
float oldInput = mEarlyLateDelay[mOldEarlyLateReadPointer[0]] * ERgain;
input = ((oldInput * sampframesmi) + (input * i)) * invSampframes;
}
// 2 Allpasses in series
for (delayLine=0; delayLine<kNumAllpassDelays; delayLine++)
{
mAllpassWritePointer[delayLine] = --mAllpassWritePointer[delayLine] & mAllpassMask[delayLine];
mAllpassReadPointer[delayLine] = --mAllpassReadPointer[delayLine] & mAllpassMask[delayLine];
output = mAllpassDelays[delayLine][mAllpassReadPointer[delayLine]]
- input * mAllpassGain; // feedforward loop
mAllpassDelays[delayLine][mAllpassWritePointer[delayLine]] =
input + output * mAllpassGain; // feedback loop
input = output;
}
// Early Delay FIR
eruOut[0] = output;
mEarlyWritePointer = --mEarlyWritePointer & mEarlyMask;
mEarlyDelay[mEarlyWritePointer] = output;
for (delayTap=0; delayTap<kNumEarlyDelayTaps; delayTap++)
{
mEarlyReadPointer[delayTap] = --mEarlyReadPointer[delayTap] & mEarlyMask;
eruOut[delayTap+1] = mEarlyDelay[mEarlyReadPointer[delayTap]];
}
// ================== Late Reverb ====================
// This assumes mNumLateReverbDelays = kNumLate_EarlyLateDelayTaps.
for (delayLine=0; delayLine<mNumLateReverbDelays; delayLine++)
{
delayTap = kNumEarly_EarlyLateDelayTaps + delayLine;
mEarlyLateReadPointer[delayTap] = --mEarlyLateReadPointer[delayTap] & mEarlyLateMask;
val = mEarlyLateDelay[mEarlyLateReadPointer[delayTap]];
if (mEarlyLateChanged[delayTap]) // Crossfade the old and new reads
{
mOldEarlyLateReadPointer[delayTap] = --mOldEarlyLateReadPointer[delayTap] & mEarlyLateMask;
oldVal = mEarlyLateDelay[mOldEarlyLateReadPointer[delayTap]];
val = ((oldVal * sampframesmi) + (val * i)) * invSampframes;
}
if (mLRgainChanged)
{
float LRgain = ((mPrevLRgain * sampframesmi) + (mLatchLRgain * i)) * invSampframes;
val *= LRgain;
}
else
{
val *= mLatchLRgain;
}
mLateReadPointer[delayLine] = --mLateReadPointer[delayLine] & mLateMask[delayLine];
if (mLateChanged[delayLine]) // Crossfade
{
mOldLateReadPointer[delayLine] = --mOldLateReadPointer[delayLine] & mLateMask[delayLine];
oldVal = mPrevFeedback[delayLine] * mLateDelays[delayLine][mOldLateReadPointer[delayLine]];
float thisVal = mLatchFeedback[delayLine] * mLateDelays[delayLine][mLateReadPointer[delayLine]];
val += (((oldVal * sampframesmi) + (thisVal * i)) * invSampframes);
}
else
{
val += (mLatchFeedback[delayLine] * mLateDelays[delayLine][mLateReadPointer[delayLine]]);
}
// Gain to compensate for one matrix gain, based on the diffusion.
// val *= mDiffusionScale;
val *= diffusionscale;
// Low-pass filter for HF Decay ratio
if (mDecayHFChanged[delayLine])
{
// Interpolate decayHF
float decayHF = ((mPrevDecayHF[delayLine] * sampframesmi) + (mLatchDecayHF[delayLine] * i)) * invSampframes;
float oneMinusDecayHF = 1.0f - decayHF;
mzDecayHF[delayLine] = val * decayHF + mzDecayHF[delayLine] * oneMinusDecayHF;
}
else
{
mzDecayHF[delayLine] = val * mLatchDecayHF[delayLine] + mzDecayHF[delayLine] * mLatchOneMinusDecayHF[delayLine];
}
mLateWritePointer[delayLine] = --mLateWritePointer[delayLine] & mLateMask[delayLine];
}
mMatrix[0 * kNumLateReverbDelays + 0] = mzDecayHF[0] + mzDecayHF[1] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 1] = mzDecayHF[1] - mzDecayHF[0] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 2] = mzDecayHF[2] + mzDecayHF[3] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 3] = mzDecayHF[3] - mzDecayHF[2] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 4] = mzDecayHF[4] + mzDecayHF[5] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 5] = mzDecayHF[5] - mzDecayHF[4] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 6] = mzDecayHF[6] + mzDecayHF[7] * hadamard;
mMatrix[0 * kNumLateReverbDelays + 7] = mzDecayHF[7] - mzDecayHF[6] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 0] = mMatrix[0 * kNumLateReverbDelays + 0] + mMatrix[0 * kNumLateReverbDelays + 2] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 1] = mMatrix[0 * kNumLateReverbDelays + 1] + mMatrix[0 * kNumLateReverbDelays + 3] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 2] = mMatrix[0 * kNumLateReverbDelays + 2] - mMatrix[0 * kNumLateReverbDelays + 0] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 3] = mMatrix[0 * kNumLateReverbDelays + 3] - mMatrix[0 * kNumLateReverbDelays + 1] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 4] = mMatrix[0 * kNumLateReverbDelays + 4] + mMatrix[0 * kNumLateReverbDelays + 6] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 5] = mMatrix[0 * kNumLateReverbDelays + 5] + mMatrix[0 * kNumLateReverbDelays + 7] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 6] = mMatrix[0 * kNumLateReverbDelays + 6] - mMatrix[0 * kNumLateReverbDelays + 4] * hadamard;
mMatrix[1 * kNumLateReverbDelays + 7] = mMatrix[0 * kNumLateReverbDelays + 7] - mMatrix[0 * kNumLateReverbDelays + 5] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 0] = mMatrix[1 * kNumLateReverbDelays + 0] + mMatrix[1 * kNumLateReverbDelays + 4] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 1] = mMatrix[1 * kNumLateReverbDelays + 1] + mMatrix[1 * kNumLateReverbDelays + 5] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 2] = mMatrix[1 * kNumLateReverbDelays + 2] + mMatrix[1 * kNumLateReverbDelays + 6] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 3] = mMatrix[1 * kNumLateReverbDelays + 3] + mMatrix[1 * kNumLateReverbDelays + 7] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 4] = mMatrix[1 * kNumLateReverbDelays + 4] - mMatrix[1 * kNumLateReverbDelays + 0] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 5] = mMatrix[1 * kNumLateReverbDelays + 5] - mMatrix[1 * kNumLateReverbDelays + 1] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 6] = mMatrix[1 * kNumLateReverbDelays + 6] - mMatrix[1 * kNumLateReverbDelays + 2] * hadamard;
mMatrix[2 * kNumLateReverbDelays + 7] = mMatrix[1 * kNumLateReverbDelays + 7] - mMatrix[1 * kNumLateReverbDelays + 3] * hadamard;
// Write to the lateDelays
mLateDelays[0][mLateWritePointer[0]] = mMatrix[2 * kNumLateReverbDelays + 1];
mLateDelays[1][mLateWritePointer[1]] = mMatrix[2 * kNumLateReverbDelays + 2];
mLateDelays[2][mLateWritePointer[2]] = mMatrix[2 * kNumLateReverbDelays + 3];
mLateDelays[3][mLateWritePointer[3]] = mMatrix[2 * kNumLateReverbDelays + 4];
mLateDelays[4][mLateWritePointer[4]] = mMatrix[2 * kNumLateReverbDelays + 5];
mLateDelays[5][mLateWritePointer[5]] = mMatrix[2 * kNumLateReverbDelays + 6];
mLateDelays[6][mLateWritePointer[6]] = mMatrix[2 * kNumLateReverbDelays + 7];
mLateDelays[7][mLateWritePointer[7]] = mMatrix[2 * kNumLateReverbDelays + 0];
for (ch=0; ch<channels; ch++) // for each channel
{
if (!((1 << ch) & speakermask))
{
outAudio[i*channels+ch] = inAudio[i*channels+ch];
}
else
{
float lruSum = 0.0f;
float eruSum = 0.0f;
int nextDelay = ch;
for (int delay=0; delay<(kNumLateReverbDelays/channels); delay++)
{
mLateReadPointerB[nextDelay] = --mLateReadPointerB[nextDelay] & mLateMask[nextDelay];
lruSum += mLateDelays[nextDelay][mLateReadPointerB[nextDelay]];
eruSum += eruOut[nextDelay];
nextDelay += channels;
}
if (drymix == 0.0f)
{
outAudio[i*channels+ch] = eruSum + lruSum;
}
else
{
outAudio[i*channels+ch] = (inAudio[i*channels+ch] * drymix) + eruSum + lruSum;
}
}
} // end for each channel
} // end for each sample
} // end DoDSPProcessing
// Copy input into our input buffer. This may be faster than doing it inside the big loop (?).
void ASfxDsp::BlockProcessInput(unsigned int sampframes, int channels, float *inAudio, float rate)
{
unsigned int i;
if (channels == 1) // mono
{
SfxDataMove(inAudio, mInBuff, sampframes*sizeof(float));
}
else if (channels == 6)
{
float *inptr = inAudio;
float *outptr = mInBuff;
for (i = 0; i < sampframes / 4; i++) // for each sample
{
outptr[0] = inptr[0] + inptr[1] + inptr[2] + inptr[3] + inptr[4] + inptr[5];
outptr[1] = inptr[6] + inptr[7] + inptr[8] + inptr[9] + inptr[10] + inptr[11];
outptr[2] = inptr[12] + inptr[13] + inptr[14] + inptr[15] + inptr[16] + inptr[17];
outptr[3] = inptr[18] + inptr[19] + inptr[20] + inptr[21] + inptr[22] + inptr[23];
inptr += 24;
outptr += 4;
}
}
else if (channels == 8)
{
float *inptr = inAudio;
float *outptr = mInBuff;
for (i = 0; i < sampframes / 4; i++) // for each sample
{
outptr[0] = inptr[0] + inptr[1] + inptr[2] + inptr[3] + inptr[4] + inptr[5] + inptr[6] + inptr[7];
outptr[1] = inptr[8] + inptr[9] + inptr[10] + inptr[11] + inptr[12] + inptr[13] + inptr[14] + inptr[15];
outptr[2] = inptr[16] + inptr[17] + inptr[18] + inptr[19] + inptr[20] + inptr[21] + inptr[22] + inptr[23];
outptr[3] = inptr[24] + inptr[25] + inptr[26] + inptr[27] + inptr[28] + inptr[29] + inptr[30] + inptr[31];
inptr += 32;
outptr += 4;
}
}
else
{
int ch;
for (i=0; i<sampframes; i++) // for each sample
{
mInBuff[i] = 0.0f;
for (ch=0; ch<channels; ++ch) // for each channel
{
mInBuff[i] += inAudio[i*channels+ch]; // *** Would it be more efficient to reverse the loops? ***
}
// mInBuff[i] /= (float)channels; // Don't average them!
}
}
}
void ASfxDsp::SetLate_EarlyLateDelayTaps(float refPlusRevDelaySec, float nextLengthSec, float delayRatio, float rate)
{
mEarlyLateSec[kNumEarly_EarlyLateDelayTaps] = refPlusRevDelaySec; // Tap 1 = Ref+Rev delay
int earlyLateSamples = (int)(refPlusRevDelaySec * rate);
if (earlyLateSamples == 0)
{
earlyLateSamples++; // Avoid long wrap-around delay.
}
mEarlyLateSamples[kNumEarly_EarlyLateDelayTaps] = earlyLateSamples;
// Set the remaining EarlyLate delay taps (2 - 8)
for (int delayTap=kNumEarly_EarlyLateDelayTaps+1; delayTap<kNumEarlyLateDelayTaps; delayTap++)
{
mEarlyLateSec[delayTap] = refPlusRevDelaySec + nextLengthSec;
mEarlyLateSamples[delayTap] = (int)(mEarlyLateSec[delayTap] * rate);
nextLengthSec *= delayRatio;
}
}
void ASfxDsp::SetAllpassDelays(float rate)
{
mAllpassDelayLenSec[0] = kAllpassDelayLenSec0;
mAllpassDelayLenSec[1] = kAllpassDelayLenSec1;
for (int delayLine = 0; delayLine<kNumAllpassDelays; delayLine++)
{
mAllpassDelayLenSamples[delayLine] = (int)(mAllpassDelayLenSec[delayLine] * rate);
mAllpassReadPointer[delayLine] = mAllpassDelayLenSamples[delayLine] - 1;
}
}
void ASfxDsp::SetEarlyDelay(float nextLengthSec, float delayRatio, float rate)
{
// Set the early delay taps (0 - 6)
for (int delayLine=0; delayLine<kNumEarlyDelayTaps; delayLine++)
{
mEarlyDelayLenSec[delayLine] = nextLengthSec;
mEarlyDelayLenSamples[delayLine] = (int)(nextLengthSec * rate);
nextLengthSec *= delayRatio;
mEarlyReadPointer[delayLine] = mEarlyDelayLenSamples[delayLine] - 1;
}
}
void ASfxDsp::SetLateDelays(float nextLengthSec, float delayRatio, float nextLengthBSec, float delayRatioB, float rate)
{
float nextLengthSamples;
float nextLengthBSamples = nextLengthBSec * rate;
for (int delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
// Set main delay line lengths
mLateDelayLenSec[delayLine] = nextLengthSec;
nextLengthSamples = nextLengthSec * rate;
mLateDelayLenSamples[delayLine] = (int)(nextLengthSamples + 0.5);
nextLengthSec *= delayRatio;
mLateReadPointer[delayLine] = (mLateDelayLenSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
// Set delay line lengths for B reads
mLateDelayLenBSamples[delayLine] = (int)(nextLengthBSamples + 0.5); // Short delays to keep outputs from cancelling.
nextLengthBSamples *= delayRatioB;
mLateReadPointerB[delayLine] = (mLateDelayLenBSamples[delayLine] + mLateWritePointer[delayLine] - 1)
& mLateMask[delayLine];
}
}
void ASfxDsp::ZeroWritePointers()
{
int delayLine;
mEarlyWritePointer = 0;
mEarlyLateWritePointer = 0;
for (delayLine=0; delayLine<kNumAllpassDelays; delayLine++)
{
mAllpassWritePointer[delayLine] = 0;
}
for (delayLine=0; delayLine<kNumLateReverbDelays; delayLine++)
{
mLateWritePointer[delayLine] = 0;
}
}

223
lib/sfx/foreverb/aSfxDsp.hpp Executable file
View file

@ -0,0 +1,223 @@
#ifndef __ASFXDSP_H
#define __ASFXDSP_H
#include "../../../src/fmod_settings.h"
#include "../../../src/fmod_types.h"
#include <math.h>
struct DspValues
{
short reinitialize; // 0 means in progress. 1 means settings have changed, start over
};
struct coeff2ndorder
{
float a0, a1, a2, b1, b2;
};
#define kNumLateReverbDelays 8
// Only feed the first 8 or so late reverb inputs at first?
#define kNumMatrixStages 3 // 2 ^ kNumMatrixStages should equal kNumLateReverbDelays
#define kNumEarly_EarlyLateDelayTaps 1
#define kNumLate_EarlyLateDelayTaps 8 // Should equal kNumLateReverbDelays
#define kNumEarlyLateDelayTaps (kNumEarly_EarlyLateDelayTaps + kNumLate_EarlyLateDelayTaps)
#define kNumEarlyDelayTaps 7
#define kNumAllpassDelays 2
#define kSFXREVERB_MAXCHANNELS 8
#define kEarlyLateDelayLen 65536 // Delete
#define kEarlyDelayLenSamples 16384 // Delete
#define kAllpassLengthSamples 2048 // Delete
// Main late delays
#define LOWEST_DELAY_LINE_LENGTH_SEC (0.061f)
#define DELAY_LINE_RATIO (1.32f)
#define LOWEST_DELAY_LINE_LENGTH_B_SEC (0.0015f)
#define DELAY_LINE_RATIO_B (1.47f)
// Allpass delays
#define kAllpassDelayLenSec0 (0.0059f)
#define kAllpassDelayLenSec1 (0.0077f)
// EarlyLate delays
#define kEarlyLateNextLengthSec (0.0187f)
#define kEarlyLateDelayRatio (1.29f)
// Early delays
#define kEarlyFirstDelaySec (0.005f)
#define kEarlyDelayRatio (1.59f)
// Error codes
#define REVERB_ALLPASS_ALLOCATION_ERR 4500
#define REVERB_EARLYLATE_ALLOCATION_ERR 4501
#define REVERB_EARLY_ALLOCATION_ERR 4502
#define REVERB_LATE_ALLOCATION_ERR 4503
#define REVERB_PARAMETER_ERROR 4504
#define REVERB_INBUFF_ALLOCATION_ERR 4505
namespace FMOD
{
class SystemI;
}
class ASfxDsp
{
public:
int init(float rate);
void close();
int UpdateBufferSize(int newMaxBlockSize); // possibly reallocate mInBuff buffers to new MaxBlockSize
void ClearBuffers(); // zero the audio buffers
void ClearInBuff();
void ClearReverbInternalBuffers();
int AllocateEarlyLateDelay(float *delaySec, float sampleRate);
int AllocateAllpassDelays(int numDelays, float *delaySec, float sampleRate);
int AllocateEarlyDelay(float delaySec, float sampleRate);
int AllocateLateDelays(int numDelays, float *delaySec, float sampleRate);
int NextPowerOf2(int delaySamples);
void DoDSPProcessing (float *inAudio, float *outAudio, int channels, unsigned int sampleframes, float rate, float drymix, unsigned short speakermask);
void BlockProcessInput(unsigned int sampframes, int channels, float *inAudio, float rate);
public:
void SetAllpassDelays(float rate);
void SetLate_EarlyLateDelayTaps(float refPlusRevDelaySec, float nextLengthSec, float delayRatio, float rate);
void SetEarlyDelay(float nextLengthSec, float delayRatio, float rate);
void SetLateDelays(float nextLengthSec, float delayRatio, float nextLengthBSec, float delayRatioB, float rate);
void DeallocateLateDelays();
void DeallocateAllpassDelays();
void DeallocateEarlyLateDelay();
void DeallocateEarlyDelay();
void ZeroWritePointers();
#if defined(PLATFORM_PS3) //|| defined(PLATFORM_WINDOWS_PS3MODE)
float mInBuffMemory[256 + 4]; /* +4 = 16bytes extra for alignment */
#else
float *mInBuffMemory;
#endif
float *mInBuff;
int mNumAllocatedInBuffSamples; // the number of samples per mInBuff currently allocated
// (varies according to MaxBlockSize)
#if defined(PLATFORM_PS3) //|| defined(PLATFORM_WINDOWS_PS3MODE)
float FMOD_PPCALIGN16(mTempbuff[(9*256) + 4]); // 8k
#endif
FMOD::SystemI *mSystem;
float mRoomHF;
bool mRoomHFChanged;
float mLatchRoomHF; // Latch it for safety
float mPrevRoomHF; // For our interpolation
float mOldRoomHF; // For next time
float mzRoomHF0, mzRoomHF1;
struct coeff2ndorder mRoomLFcoeffs;
float mRoomLF;
float mzRoomLF0, mzRoomLF1;
float FMOD_PPCALIGN16(mDecayHF[kNumLateReverbDelays]);
bool FMOD_PPCALIGN16(mDecayHFChanged[kNumLateReverbDelays]);
float FMOD_PPCALIGN16(mLatchDecayHF[kNumLateReverbDelays]); // Latch it for safety.
float FMOD_PPCALIGN16(mLatchOneMinusDecayHF[kNumLateReverbDelays]);
float FMOD_PPCALIGN16(mPrevDecayHF[kNumLateReverbDelays]); // Latch previous one
float FMOD_PPCALIGN16(mOldDecayHF[kNumLateReverbDelays]); // Save current one for next time...
float FMOD_PPCALIGN16(mMatrixMem[kNumMatrixStages * kNumLateReverbDelays + 16]);
float FMOD_PPCALIGN16(mzDecayHFMem[kNumLateReverbDelays + 16]);
float *FMOD_PPCALIGN16(mzDecayHF);
float *FMOD_PPCALIGN16(mMatrix);
float FMOD_PPCALIGN16(mFeedback[kNumLateReverbDelays]);
float FMOD_PPCALIGN16(mLatchFeedback[kNumLateReverbDelays]); // Latch it for safety
float FMOD_PPCALIGN16(mOldFeedback[kNumLateReverbDelays]); // Save for next buffer
float FMOD_PPCALIGN16(mPrevFeedback[kNumLateReverbDelays]); // Use previous value for crossfade
float mHadamard;
bool mHadamardChanged;
float mLatchHadamard; // Latch it for safety
float mPrevHadamard; // For our interpolation
float mOldHadamard; // For next time
float mERgain, mLRgain;
bool mLRgainChanged;
float mLatchLRgain; // Latch it for safety
float mPrevLRgain; // For our interpolation
float mOldLRgain; // For next time
bool mERgainChanged;
float mLatchERgain; // Latch it for safety
float mPrevERgain; // For our interpolation
float mOldERgain; // For next time
float mDiffusionScale;
bool mDiffusionScaleChanged;
float mLatchDiffusionScale; // Latch it for safety
float mPrevDiffusionScale; // For our interpolation
float mOldDiffusionScale; // For next time
float mAllpassGain;
int mNumLateReverbDelays;
// Late delays
#if defined(PLATFORM_PS3) //|| defined(PLATFORM_WINDOWS_PS3MODE)
float *FMOD_PPCALIGN16(mLateDelaysMemory[kNumLateReverbDelays]);
#endif
float *FMOD_PPCALIGN16(mLateDelays[kNumLateReverbDelays]); // Array of delay lines
float FMOD_PPCALIGN16(mLateDelayLenSec[kNumLateReverbDelays]); // Seconds
int FMOD_PPCALIGN16(mLateDelayLenSamples[kNumLateReverbDelays]); // Samples used
int FMOD_PPCALIGN16(mOldLateDelayLenSamples[kNumLateReverbDelays]);
int FMOD_PPCALIGN16(mLateDelayLenBSamples[kNumLateReverbDelays]); // Samples used
int FMOD_PPCALIGN16(mLateDelaySamplesAllocated[kNumLateReverbDelays]); // Samples allocated
bool FMOD_PPCALIGN16(mLateChanged[kNumLateReverbDelays]); // Either the delay lengths or mFeedback changed
int FMOD_PPCALIGN16(mLateMask[kNumLateReverbDelays]);
int FMOD_PPCALIGN16(mLateWritePointer[kNumLateReverbDelays]);
int FMOD_PPCALIGN16(mLateReadPointer[kNumLateReverbDelays]);
int FMOD_PPCALIGN16(mOldLateReadPointer[kNumLateReverbDelays]);
int FMOD_PPCALIGN16(mLateReadPointerB[kNumLateReverbDelays]); // Short (~10 ms) reads to avoid cancellations
// EarlyLate delay
float *FMOD_PPCALIGN16(mEarlyLateDelay);
float *FMOD_PPCALIGN16(mEarlyLateDelayMemory);
float FMOD_PPCALIGN16(mEarlyLateSec[kNumEarlyLateDelayTaps]);
int FMOD_PPCALIGN16(mEarlyLateSamples[kNumEarlyLateDelayTaps]);
int FMOD_PPCALIGN16(mOldEarlyLateSamples[kNumEarlyLateDelayTaps]);
bool FMOD_PPCALIGN16(mEarlyLateChanged[kNumEarlyLateDelayTaps]);
int FMOD_PPCALIGN16(mEarlyLateSamplesAllocated);
int FMOD_PPCALIGN16(mEarlyLateMask);
int FMOD_PPCALIGN16(mEarlyLateWritePointer);
int FMOD_PPCALIGN16(mEarlyLateReadPointer[kNumEarlyLateDelayTaps]);
int FMOD_PPCALIGN16(mOldEarlyLateReadPointer[kNumEarlyLateDelayTaps]);
// Early delay
#if defined(PLATFORM_PS3) //|| defined(PLATFORM_WINDOWS_PS3MODE)
float FMOD_PPCALIGN16(mEarlyDelay[4096]);
#else
float *mEarlyDelay;
#endif
float FMOD_PPCALIGN16(mEarlyDelayLenSec[kNumEarlyDelayTaps]);
int FMOD_PPCALIGN16(mEarlyDelayLenSamples[kNumEarlyDelayTaps]);
int FMOD_PPCALIGN16(mEarlyDelaySamplesAllocated);
int FMOD_PPCALIGN16(mEarlyMask);
int FMOD_PPCALIGN16(mEarlyWritePointer);
int FMOD_PPCALIGN16(mEarlyReadPointer[kNumEarlyDelayTaps]);
// Allpass delays
#if defined(PLATFORM_PS3) //|| defined(PLATFORM_WINDOWS_PS3MODE)
float FMOD_PPCALIGN16(mAllpassDelays[kNumAllpassDelays][512]);
#else
float *mAllpassDelays[kNumAllpassDelays];
#endif
float FMOD_PPCALIGN16(mAllpassDelayLenSec[kNumAllpassDelays]);
int FMOD_PPCALIGN16(mAllpassDelayLenSamples[kNumAllpassDelays]);
int FMOD_PPCALIGN16(mAllpassSamplesAllocated[kNumAllpassDelays]);
int FMOD_PPCALIGN16(mAllpassMask[kNumAllpassDelays]);
int FMOD_PPCALIGN16(mAllpassWritePointer[kNumAllpassDelays]);
int FMOD_PPCALIGN16(mAllpassReadPointer[kNumAllpassDelays]);
int mNumMatrixStages;
};
#endif // __ASFXDSP_H