sof/tools/tune/drc/drc_gen_coefs.m

120 lines
3.5 KiB
Matlab

function coefs = drc_gen_coefs(params, sample_rate)
if exist('OCTAVE_VERSION', 'builtin')
pkg load control;
end
% Print out params
params
coefs.enabled = params.enabled;
% Calculate static curve coefficients
coefs.db_threshold = params.threshold;
coefs.db_knee = params.knee;
coefs.ratio = params.ratio;
coefs.pre_delay_time = params.pre_delay;
coefs.linear_threshold = db2mag(coefs.db_threshold);
coefs.slope = 1 / coefs.ratio;
k = k_at_slope(coefs.db_threshold, coefs.db_knee, coefs.linear_threshold, coefs.slope);
coefs.K = k;
coefs.knee_alpha = coefs.linear_threshold + 1 / k;
coefs.knee_beta = -exp(k * coefs.linear_threshold) / k;
coefs.knee_threshold = db2mag(coefs.db_threshold + coefs.db_knee);
y0 = knee_curve(coefs.linear_threshold, coefs.knee_threshold, k);
coefs.ratio_base = y0 * (coefs.knee_threshold ^ (-coefs.slope));
% Calculate makeup gain coefficients
full_range_makeup_gain = (1 / coefs.ratio_base) ^ 0.6; % Empirical/perceptual tuning
coefs.master_linear_gain = db2mag(params.post_gain) * full_range_makeup_gain;
% Calculate attack time coefficients
attack_time = max(0.001, params.attack);
coefs.one_over_attack_frames = 1 / (attack_time * sample_rate);
% Calculate release time coefficients
release_frames = params.release * sample_rate;
sat_release_time = 0.0025;
sat_release_frames = sat_release_time * sample_rate;
coefs.sat_release_frames_inv_neg = -1 / sat_release_frames;
coefs.sat_release_rate_at_neg_two_db = db2mag(-2 * coefs.sat_release_frames_inv_neg) - 1;
coefs.kSpacingDb = params.release_spacing;
% Create a smooth function which passes through four points.
% Polynomial of the form y = a + b*x + c*x^2 + d*x^3 + e*x^4
y = params.release_zone .* release_frames;
% All of these coefficients were derived for 4th order polynomial curve fitting
% where the y values match the evenly spaced x values as follows:
% (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3)
coefs.kA = 0.9999999999999998 * y(1) + 1.8432219684323923e-16 * y(2) ...
- 1.9373394351676423e-16 * y(3) + 8.824516011816245e-18 * y(4);
coefs.kB = -1.5788320352845888 * y(1) + 2.3305837032074286 * y(2) ...
- 0.9141194204840429 * y(3) + 0.1623677525612032 * y(4);
coefs.kC = 0.5334142869106424 * y(1) - 1.272736789213631 * y(2) ...
+ 0.9258856042207512 * y(3) - 0.18656310191776226 * y(4);
coefs.kD = 0.08783463138207234 * y(1) - 0.1694162967925622 * y(2) ...
+ 0.08588057951595272 * y(3) - 0.00429891410546283 * y(4);
coefs.kE = -0.042416883008123074 * y(1) + 0.1115693827987602 * y(2) ...
- 0.09764676325265872 * y(3) + 0.028494263462021576 * y(4);
% Print out coefs
coefs
end
function k = k_at_slope(db_threshold, db_knee, linear_threshold, desired_slope)
% Approximate k given initial values
x = db2mag(db_threshold + db_knee);
min_k = 0.1;
max_k = 10000;
k = 5;
for i = 1:15
% A high value for k will more quickly asymptotically approach a slope of 0
slope = slope_at(linear_threshold, x, k);
if slope < desired_slope
max_k = k; % k is too high
else
min_k = k; % k is too low
end
% Re-calculate based on geometric mean
k = sqrt(min_k * max_k);
end
end
function slope = slope_at(linear_threshold, x, k)
if x < linear_threshold
slope = 1;
else
x2 = x * 1.001;
x_db = mag2db(x);
x2_db = mag2db(x2);
y_db = mag2db(knee_curve(linear_threshold, x, k));
y2_db = mag2db(knee_curve(linear_threshold, x2, k));
slope = (y2_db - y_db) / (x2_db - x_db);
end
end
function y = knee_curve(linear_threshold, x, k)
if x < linear_threshold
y = x;
else
y = linear_threshold + (1 - exp(-k * (x - linear_threshold))) / k;
end
end