inline float Process(float input) { float g = 1.0f; float s = FastClip(input * input, 1.0e-11f, 100.0f); float timeConst = (s > env) ? atk : rel; env += (s - env) * timeConst + 1.0e-16f; // add small constant to always positive number to avoid denormal numbers float sideChainLevel = 10.0f * log10f(env); // multiply by 10 (not 20) because duckEnvelope is RMS float t = sideChainLevel - thr; if (fabsf(t) < knee) { t += knee; g = powf(exp1, t * t); } else if (t > 0.0f) g = powf(exp2, t); reduction = g; return input * g; }
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ProcessCallback(UnityAudioEffectState* state, float* inbuffer, float* outbuffer, unsigned int length, int inchannels, int outchannels) { EffectData::Data* data = &state->GetEffectData<EffectData>()->data; const float atksamples = data->p[P_ATK] * state->samplerate; const float relsamples = data->p[P_REL] * state->samplerate; const float atkconst = (atksamples <= 1.0f) ? 1.0f : (1.0f - powf(0.01f, 1.0f / atksamples)); const float relconst = (relsamples <= 1.0f) ? 1.0f : (1.0f - powf(0.01f, 1.0f / relsamples)); const float bw = powf(1.0f - 0.999f * data->p[P_RESO], 3.0f); for (int i = 0; i < inchannels; i++) { EffectData::Data::Channel& ch = data->channels[i]; ch.filter1.bandwidth = bw; ch.filter2.bandwidth = bw; float* src = inbuffer + i; float* dst = outbuffer + i; float* sc = state->sidechainbuffer + i; for (unsigned int n = 0; n < length; n++) { float s = *src; float a = fabsf(s + (*sc - s) * data->p[P_SIDECHAIN]); ch.env += (a - ch.env) * ((a > ch.env) ? atkconst : relconst); ch.filter1.cutoff = FastClip(data->p[P_BASE] + ch.env * data->p[P_SENS], 0.0f, 1.4f); ch.filter2.cutoff = ch.filter1.cutoff; ch.filter2.ProcessLPF(ch.filter1.ProcessLPF(*src)); float lpf = ch.filter1.lpf + (ch.filter2.lpf - ch.filter1.lpf) * data->p[P_DEPTH]; float bpf = ch.filter1.bpf + (ch.filter2.bpf - ch.filter1.bpf) * data->p[P_DEPTH]; *dst = lpf + (bpf - lpf) * data->p[P_TYPE]; src += inchannels; dst += outchannels; sc += inchannels; } } return UNITY_AUDIODSP_OK; }