diff --git a/compressor/Makefile b/compressor/Makefile new file mode 100644 index 0000000..afac6c7 --- /dev/null +++ b/compressor/Makefile @@ -0,0 +1,2 @@ +all: + mkoctfile -mex level_detect.c diff --git a/compressor/cmp_eval.m b/compressor/cmp_eval.m new file mode 100644 index 0000000..eedc779 --- /dev/null +++ b/compressor/cmp_eval.m @@ -0,0 +1,72 @@ +## Copyright (C) 2020 Jens +## +## This program is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {@var{retval} =} eq_eval (@var{input1}, @var{input2}) +## +## @seealso{} +## +## Exapmple: cmp_eval("snip.wav", 0.25, -40, 18); +## @end deftypefn + +## Author: Jens +## Created: 2020-06-22 + +function cmp_eval (filename_in, R, lev_knee_dB, gain_makeup_dB) + +fs = 48000 +[x, fs] = audioread(filename_in); +N = size(x)(1) +num_channels = size(x)(2) +filename_out = to_filename_out(filename_in, "out"); + +time_look_ahead = 0.01; +time_attack = 0.01; +time_release = 1.0; + +n_look_ahead = round(time_look_ahead*fs); +h_dly = [zeros(1, n_look_ahead-1) 1]; + +x_dly = filter(h_dly, 1, x); + +alpha_a = 5/(time_attack*fs); +alpha_r = 5/(time_release*fs); + +lev = level_detect(x, alpha_a, alpha_r); +lev_dB = max(-120, 20*log10(lev)); + +k_makeup_gain = 10^(gain_makeup_dB/20); +gain1 = min(8, (1/8)./(lev+0.1)); +[lev_out_dB, gain2_dB] = cmp_gain(R, lev_knee_dB, lev_dB); +gain2 = 10.^(gain2_dB/20); +y1 = gain1.*x_dly * 2; +y2 = gain2.*x_dly * k_makeup_gain; +audiowrite(to_filename_out(filename_in, "gain1"), gain1, fs) +audiowrite(to_filename_out(filename_in, "gain2"), gain2, fs) +audiowrite(to_filename_out(filename_in, "out1"), y1, fs) +audiowrite(to_filename_out(filename_in, "out2"), y2, fs) +audiowrite(to_filename_out(filename_in, "lev"), lev, fs) + +gain_out = []; +gain_in = []; +for g=0:0.1:1, + gain_out = [gain_out cmp_gain(R, g, 0.01)]; + gain_in = [gain_in g]; +endfor +plot(gain_in, gain_out); grid(); + +endfunction + diff --git a/compressor/cmp_gain.m b/compressor/cmp_gain.m new file mode 100644 index 0000000..a8786eb --- /dev/null +++ b/compressor/cmp_gain.m @@ -0,0 +1,5 @@ +function [lev_out_dB, gain_out_dB] = cmp_gain(R, lev_knee_dB, lev_in_dB) + k = lev_in_dB > lev_knee_dB; + lev_out_dB = (1-k).*lev_in_dB + k.*(lev_knee_dB + R*(lev_in_dB - lev_knee_dB)); + gain_out_dB = - (lev_in_dB - lev_out_dB); +endfunction diff --git a/compressor/cmp_gain_eval.m b/compressor/cmp_gain_eval.m new file mode 100644 index 0000000..5afbc12 --- /dev/null +++ b/compressor/cmp_gain_eval.m @@ -0,0 +1,42 @@ +## Copyright (C) 2020 Jens +## +## This program is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {} {@var{retval} =} eq_eval (@var{input1}, @var{input2}) +## +## @seealso{} +## @end deftypefn + +## Author: Jens +## Created: 2020-06-22 + +function cmp_gain_eval (R) +epsilon = 0.01; +dl = 10; +gain_out = []; +lev_out = []; +lev_in = []; +for li=-120:dl:0, + [lo, go] = cmp_gain(R, -20, li); + lev_out = [lev_out lo]; + lev_in = [lev_in li]; + gain_out = [gain_out go]; +endfor +close; +plot(lev_in, lev_out, lev_in, gain_out); grid(); + +endfunction + diff --git a/compressor/level_detect.c b/compressor/level_detect.c new file mode 100644 index 0000000..9d13bdb --- /dev/null +++ b/compressor/level_detect.c @@ -0,0 +1,70 @@ +#include +#include +void mexFunction (int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + const char *funcName = mexFunctionName (); + mexPrintf ("You called function: %s\n", funcName); + mexPrintf ("I have %d inputs and %d outputs\n", nrhs, nlhs); + + if (nrhs < 3) + mexErrMsgTxt ("Too few arguments"); + + const mxArray *array_x = prhs[0]; + const mxArray *scalar_alpha_attack = prhs[1]; + const mxArray *scalar_alpha_release = prhs[2]; + + + plhs[0] = mxCreateNumericArray (mxGetNumberOfDimensions (array_x), + mxGetDimensions (array_x), + mxGetClassID (array_x), + mxIsComplex (array_x)); + + mwIndex channelsDim = 1; + double alpha_a = *mxGetPr(scalar_alpha_attack); + double alpha_r = *mxGetPr(scalar_alpha_release); + + double *vri = mxGetPr (array_x); + double *vro = mxGetPr (plhs[0]); + + mwSize M = mxGetM (array_x); + mwSize N = mxGetN (array_x); + if (channelsDim == 1) + { + M = mxGetN (array_x); + N = mxGetM (array_x); + } + + mexPrintf ("Number of channels = %u\n", M); + mexPrintf ("Number of samples per channel = %u\n", N); + mexPrintf ("alpha_a = %f\n", alpha_a); + mexPrintf ("alpha_r = %f\n", alpha_r); + + double level[M]; + for (mwIndex m=0; m < M; m++) + { + level[m] = 0; + } + + for (mwIndex n=0; n < N; n++) + { + for (mwIndex m=0; m < M; m++) + { + double x = vri[n*M + m]; + double xmag = fabs(x); + + if (xmag > level[m]) + { + level[m] = (1.0-alpha_a)*level[m] + alpha_a*xmag; + } + else + { + level[m] = (1.0-alpha_r)*level[m]; + } + vro[n*M + m] = level[m]; + } + } +} + + +