📄 unadspdlib.pas
字号:
gr_env := 1;
nsot := 0;
//
inherited create(DSPL_OID or DSPL_DYNPROC);
end;
// -- --
function unaDspDL_DynProc.process(nSamples: dspl_int): dspl_result;
var
in_chunk: pdspl_chunk;
out_chunk: pdspl_chunk;
sc_chunk: pdspl_chunk;
ina: pdspl_float;
//sc: pdspl_float;
outa: pdspl_float;
out_len: dspl_int;
valid: dspl_result;
attack_samples: dspl_float;
release_samples: dspl_float;
aratio: dspl_float;
bratio: dspl_float;
ld: pdspl_float;
theta: dspl_double;
oth: bool;
gain: dspl_double;
gr: dspl_double;
t: int;
begin
in_chunk := getc(DSPL_PID or DSPL_P_IN or DSPL_DYNPROC_IN);
out_chunk := getc(DSPL_PID or DSPL_P_OUT);
sc_chunk := getc(DSPL_PID or DSPL_P_IN or DSPL_DYNPROC_SC);
//
result := DSPL_SUCCESS;
//
if (nil = sc_chunk.r_fp) then
sc_chunk := in_chunk
else
if (in_chunk.r_len <> sc_chunk.r_len) then
result := DSPL_FAILURE;
//
if (DSPL_SUCCESS = result) then begin
//
ina := in_chunk.r_fp;
//sc := sc_chunk.r_fp;
outa := out_chunk.r_fp;
//
out_len := out_chunk.r_len;
if ((out_len <> in_chunk.r_len) or (out_len < nSamples)) then
result := DSPL_FAILURE
else begin
//
if (f_modified) then begin
//
if (ld_buffer_size < out_len) then begin
//
ld_buffer_size := out_len;
mrealloc(ld_buffer, sizeOf(ld_buffer^) * ld_buffer_size);
end;
//
valid := true;
//
valid := valid and level_detector.setf(DSPL_PID or DSPL_P_ATTACK, getf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD));
valid := valid and level_detector.setf(DSPL_PID or DSPL_P_RELEASE, getf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD));
valid := valid and level_detector.setf(DSPL_PID or DSPL_P_OTHER, getf(DSPL_PID or DSPL_P_OTHER or DSPL_LD));
//
valid := valid and level_detector.seti(DSPL_PID or DSPL_P_TYPE, geti(DSPL_PID or DSPL_P_TYPE or DSPL_LD));
valid := valid and level_detector.setc(DSPL_PID or DSPL_P_IN, sc_chunk.r_fp, sc_chunk.r_len);
valid := valid and level_detector.setc(DSPL_PID or DSPL_P_OUT, ld_buffer, out_len);
//
if (not valid) then
result := DSPL_FAILURE
else begin
//
attack_samples := 0.5 * getf(DSPL_PID or DSPL_P_ATTACK);
release_samples := 0.5 * getf(DSPL_PID or DSPL_P_RELEASE);
//
if ((attack_samples < 0) or (release_samples < 0)) then
result := DSPL_FAILURE
else begin
//
alpha := attack_samples / (attack_samples + 2.0);
beta := exp(-1.0 / (release_samples + 1.0));
//
aratio := getf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE);
bratio := getf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW);
//
if ((aratio < 0.02) or (bratio < 0.02)) then
result := DSPL_FAILURE
else begin
//
aratio_inv := 1.0 / aratio;
bratio_inv := 1.0 / bratio;
//
if (aratio_inv < 1e-3) then aratio_inv := 0.0;
if (bratio_inv < 1e-3) then bratio_inv := 0.0;
//
th := getf(DSPL_PID or DSPL_P_THRESHOLD);
try
ascale := getf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE) * pow(th, 1.0 - aratio_inv);
except
ascale := db2v(60.0);
end;
//
try
bscale := getf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW) * pow(th, 1.0 - bratio_inv);
except
bscale := db2v(60.0);
end;
//
end;
end;
end;
end; // if (modified) ...
//
if (DSPL_SUCCESS = result) then begin
//
level_detector.process(nSamples);
//
ld := ld_buffer;
nsot := 0;
//
for t := 0 to nSamples -1 do begin
//
oth := (ld^ >= th);
//
if (oth) then
gain := ascale * pow(ld^, aratio_inv)
else
gain := bscale * pow(ld^, bratio_inv);
//
if (oth) then
gr := ascale * pow(ld^, aratio_inv - 1)
else
gr := bscale * pow(ld^, bratio_inv - 1);
//
if (gr < db2v(-127.0)) then gr := 0;
if (gr > db2v(127.0)) then gr := db2v(120.0);
//
if (gain > gain_env) then
theta := alpha
else
theta := beta;
//
if (gain_env > th) then
inc(nsot);
//
gain_env := gain_env * theta;
gain_env := gain_env + gain * (1.0 - theta);
//
gr_env := gr_env * theta;
gr_env := gr_env + gr * (1.0 - theta);
//
outa^ := gr_env * ina^;
//
inc(ina);
inc(outa);
inc(ld);
end;
//
seti(DSPL_PID or DSPL_P_OTHER, nsot);
//
f_modified := false;
end;
end;
end;
end;
{ unaDspDL_SpeechProc }
// -- --
procedure unaDspDL_SpeechProc.AfterConstruction();
begin
setc(DSPL_PID or DSPL_P_IN or 0, nil, 0);
setc(DSPL_PID or DSPL_P_OUT or 0, nil, 0);
//
setf(DSPL_PID or DSPL_P_THRESHOLD or 0, db2v(-36.0));
setc(DSPL_PID or DSPL_P_THRESHOLD or 0, nil, 0);
//
setf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_SAMPLE_RATE, DSPL_DEFAULT_SAMPLE_FRQ);
//
setf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_DEESSER, 2000.0);
setf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_ENHANCER, 5000.0);
setf(DSPL_PID or DSPL_P_Q or DSPL_SPEECHPROC_ENHANCER, 0.4);
setf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_LOWCUT, 300.0);
//
setf(DSPL_PID or DSPL_P_GAIN or 0, db2v(+6.0));
setf(DSPL_PID or DSPL_P_GAIN or DSPL_SPEECHPROC_CEIL or 0, db2v(-0.5));
//
// number of samples over threshold
seti(DSPL_PID or DSPL_P_OTHER or 0, 0);
//
inherited;
end;
// -- --
procedure unaDspDL_SpeechProc.BeforeDestruction();
begin
inherited;
//
mrealloc(acca);
mrealloc(accb);
mrealloc(la_in);
mrealloc(la_buf);
mrealloc(hp_out);
//
freeAndNil(hp);
freeAndNil(enh);
//
freeAndNil(agc);
freeAndNil(comp);
freeAndNil(ng);
freeAndNil(lim);
freeAndNil(ds);
end;
// -- --
constructor unaDspDL_SpeechProc.create();
begin
{$IFDEF DEBUG }
f_nameFull := c_DSPL_OBJNAMES_FULL[DSPL_SPEECHPROC];
f_nameShort := c_DSPL_OBJNAMES_SHORT[DSPL_SPEECHPROC];
{$ENDIF }
//
hp := unaDspDL_EQ2B.create();
enh := unaDspDL_EQ2B.create();
//
agc := unaDspDL_DynProc.create();
comp := unaDspDL_DynProc.create();
ng := unaDspDL_DynProc.create();
lim := unaDspDL_DynProc.create();
ds := unaDspDL_DynProc.create();
//
acca := nil;
accb := nil;
hp_out := nil;
la_buf := nil;
la_in := nil;
//
la_size := 0;
la_pos := 0;
//
inherited create(DSPL_OID or DSPL_SPEECHPROC);
end;
// -- --
function unaDspDL_SpeechProc.process(nSamples: dspl_int): dspl_result;
const
look_ahead: dspl_float = 0.005;
att_ratio: dspl_double = 0.125;
var
in_chunk: pdspl_chunk;
out_chunk: pdspl_chunk;
th_chunk: pdspl_chunk;
//
ina: pdspl_float;
outa: pdspl_float;
la: pdspl_float;
ill: pdspl_float;
acc: pdspl_float;
hpp: pdspl_float;
//
out_len: dspl_int;
sample_rate: dspl_float;
noise_level: dspl_float;
gap: dspl_double;
agc_th: dspl_float;
agc_gain: dspl_float;
//
i: int;
s: dspl_float;
slope: dspl_double;
begin
in_chunk := getc(DSPL_PID or DSPL_P_IN);
out_chunk := getc(DSPL_PID or DSPL_P_OUT);
//
th_chunk := getc(DSPL_PID or DSPL_P_THRESHOLD);
//
ina := in_chunk.r_fp;
outa := out_chunk.r_fp;
out_len := out_chunk.r_len;
//
result := DSPL_SUCCESS;
if ((out_len <> in_chunk.r_len) or (out_len < nSamples)) then
result := DSPL_FAILURE
else begin
//
if (f_modified) then begin
//
if (buffer_length < out_len) then begin
//
buffer_length := out_len;
//
mrealloc(acca, sizeOf(acca^) * buffer_length);
mrealloc(accb, sizeOf(accb^) * buffer_length);
mrealloc(la_in, sizeOf(la_in^) * buffer_length);
mrealloc(hp_out, sizeOf(hp_out^) * buffer_length);
end;
//
// lookahead
sample_rate := getf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_SAMPLE_RATE);
if (la_size < floor(sample_rate * look_ahead)) then begin
//
la_size := floor(sample_rate * look_ahead);
la_pos := 0;
mrealloc(la_buf, sizeOf(la_buf^) * la_size);
//
for i := 0 to la_size - 1 do
pFloatArray(la_buf)[i] := 0.0;
end;
//
// AGC Setup
agc.seti(DSPL_PID or DSPL_P_TYPE or DSPL_LD, DSPL_LD_PEAK);
agc.setf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD, 0.001 * sample_rate);
agc.setf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD, 1.0 * sample_rate);
agc.setf(DSPL_PID or DSPL_P_OTHER or DSPL_LD, 0.5 * sample_rate);
//
agc.setf(DSPL_PID or DSPL_P_ATTACK , 0.01 * sample_rate);
agc.setf(DSPL_PID or DSPL_P_RELEASE, 0.05 * sample_rate);
//
enh.seti(DSPL_PID or DSPL_P_TYPE or DSPL_EQ2B_BAND1, DSPL_BIQ_PEAK);
enh.setf(DSPL_PID or DSPL_P_GAIN or DSPL_EQ2B_BAND1, db2v(+6.0));
enh.setf(DSPL_PID or DSPL_P_FRQ or DSPL_EQ2B_BAND1, getf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_ENHANCER) / sample_rate);
enh.setf(DSPL_PID or DSPL_P_Q or DSPL_EQ2B_BAND1, getf(DSPL_PID or DSPL_P_Q or DSPL_SPEECHPROC_ENHANCER));
//
slope := pow(2.0, -0.5);
//
enh.seti(DSPL_PID or DSPL_P_TYPE or DSPL_EQ2B_BAND2, DSPL_BIQ_HP);
enh.setf(DSPL_PID or DSPL_P_FRQ or DSPL_EQ2B_BAND2, getf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_LOWCUT) / sample_rate);
enh.setf(DSPL_PID or DSPL_P_Q or DSPL_EQ2B_BAND2, slope);
//
hp.seti(DSPL_PID or DSPL_P_TYPE or DSPL_EQ2B_BAND2, DSPL_BIQ_HP);
hp.setf(DSPL_PID or DSPL_P_FRQ or DSPL_EQ2B_BAND2, getf(DSPL_PID or DSPL_P_NFRQ or DSPL_SPEECHPROC_DEESSER) / sample_rate);
hp.setf(DSPL_PID or DSPL_P_Q or DSPL_EQ2B_BAND2, slope / 2.0);
//
ds.seti(DSPL_PID or DSPL_P_TYPE or DSPL_LD, DSPL_LD_RMS);
ds.setf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD, 0.001 * sample_rate);
ds.setf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD, 0.001 * sample_rate);
//
ds.setf(DSPL_PID or DSPL_P_ATTACK , 0.005 * sample_rate);
ds.setf(DSPL_PID or DSPL_P_RELEASE, 0.050 * sample_rate);
//
ds.setf(DSPL_PID or DSPL_P_THRESHOLD, db2v(-20.0));
ds.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE, 100.0);
ds.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW, 1.0);
ds.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE, db2v(3.0));
ds.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW, db2v(3.0));
//
comp.seti(DSPL_PID or DSPL_P_TYPE or DSPL_LD, DSPL_LD_RMS);
comp.setf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD, 0.001 * sample_rate);
comp.setf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD, 0.005 * sample_rate);
//
comp.setf(DSPL_PID or DSPL_P_ATTACK , 0.005 * sample_rate);
comp.setf(DSPL_PID or DSPL_P_RELEASE, 0.050 * sample_rate);
//
comp.setf(DSPL_PID or DSPL_P_THRESHOLD, db2v(-12.0));
comp.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE, 4.0);
comp.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW, 1.0);
comp.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE, getf(DSPL_PID or DSPL_P_GAIN));
comp.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW, getf(DSPL_PID or DSPL_P_GAIN));
//
ng.seti(DSPL_PID or DSPL_P_TYPE or DSPL_LD, DSPL_LD_PEAK);
ng.setf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD, 0.001 * sample_rate);
ng.setf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD, 0.001 * sample_rate);
ng.setf(DSPL_PID or DSPL_P_OTHER or DSPL_LD, 0.001 * sample_rate);
//
ng.setf(DSPL_PID or DSPL_P_ATTACK , 0.005 * sample_rate);
ng.setf(DSPL_PID or DSPL_P_RELEASE, 0.300 * sample_rate);
//
ng.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE, 1.0);
ng.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW, 0.05);
ng.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE, db2v(0.0));
ng.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW, db2v(0.0));
//
lim.seti(DSPL_PID or DSPL_P_TYPE or DSPL_LD, DSPL_LD_PEAK);
lim.setf(DSPL_PID or DSPL_P_ATTACK or DSPL_LD, 0.000 * sample_rate);
lim.setf(DSPL_PID or DSPL_P_RELEASE or DSPL_LD, 0.001 * sample_rate);
lim.setf(DSPL_PID or DSPL_P_OTHER or DSPL_LD, 0.005 * sample_rate);
//
lim.setf(DSPL_PID or DSPL_P_ATTACK , 0.000 * sample_rate);
lim.setf(DSPL_PID or DSPL_P_RELEASE, 0.050 * sample_rate);
//
lim.setf(DSPL_PID or DSPL_P_THRESHOLD, getf(DSPL_PID or DSPL_P_GAIN or DSPL_SPEECHPROC_CEIL));
lim.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE, 100.0);
lim.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW, 1.0);
lim.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE, db2v(0.0));
lim.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW, db2v(0.0));
//
agc.setc(DSPL_PID or DSPL_P_IN, la_in, out_len);
agc.setc(DSPL_PID or DSPL_P_OUT, acca , out_len);
//
enh.setc(DSPL_PID or DSPL_P_IN, acca, out_len);
enh.setc(DSPL_PID or DSPL_P_OUT, accb, out_len);
//
hp.setc(DSPL_PID or DSPL_P_IN, accb , out_len);
hp.setc(DSPL_PID or DSPL_P_OUT, hp_out, out_len);
//
ds.setc(DSPL_PID or DSPL_P_IN, hp_out, out_len);
ds.setc(DSPL_PID or DSPL_P_OUT, accb , out_len);
//
ng.setc(DSPL_PID or DSPL_P_IN, acca, out_len);
ng.setc(DSPL_PID or DSPL_P_OUT, accb, out_len);
ng.setc(DSPL_PID or DSPL_P_IN or DSPL_DYNPROC_SC, ina, out_len);
//
comp.setc(DSPL_PID or DSPL_P_IN, accb, out_len);
comp.setc(DSPL_PID or DSPL_P_OUT, acca, out_len);
//
lim.setc(DSPL_PID or DSPL_P_IN, acca, out_len);
lim.setc(DSPL_PID or DSPL_P_OUT, outa, out_len);
//
end; // if (modified) ...
//
if ((nil <> th_chunk.r_fp) or f_modified) then begin
//
if (nil <> th_chunk.r_fp) then
noise_level := th_chunk.r_fp^
else
noise_level := getf(DSPL_PID or DSPL_P_THRESHOLD);
//
if (noise_level > db2v(-18.0)) then
noise_level := db2v(-18.0)
else
if (noise_level < db2v(-127.0)) then
noise_level := db2v(-127.0);
//
gap := pow(db2v(-12.0) / noise_level, att_ratio);
//
agc_th := noise_level * gap;
agc_gain := db2v(-12.0) / agc_th;
//
agc.setf(DSPL_PID or DSPL_P_THRESHOLD, agc_th);
agc.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_ABOVE, 8.0);
agc.setf(DSPL_PID or DSPL_P_RATIO or DSPL_DYNPROC_BELOW, att_ratio);
agc.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_ABOVE, agc_gain);
agc.setf(DSPL_PID or DSPL_P_GAIN or DSPL_DYNPROC_BELOW, agc_gain);
//
ng.setf(DSPL_PID or DSPL_P_THRESHOLD, noise_level);
//
end; // if (chunk or modified) ...
//
la := la_in;
ill := ina;
//
i := nSamples;
while (i > 0) do begin
//
dec(i);
//
s := pFloatArray(la_buf)[la_pos];
pFloatArray(la_buf)[la_pos] := ill^;
inc(la_pos);
//
if (la_pos >= la_size) then
la_pos := 0;
//
la^ := s;
//
inc(la);
inc(ill);
end;
//
agc.process(nSamples);
enh.process(nSamples);
hp.process(nSamples);
//
acc := acca;
hpp := hp_out;
//
i := nSamples;
while (i > 0) do begin
//
dec(i);
//
acc^ := acc^ - hpp^;
inc(acc);
inc(hpp);
end;
//
ds.process(nSamples);
//
acc := acca;
hpp := accb;
//
i := nSamples;
while (i > 0) do begin
//
dec(i);
//
acc^ := acc^ + hpp^;
//
inc(acc);
inc(hpp);
end;
//
ng.process(nSamples);
comp.process(nSamples);
lim.process(nSamples);
//
seti(DSPL_PID or DSPL_P_OTHER, ng.geti(DSPL_PID or DSPL_P_OTHER));
//
f_modified := false;
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -