add program-dependent attack/release times

This commit is contained in:
2025-08-01 15:35:14 +02:00
parent 5b7385df07
commit 1ab0d89b00

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "audio_math.h" #include "audio_math.h"
#include "rms_detector.h" #include "rms_detector.h"
#include <algorithm>
#include <cmath> #include <cmath>
namespace trnr { namespace trnr {
@@ -30,6 +31,7 @@ inline float hp_filter_process(hp_filter& f, float x)
struct oneknob_comp { struct oneknob_comp {
// params // params
float amount = 0.f; float amount = 0.f;
bool multiplied = false;
// state // state
rms_detector detector; rms_detector detector;
@@ -38,9 +40,10 @@ struct oneknob_comp {
float release_coef; float release_coef;
float envelope_level; float envelope_level;
float sidechain_in; float sidechain_in;
double samplerate;
}; };
inline void oneknob_init(oneknob_comp& c, float samplerate, float window_ms) inline void oneknob_init(oneknob_comp& c, double samplerate, float window_ms)
{ {
rms_init(c.detector, samplerate, window_ms); rms_init(c.detector, samplerate, window_ms);
hp_filter_init(c.filter, samplerate); hp_filter_init(c.filter, samplerate);
@@ -48,6 +51,7 @@ inline void oneknob_init(oneknob_comp& c, float samplerate, float window_ms)
const float attack_ms = 0.2f; const float attack_ms = 0.2f;
const float release_ms = 150.f; const float release_ms = 150.f;
c.samplerate = samplerate;
c.attack_coef = expf(-1.0f / (attack_ms * 1e-6 * samplerate)); c.attack_coef = expf(-1.0f / (attack_ms * 1e-6 * samplerate));
c.release_coef = expf(-1.0f / (release_ms * 1e-3 * samplerate)); c.release_coef = expf(-1.0f / (release_ms * 1e-3 * samplerate));
c.envelope_level = -60.f; c.envelope_level = -60.f;
@@ -59,11 +63,17 @@ inline void oneknob_process_block(oneknob_comp& c, sample** audio, int frames)
{ {
const float min_user_ratio = 1.0f; const float min_user_ratio = 1.0f;
const float max_user_ratio = 20.0f; const float max_user_ratio = 20.0f;
const float threshold_db = -9.f; const float threshold_db = -12.f;
const float amount = fmaxf(0.0f, fminf(powf(c.amount, 2.f), 1.0f)); // clamp to [0, 1] const float amount = fmaxf(0.0f, fminf(powf(c.amount, 2.f), 1.0f));
float ratio = min_user_ratio + amount * (max_user_ratio - min_user_ratio); float ratio = min_user_ratio + amount * (max_user_ratio - min_user_ratio);
const float fast_attack = 0.1f;
const float slow_attack = 0.6f;
const float fast_release = 90.f;
const float slow_release = 300.f;
const float max_gr = 24.f;
for (int i = 0; i < frames; ++i) { for (int i = 0; i < frames; ++i) {
float rms_value = rms_process<sample>(c.detector, c.sidechain_in); float rms_value = rms_process<sample>(c.detector, c.sidechain_in);
float envelope_in = lin_2_db(fmaxf(fabs(rms_value), 1e-20f)); float envelope_in = lin_2_db(fmaxf(fabs(rms_value), 1e-20f));
@@ -89,8 +99,17 @@ inline void oneknob_process_block(oneknob_comp& c, sample** audio, int frames)
audio[0][i] *= gain_reduction_lin; audio[0][i] *= gain_reduction_lin;
audio[1][i] *= gain_reduction_lin; audio[1][i] *= gain_reduction_lin;
// calculate program-dependent attack/release times
float norm_gr = std::clamp(gain_reduction_db / max_gr, 0.f, 1.f);
float release_ms = fast_release + (slow_release - fast_release) * (1.f - norm_gr);
float attack_ms = fast_attack + (slow_attack - fast_attack) * (1.f - norm_gr);
c.attack_coef = expf(-1.0f / (attack_ms * 1e-6 * c.samplerate));
c.release_coef = expf(-1.0f / (release_ms * 1e-3 * c.samplerate));
// feedback compression // feedback compression
float sum = sqrtf(0.5f * (audio[0][i] * audio[0][i] + audio[1][i] * audio[1][i])); float sum = sqrtf(0.5f * (audio[0][i] * audio[0][i] + audio[1][i] * audio[1][i]));
if (c.multiplied) sum *= 3.f;
c.sidechain_in = hp_filter_process(c.filter, sum); c.sidechain_in = hp_filter_process(c.filter, sum);
} }
} }