1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-03-21 11:48:54 -04:00

WDSP: WCPAGC rework

This commit is contained in:
f4exb 2024-07-29 23:31:43 +02:00
parent 7cb15bbd95
commit bc06095a56
7 changed files with 346 additions and 432 deletions

View File

@ -770,46 +770,46 @@ void WDSPRxSink::applySettings(const WDSPRxSettings& settings, bool force)
|| (m_settings.m_agcHangThreshold != settings.m_agcHangThreshold)
|| (m_settings.m_agcGain != settings.m_agcGain) || force)
{
WDSP::WCPAGC::SetAGCSlope(*m_rxa, settings.m_agcSlope); // SetRXAAGCSlope(id, rx->agc_slope);
WDSP::WCPAGC::SetAGCTop(*m_rxa, (float) settings.m_agcGain); // SetRXAAGCTop(id, rx->agc_gain);
m_rxa->agc->setSlope(settings.m_agcSlope); // SetRXAAGCSlope(id, rx->agc_slope);
m_rxa->agc->setTop((float) settings.m_agcGain); // SetRXAAGCTop(id, rx->agc_gain);
if (settings.m_agc)
{
switch (settings.m_agcMode)
{
case WDSPRxProfile::WDSPRxAGCMode::AGCLong:
WDSP::WCPAGC::SetAGCMode(*m_rxa, 1);
WDSP::WCPAGC::SetAGCAttack(*m_rxa, 2); // SetRXAAGCAttack(id, 2);
WDSP::WCPAGC::SetAGCHang(*m_rxa, 2000); // SetRXAAGCHang(id, 2000);
WDSP::WCPAGC::SetAGCDecay(*m_rxa, 2000); // SetRXAAGCDecay(id, 2000);
WDSP::WCPAGC::SetAGCHangThreshold(*m_rxa, settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, (int)rx->agc_hang_threshold);
m_rxa->agc->setMode(1);
m_rxa->agc->setAttack(2); // SetRXAAGCAttack(id, 2);
m_rxa->agc->setHang(2000); // SetRXAAGCHang(id, 2000);
m_rxa->agc->setDecay(2000); // SetRXAAGCDecay(id, 2000);
m_rxa->agc->setHangThreshold(settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, (int)rx->agc_hang_threshold);
break;
case WDSPRxProfile::WDSPRxAGCMode::AGCSlow:
WDSP::WCPAGC::SetAGCMode(*m_rxa, 2);
WDSP::WCPAGC::SetAGCAttack(*m_rxa, 2); // SetRXAAGCAttack(id, 2);
WDSP::WCPAGC::SetAGCHang(*m_rxa, 1000); // SetRXAAGCHang(id, 1000);
WDSP::WCPAGC::SetAGCDecay(*m_rxa, 500); // SetRXAAGCDecay(id, 500);
WDSP::WCPAGC::SetAGCHangThreshold(*m_rxa, settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, (int)rx->agc_hang_threshold);
m_rxa->agc->setMode(2);
m_rxa->agc->setAttack(2); // SetRXAAGCAttack(id, 2);
m_rxa->agc->setHang(1000); // SetRXAAGCHang(id, 1000);
m_rxa->agc->setDecay(500); // SetRXAAGCDecay(id, 500);
m_rxa->agc->setHangThreshold(settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, (int)rx->agc_hang_threshold);
break;
case WDSPRxProfile::WDSPRxAGCMode::AGCMedium:
WDSP::WCPAGC::SetAGCMode(*m_rxa, 3);
WDSP::WCPAGC::SetAGCAttack(*m_rxa, 2); // SetRXAAGCAttack(id, 2);
WDSP::WCPAGC::SetAGCHang(*m_rxa, 0); // SetRXAAGCHang(id, 0);
WDSP::WCPAGC::SetAGCDecay(*m_rxa, 250); // SetRXAAGCDecay(id, 250);
WDSP::WCPAGC::SetAGCHangThreshold(*m_rxa, settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, 100);
m_rxa->agc->setMode(3);
m_rxa->agc->setAttack(2); // SetRXAAGCAttack(id, 2);
m_rxa->agc->setHang(0); // SetRXAAGCHang(id, 0);
m_rxa->agc->setDecay(250); // SetRXAAGCDecay(id, 250);
m_rxa->agc->setHangThreshold(settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, 100);
break;
case WDSPRxProfile::WDSPRxAGCMode::AGCFast:
WDSP::WCPAGC::SetAGCMode(*m_rxa, 4);
WDSP::WCPAGC::SetAGCAttack(*m_rxa, 2); // SetRXAAGCAttack(id, 2);
WDSP::WCPAGC::SetAGCHang(*m_rxa, 0); // SetRXAAGCHang(id, 0);
WDSP::WCPAGC::SetAGCDecay(*m_rxa, 50); // SetRXAAGCDecay(id, 50);
WDSP::WCPAGC::SetAGCHangThreshold(*m_rxa, settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, 100);
m_rxa->agc->setMode(4);
m_rxa->agc->setAttack(2); // SetRXAAGCAttack(id, 2);
m_rxa->agc->setHang(0); // SetRXAAGCHang(id, 0);
m_rxa->agc->setDecay(50); // SetRXAAGCDecay(id, 50);
m_rxa->agc->setHangThreshold(settings.m_agcHangThreshold); // SetRXAAGCHangThreshold(id, 100);
break;
}
}
else
{
WDSP::WCPAGC::SetAGCMode(*m_rxa, 0);
m_rxa->agc->setMode(0);
}
}

View File

@ -403,7 +403,7 @@ RXA* RXA::create_rxa (
1); // ae_run
// AGC
rxa->agc = WCPAGC::create_wcpagc (
rxa->agc = new WCPAGC(
1, // run
3, // mode
1, // peakmode = envelope
@ -572,7 +572,7 @@ void RXA::destroy_rxa (RXA *rxa)
SIPHON::destroy_siphon (rxa->sip1);
BANDPASS::destroy_bandpass (rxa->bp1);
delete (rxa->agcmeter);
WCPAGC::destroy_wcpagc (rxa->agc);
delete (rxa->agc);
delete (rxa->emnr);
delete (rxa->anr);
delete (rxa->anf);
@ -621,7 +621,7 @@ void RXA::flush_rxa (RXA *rxa)
rxa->anf->flush();
rxa->anr->flush();
rxa->emnr->flush();
WCPAGC::flush_wcpagc (rxa->agc);
rxa->agc->flush();
rxa->agcmeter->flush();
BANDPASS::flush_bandpass (rxa->bp1);
SIPHON::flush_siphon (rxa->sip1);
@ -657,7 +657,7 @@ void RXA::xrxa (RXA *rxa)
rxa->anr->ANR::execute(0);
rxa->emnr->execute(0);
BANDPASS::xbandpass (rxa->bp1, 0);
WCPAGC::xwcpagc (rxa->agc);
rxa->agc->execute();
rxa->anf->execute(1);
rxa->anr->execute(1);
rxa->emnr->execute(1);
@ -768,7 +768,7 @@ void RXA::setDSPSamplerate (RXA *rxa, int dsp_rate)
rxa->anr->setSamplerate(rxa->dsp_rate);
rxa->emnr->setSamplerate(rxa->dsp_rate);
BANDPASS::setSamplerate_bandpass (rxa->bp1, rxa->dsp_rate);
WCPAGC::setSamplerate_wcpagc (rxa->agc, rxa->dsp_rate);
rxa->agc->setSamplerate(rxa->dsp_rate);
rxa->agcmeter->setSamplerate(rxa->dsp_rate);
SIPHON::setSamplerate_siphon (rxa->sip1, rxa->dsp_rate);
CBL::setSamplerate_cbl (rxa->cbl, rxa->dsp_rate);
@ -845,8 +845,8 @@ void RXA::setDSPBuffsize (RXA *rxa, int dsp_size)
rxa->emnr->setSize(rxa->dsp_size);
BANDPASS::setBuffers_bandpass (rxa->bp1, rxa->midbuff, rxa->midbuff);
BANDPASS::setSize_bandpass (rxa->bp1, rxa->dsp_size);
WCPAGC::setBuffers_wcpagc (rxa->agc, rxa->midbuff, rxa->midbuff);
WCPAGC::setSize_wcpagc (rxa->agc, rxa->dsp_size);
rxa->agc->setBuffers(rxa->midbuff, rxa->midbuff);
rxa->agc->setSize(rxa->dsp_size);
rxa->agcmeter->setBuffers(rxa->midbuff);
rxa->agcmeter->setSize(rxa->dsp_size);
SIPHON::setBuffers_siphon (rxa->sip1, rxa->midbuff);
@ -1343,6 +1343,23 @@ void RXA::SetEMNRPosition (RXA& rxa, int position)
rxa.bp1->position = position;
}
void RXA::GetAGCThresh(RXA& rxa, double *thresh, double size, double rate)
//for line on bandscope.
{
double noise_offset;
noise_offset = 10.0 * log10((rxa.nbp0->fhigh - rxa.nbp0->flow) * size / rate);
*thresh = 20.0 * log10( rxa.agc->min_volts ) - noise_offset;
}
void RXA::SetAGCThresh(RXA& rxa, double thresh, double size, double rate)
//for line on bandscope
{
double noise_offset;
noise_offset = 10.0 * log10((rxa.nbp0->fhigh - rxa.nbp0->flow) * size / rate);
rxa.agc->max_gain = rxa.agc->out_target / (rxa.agc->var_gain * pow (10.0, (thresh + noise_offset) / 20.0));
rxa.agc->loadWcpAGC();
}
/********************************************************************************************************
* *
* Collectives *

View File

@ -180,6 +180,9 @@ public:
// EMNR
static void SetEMNRRun (RXA& rxa, int run);
static void SetEMNRPosition (RXA& rxa, int position);
// WCPAGC
static void SetAGCThresh(RXA& rxa, double thresh, double size, double rate);
static void GetAGCThresh(RXA& rxa, double *thresh, double size, double rate);
// Collectives
static void SetPassband (RXA& rxa, float f_low, float f_high);
static void SetNC (RXA& rxa, int nc);

View File

@ -197,7 +197,7 @@ TXA* TXA::create_txa (
300.0, // f_low
3000.0); // f_high
txa->leveler = WCPAGC::create_wcpagc (
txa->leveler = new WCPAGC(
0, // run - OFF by default
5, // mode
0, // 0 for max(I,Q), 1 for envelope
@ -347,7 +347,7 @@ TXA* TXA::create_txa (
-1, // index for gain value
0); // pointer for gain computation
txa->alc = WCPAGC::create_wcpagc (
txa->alc = new WCPAGC(
1, // run - always ON
5, // mode
1, // 0 for max(I,Q), 1 for envelope
@ -530,7 +530,7 @@ void TXA::destroy_txa (TXA *txa)
delete (txa->gen1);
FMMOD::destroy_fmmod (txa->fmmod);
AMMOD::destroy_ammod (txa->ammod);
WCPAGC::destroy_wcpagc (txa->alc);
delete (txa->alc);
delete (txa->compmeter);
BANDPASS::destroy_bandpass (txa->bp2);
OSCTRL::destroy_osctrl (txa->osctrl);
@ -540,7 +540,7 @@ void TXA::destroy_txa (TXA *txa)
delete (txa->cfcmeter);
CFCOMP::destroy_cfcomp (txa->cfcomp);
delete (txa->lvlrmeter);
WCPAGC::destroy_wcpagc (txa->leveler);
delete (txa->leveler);
EMPHP::destroy_emphp (txa->preemph);
delete (txa->eqmeter);
delete (txa->eqp);
@ -570,7 +570,7 @@ void TXA::flush_txa (TXA* txa)
txa->eqp->flush();
txa->eqmeter->flush ();
EMPHP::flush_emphp (txa->preemph);
WCPAGC::flush_wcpagc (txa->leveler);
txa->leveler->flush();
txa->lvlrmeter->flush ();
CFCOMP::flush_cfcomp (txa->cfcomp);
txa->cfcmeter->flush ();
@ -580,7 +580,7 @@ void TXA::flush_txa (TXA* txa)
OSCTRL::flush_osctrl (txa->osctrl);
BANDPASS::flush_bandpass (txa->bp2);
txa->compmeter->flush ();
WCPAGC::flush_wcpagc (txa->alc);
txa->alc->flush ();
AMMOD::flush_ammod (txa->ammod);
FMMOD::flush_fmmod (txa->fmmod);
txa->gen1->flush();
@ -605,7 +605,7 @@ void xtxa (TXA* txa)
txa->eqp->execute (); // pre-EQ
txa->eqmeter->execute (); // EQ meter
EMPHP::xemphp (txa->preemph, 0); // FM pre-emphasis (first option)
WCPAGC::xwcpagc (txa->leveler); // Leveler
txa->leveler->execute (); // Leveler
txa->lvlrmeter->execute (); // Leveler Meter
CFCOMP::xcfcomp (txa->cfcomp, 0); // Continuous Frequency Compressor with post-EQ
txa->cfcmeter->execute (); // CFC+PostEQ Meter
@ -615,7 +615,7 @@ void xtxa (TXA* txa)
OSCTRL::xosctrl (txa->osctrl); // CESSB Overshoot Control
BANDPASS::xbandpass (txa->bp2, 0); // aux bandpass (runs if CESSB)
txa->compmeter->execute (); // COMP meter
WCPAGC::xwcpagc (txa->alc); // ALC
txa->alc->execute (); // ALC
AMMOD::xammod (txa->ammod); // AM Modulator
EMPHP::xemphp (txa->preemph, 1); // FM pre-emphasis (second option)
FMMOD::xfmmod (txa->fmmod); // FM Modulator
@ -702,7 +702,7 @@ void TXA::setDSPSamplerate (TXA *txa, int dsp_rate)
txa->eqp->setSamplerate (txa->dsp_rate);
txa->eqmeter->setSamplerate (txa->dsp_rate);
EMPHP::setSamplerate_emphp (txa->preemph, txa->dsp_rate);
WCPAGC::setSamplerate_wcpagc (txa->leveler, txa->dsp_rate);
txa->leveler->setSamplerate (txa->dsp_rate);
txa->lvlrmeter->setSamplerate (txa->dsp_rate);
CFCOMP::setSamplerate_cfcomp (txa->cfcomp, txa->dsp_rate);
txa->cfcmeter->setSamplerate (txa->dsp_rate);
@ -712,7 +712,7 @@ void TXA::setDSPSamplerate (TXA *txa, int dsp_rate)
OSCTRL::setSamplerate_osctrl (txa->osctrl, txa->dsp_rate);
BANDPASS::setSamplerate_bandpass (txa->bp2, txa->dsp_rate);
txa->compmeter->setSamplerate (txa->dsp_rate);
WCPAGC::setSamplerate_wcpagc (txa->alc, txa->dsp_rate);
txa->alc->setSamplerate (txa->dsp_rate);
AMMOD::setSamplerate_ammod (txa->ammod, txa->dsp_rate);
FMMOD::setSamplerate_fmmod (txa->fmmod, txa->dsp_rate);
txa->gen1->setSamplerate(txa->dsp_rate);
@ -770,8 +770,8 @@ void TXA::setDSPBuffsize (TXA *txa, int dsp_size)
txa->eqmeter->setSize (txa->dsp_size);
EMPHP::setBuffers_emphp (txa->preemph, txa->midbuff, txa->midbuff);
EMPHP::setSize_emphp (txa->preemph, txa->dsp_size);
WCPAGC::setBuffers_wcpagc (txa->leveler, txa->midbuff, txa->midbuff);
WCPAGC::setSize_wcpagc (txa->leveler, txa->dsp_size);
txa->leveler->setBuffers(txa->midbuff, txa->midbuff);
txa->leveler->setSize(txa->dsp_size);
txa->lvlrmeter->setBuffers(txa->midbuff);
txa->lvlrmeter->setSize(txa->dsp_size);
CFCOMP::setBuffers_cfcomp (txa->cfcomp, txa->midbuff, txa->midbuff);
@ -790,8 +790,8 @@ void TXA::setDSPBuffsize (TXA *txa, int dsp_size)
BANDPASS::setSize_bandpass (txa->bp2, txa->dsp_size);
txa->compmeter->setBuffers(txa->midbuff);
txa->compmeter->setSize(txa->dsp_size);
WCPAGC::setBuffers_wcpagc (txa->alc, txa->midbuff, txa->midbuff);
WCPAGC::setSize_wcpagc (txa->alc, txa->dsp_size);
txa->alc->setBuffers(txa->midbuff, txa->midbuff);
txa->alc->setSize( txa->dsp_size);
AMMOD::setBuffers_ammod (txa->ammod, txa->midbuff, txa->midbuff);
AMMOD::setSize_ammod (txa->ammod, txa->dsp_size);
FMMOD::setBuffers_fmmod (txa->fmmod, txa->midbuff, txa->midbuff);

View File

@ -55,7 +55,7 @@ void FMD::calc()
// CTCSS Removal
sntch = SNOTCH::create_snotch(1, size, out, out, (int)rate, ctcss_freq, 0.0002);
// detector limiter
plim = WCPAGC::create_wcpagc (
plim = new WCPAGC(
1, // run - always ON
5, // mode
1, // 0 for max(I,Q), 1 for envelope
@ -83,7 +83,7 @@ void FMD::calc()
void FMD::decalc()
{
WCPAGC::destroy_wcpagc(plim);
delete (plim);
SNOTCH::destroy_snotch(sntch);
}
@ -163,7 +163,7 @@ void FMD::flush()
omega = 0.0;
fmdc = 0.0;
SNOTCH::flush_snotch (sntch);
WCPAGC::flush_wcpagc (plim);
plim->flush();
}
void FMD::execute()
@ -205,7 +205,7 @@ void FMD::execute()
{
for (i = 0; i < 2 * size; i++)
out[i] *= lim_pre_gain;
WCPAGC::xwcpagc (plim);
plim->execute();
}
}
else if (in != out)
@ -220,7 +220,7 @@ void FMD::setBuffers(float* _in, float* _out)
calc();
FIRCORE::setBuffers_fircore (pde, audio.data(), out);
FIRCORE::setBuffers_fircore (paud, out, out);
WCPAGC::setBuffers_wcpagc (plim, out, out);
plim->setBuffers(out, out);
}
void FMD::setSamplerate(int _rate)
@ -237,7 +237,7 @@ void FMD::setSamplerate(int _rate)
impulse = FIR::fir_bandpass(nc_aud, 0.8 * f_low, 1.1 * f_high, rate, 0, 1, afgain / (2.0 * size));
FIRCORE::setImpulse_fircore (paud, impulse, 1);
delete[] (impulse);
WCPAGC::setSamplerate_wcpagc (plim, (int)rate);
plim->setSamplerate((int) rate);
}
void FMD::setSize(int _size)
@ -257,7 +257,7 @@ void FMD::setSize(int _size)
impulse = FIR::fir_bandpass(nc_aud, 0.8 * f_low, 1.1 * f_high, rate, 0, 1, afgain / (2.0 * size));
paud = FIRCORE::create_fircore (size, out, out, nc_aud, mp_aud, impulse);
delete[] (impulse);
WCPAGC::setSize_wcpagc (plim, size);
plim->setSize(size);
}
/********************************************************************************************************

View File

@ -39,218 +39,201 @@ Santa Cruz, CA 95060
namespace WDSP {
void WCPAGC::calc_wcpagc (WCPAGC *a)
void WCPAGC::calc()
{
//assign constants
a->ring_buffsize = RB_SIZE;
//do one-time initialization
a->out_index = -1;
a->ring_max = 0.0;
a->volts = 0.0;
a->save_volts = 0.0;
a->fast_backaverage = 0.0;
a->hang_backaverage = 0.0;
a->hang_counter = 0;
a->decay_type = 0;
a->state = 0;
a->ring = new double[RB_SIZE * 2]; // (float *)malloc0(RB_SIZE * sizeof(complex));
a->abs_ring = new double[RB_SIZE]; //(float *)malloc0(RB_SIZE * sizeof(float));
loadWcpAGC(a);
out_index = -1;
ring_max = 0.0;
volts = 0.0;
save_volts = 0.0;
fast_backaverage = 0.0;
hang_backaverage = 0.0;
hang_counter = 0;
decay_type = 0;
state = 0;
loadWcpAGC();
}
void WCPAGC::decalc_wcpagc (WCPAGC *a)
{
delete[] (a->abs_ring);
delete[] (a->ring);
}
WCPAGC* WCPAGC::create_wcpagc (
int run,
int mode,
int pmode,
float* in,
float* out,
int io_buffsize,
int sample_rate,
double tau_attack,
double tau_decay,
int n_tau,
double max_gain,
double var_gain,
double fixed_gain,
double max_input,
double out_targ,
double tau_fast_backaverage,
double tau_fast_decay,
double pop_ratio,
int hang_enable,
double tau_hang_backmult,
double hangtime,
double hang_thresh,
double tau_hang_decay
)
{
WCPAGC *a = new WCPAGC;
WCPAGC::WCPAGC(
int _run,
int _mode,
int _pmode,
float* _in,
float* _out,
int _io_buffsize,
int _sample_rate,
double _tau_attack,
double _tau_decay,
int _n_tau,
double _max_gain,
double _var_gain,
double _fixed_gain,
double _max_input,
double _out_targ,
double _tau_fast_backaverage,
double _tau_fast_decay,
double _pop_ratio,
int _hang_enable,
double _tau_hang_backmult,
double _hangtime,
double _hang_thresh,
double _tau_hang_decay
) :
//initialize per call parameters
a->run = run;
a->mode = mode;
a->pmode = pmode;
a->in = in;
a->out = out;
a->io_buffsize = io_buffsize;
a->sample_rate = (double) sample_rate;
a->tau_attack = tau_attack;
a->tau_decay = tau_decay;
a->n_tau = n_tau;
a->max_gain = max_gain;
a->var_gain = var_gain;
a->fixed_gain = fixed_gain;
a->max_input = max_input;
a->out_targ = out_targ;
a->tau_fast_backaverage = tau_fast_backaverage;
a->tau_fast_decay = tau_fast_decay;
a->pop_ratio = pop_ratio;
a->hang_enable = hang_enable;
a->tau_hang_backmult = tau_hang_backmult;
a->hangtime = hangtime;
a->hang_thresh = hang_thresh;
a->tau_hang_decay = tau_hang_decay;
calc_wcpagc (a);
return a;
run(_run),
mode(_mode),
pmode(_pmode),
in(_in),
out(_out),
io_buffsize(_io_buffsize),
sample_rate((double) _sample_rate),
tau_attack(_tau_attack),
tau_decay(_tau_decay),
n_tau(_n_tau),
max_gain(_max_gain),
var_gain(_var_gain),
fixed_gain(_fixed_gain),
max_input(_max_input),
out_targ(_out_targ),
tau_fast_backaverage(_tau_fast_backaverage),
tau_fast_decay(_tau_fast_decay),
pop_ratio(_pop_ratio),
hang_enable(_hang_enable),
tau_hang_backmult(_tau_hang_backmult),
hangtime(_hangtime),
hang_thresh(_hang_thresh),
tau_hang_decay(_tau_hang_decay)
{
calc();
}
void WCPAGC::loadWcpAGC (WCPAGC *a)
void WCPAGC::loadWcpAGC()
{
double tmp;
//calculate internal parameters
a->attack_buffsize = (int)ceil(a->sample_rate * a->n_tau * a->tau_attack);
a->in_index = a->attack_buffsize + a->out_index;
a->attack_mult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_attack));
a->decay_mult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_decay));
a->fast_decay_mult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_fast_decay));
a->fast_backmult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_fast_backaverage));
a->onemfast_backmult = 1.0 - a->fast_backmult;
attack_buffsize = (int)ceil(sample_rate * n_tau * tau_attack);
in_index = attack_buffsize + out_index;
attack_mult = 1.0 - exp(-1.0 / (sample_rate * tau_attack));
decay_mult = 1.0 - exp(-1.0 / (sample_rate * tau_decay));
fast_decay_mult = 1.0 - exp(-1.0 / (sample_rate * tau_fast_decay));
fast_backmult = 1.0 - exp(-1.0 / (sample_rate * tau_fast_backaverage));
onemfast_backmult = 1.0 - fast_backmult;
a->out_target = a->out_targ * (1.0 - exp(-(double)a->n_tau)) * 0.9999;
a->min_volts = a->out_target / (a->var_gain * a->max_gain);
a->inv_out_target = 1.0 / a->out_target;
out_target = out_targ * (1.0 - exp(-(double)n_tau)) * 0.9999;
min_volts = out_target / (var_gain * max_gain);
inv_out_target = 1.0 / out_target;
tmp = log10(a->out_target / (a->max_input * a->var_gain * a->max_gain));
tmp = log10(out_target / (max_input * var_gain * max_gain));
if (tmp == 0.0)
tmp = 1e-16;
a->slope_constant = (a->out_target * (1.0 - 1.0 / a->var_gain)) / tmp;
a->inv_max_input = 1.0 / a->max_input;
tmp = pow (10.0, (a->hang_thresh - 1.0) / 0.125);
a->hang_level = (a->max_input * tmp + (a->out_target /
(a->var_gain * a->max_gain)) * (1.0 - tmp)) * 0.637;
a->hang_backmult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_hang_backmult));
a->onemhang_backmult = 1.0 - a->hang_backmult;
a->hang_decay_mult = 1.0 - exp(-1.0 / (a->sample_rate * a->tau_hang_decay));
slope_constant = (out_target * (1.0 - 1.0 / var_gain)) / tmp;
inv_max_input = 1.0 / max_input;
tmp = pow (10.0, (hang_thresh - 1.0) / 0.125);
hang_level = (max_input * tmp + (out_target /
(var_gain * max_gain)) * (1.0 - tmp)) * 0.637;
hang_backmult = 1.0 - exp(-1.0 / (sample_rate * tau_hang_backmult));
onemhang_backmult = 1.0 - hang_backmult;
hang_decay_mult = 1.0 - exp(-1.0 / (sample_rate * tau_hang_decay));
}
void WCPAGC::destroy_wcpagc (WCPAGC *a)
void WCPAGC::flush()
{
decalc_wcpagc (a);
delete (a);
std::fill(ring.begin(), ring.end(), 0);
std::fill(abs_ring.begin(), abs_ring.end(), 0);
ring_max = 0.0;
}
void WCPAGC::flush_wcpagc (WCPAGC *a)
{
memset ((void *)a->ring, 0, sizeof(double) * RB_SIZE * 2);
a->ring_max = 0.0;
memset ((void *)a->abs_ring, 0, sizeof(double)* RB_SIZE);
}
void WCPAGC::xwcpagc (WCPAGC *a)
void WCPAGC::execute()
{
int i, j, k;
double mult;
if (a->run)
if (run)
{
if (a->mode == 0)
if (mode == 0)
{
for (i = 0; i < a->io_buffsize; i++)
for (i = 0; i < io_buffsize; i++)
{
a->out[2 * i + 0] = a->fixed_gain * a->in[2 * i + 0];
a->out[2 * i + 1] = a->fixed_gain * a->in[2 * i + 1];
out[2 * i + 0] = fixed_gain * in[2 * i + 0];
out[2 * i + 1] = fixed_gain * in[2 * i + 1];
}
return;
}
for (i = 0; i < a->io_buffsize; i++)
for (i = 0; i < io_buffsize; i++)
{
if (++a->out_index >= a->ring_buffsize)
a->out_index -= a->ring_buffsize;
if (++out_index >= ring_buffsize)
out_index -= ring_buffsize;
if (++a->in_index >= a->ring_buffsize)
a->in_index -= a->ring_buffsize;
if (++in_index >= ring_buffsize)
in_index -= ring_buffsize;
a->out_sample[0] = a->ring[2 * a->out_index + 0];
a->out_sample[1] = a->ring[2 * a->out_index + 1];
a->abs_out_sample = a->abs_ring[a->out_index];
double xr = a->ring[2 * a->in_index + 0] = a->in[2 * i + 0];
double xi = a->ring[2 * a->in_index + 1] = a->in[2 * i + 1];
out_sample[0] = ring[2 * out_index + 0];
out_sample[1] = ring[2 * out_index + 1];
abs_out_sample = abs_ring[out_index];
double xr = ring[2 * in_index + 0] = in[2 * i + 0];
double xi = ring[2 * in_index + 1] = in[2 * i + 1];
if (a->pmode == 0)
a->abs_ring[a->in_index] = std::max(fabs(xr), fabs(xi));
if (pmode == 0)
abs_ring[in_index] = std::max(fabs(xr), fabs(xi));
else
a->abs_ring[a->in_index] = sqrt(xr*xr + xi*xi);
abs_ring[in_index] = sqrt(xr*xr + xi*xi);
a->fast_backaverage = a->fast_backmult * a->abs_out_sample + a->onemfast_backmult * a->fast_backaverage;
a->hang_backaverage = a->hang_backmult * a->abs_out_sample + a->onemhang_backmult * a->hang_backaverage;
fast_backaverage = fast_backmult * abs_out_sample + onemfast_backmult * fast_backaverage;
hang_backaverage = hang_backmult * abs_out_sample + onemhang_backmult * hang_backaverage;
if ((a->abs_out_sample >= a->ring_max) && (a->abs_out_sample > 0.0))
if ((abs_out_sample >= ring_max) && (abs_out_sample > 0.0))
{
a->ring_max = 0.0;
k = a->out_index;
ring_max = 0.0;
k = out_index;
for (j = 0; j < a->attack_buffsize; j++)
for (j = 0; j < attack_buffsize; j++)
{
if (++k == a->ring_buffsize)
if (++k == ring_buffsize)
k = 0;
if (a->abs_ring[k] > a->ring_max)
a->ring_max = a->abs_ring[k];
if (abs_ring[k] > ring_max)
ring_max = abs_ring[k];
}
}
if (a->abs_ring[a->in_index] > a->ring_max)
a->ring_max = a->abs_ring[a->in_index];
if (abs_ring[in_index] > ring_max)
ring_max = abs_ring[in_index];
if (a->hang_counter > 0)
--a->hang_counter;
if (hang_counter > 0)
--hang_counter;
switch (a->state)
switch (state)
{
case 0:
{
if (a->ring_max >= a->volts)
if (ring_max >= volts)
{
a->volts += (a->ring_max - a->volts) * a->attack_mult;
volts += (ring_max - volts) * attack_mult;
}
else
{
if (a->volts > a->pop_ratio * a->fast_backaverage)
if (volts > pop_ratio * fast_backaverage)
{
a->state = 1;
a->volts += (a->ring_max - a->volts) * a->fast_decay_mult;
state = 1;
volts += (ring_max - volts) * fast_decay_mult;
}
else
{
if (a->hang_enable && (a->hang_backaverage > a->hang_level))
if (hang_enable && (hang_backaverage > hang_level))
{
a->state = 2;
a->hang_counter = (int)(a->hangtime * a->sample_rate);
a->decay_type = 1;
state = 2;
hang_counter = (int)(hangtime * sample_rate);
decay_type = 1;
}
else
{
a->state = 3;
a->volts += (a->ring_max - a->volts) * a->decay_mult;
a->decay_type = 0;
state = 3;
volts += (ring_max - volts) * decay_mult;
decay_type = 0;
}
}
}
@ -259,34 +242,34 @@ void WCPAGC::xwcpagc (WCPAGC *a)
case 1:
{
if (a->ring_max >= a->volts)
if (ring_max >= volts)
{
a->state = 0;
a->volts += (a->ring_max - a->volts) * a->attack_mult;
state = 0;
volts += (ring_max - volts) * attack_mult;
}
else
{
if (a->volts > a->save_volts)
if (volts > save_volts)
{
a->volts += (a->ring_max - a->volts) * a->fast_decay_mult;
volts += (ring_max - volts) * fast_decay_mult;
}
else
{
if (a->hang_counter > 0)
if (hang_counter > 0)
{
a->state = 2;
state = 2;
}
else
{
if (a->decay_type == 0)
if (decay_type == 0)
{
a->state = 3;
a->volts += (a->ring_max - a->volts) * a->decay_mult;
state = 3;
volts += (ring_max - volts) * decay_mult;
}
else
{
a->state = 4;
a->volts += (a->ring_max - a->volts) * a->hang_decay_mult;
state = 4;
volts += (ring_max - volts) * hang_decay_mult;
}
}
}
@ -296,18 +279,18 @@ void WCPAGC::xwcpagc (WCPAGC *a)
case 2:
{
if (a->ring_max >= a->volts)
if (ring_max >= volts)
{
a->state = 0;
a->save_volts = a->volts;
a->volts += (a->ring_max - a->volts) * a->attack_mult;
state = 0;
save_volts = volts;
volts += (ring_max - volts) * attack_mult;
}
else
{
if (a->hang_counter == 0)
if (hang_counter == 0)
{
a->state = 4;
a->volts += (a->ring_max - a->volts) * a->hang_decay_mult;
state = 4;
volts += (ring_max - volts) * hang_decay_mult;
}
}
break;
@ -315,280 +298,202 @@ void WCPAGC::xwcpagc (WCPAGC *a)
case 3:
{
if (a->ring_max >= a->volts)
if (ring_max >= volts)
{
a->state = 0;
a->save_volts = a->volts;
a->volts += (a->ring_max - a->volts) * a->attack_mult;
state = 0;
save_volts = volts;
volts += (ring_max - volts) * attack_mult;
}
else
{
a->volts += (a->ring_max - a->volts) * a->decay_mult;
volts += (ring_max - volts) * decay_mult;
}
break;
}
case 4:
{
if (a->ring_max >= a->volts)
if (ring_max >= volts)
{
a->state = 0;
a->save_volts = a->volts;
a->volts += (a->ring_max - a->volts) * a->attack_mult;
state = 0;
save_volts = volts;
volts += (ring_max - volts) * attack_mult;
}
else
{
a->volts += (a->ring_max - a->volts) * a->hang_decay_mult;
volts += (ring_max - volts) * hang_decay_mult;
}
break;
}
}
if (a->volts < a->min_volts)
a->volts = a->min_volts;
if (volts < min_volts)
volts = min_volts;
a->gain = a->volts * a->inv_out_target;
mult = (a->out_target - a->slope_constant * std::min (0.0, log10(a->inv_max_input * a->volts))) / a->volts;
a->out[2 * i + 0] = a->out_sample[0] * mult;
a->out[2 * i + 1] = a->out_sample[1] * mult;
gain = volts * inv_out_target;
mult = (out_target - slope_constant * std::min (0.0, log10(inv_max_input * volts))) / volts;
out[2 * i + 0] = out_sample[0] * mult;
out[2 * i + 1] = out_sample[1] * mult;
}
}
else if (a->out != a->in)
else if (out != in)
{
std::copy(a->in, a->in + a->io_buffsize * 2, a->out);
std::copy(in, in + io_buffsize * 2, out);
}
}
void WCPAGC::setBuffers_wcpagc (WCPAGC *a, float* in, float* out)
void WCPAGC::setBuffers(float* _in, float* _out)
{
a->in = in;
a->out = out;
in = _in;
out = _out;
}
void WCPAGC::setSamplerate_wcpagc (WCPAGC *a, int rate)
void WCPAGC::setSamplerate(int _rate)
{
decalc_wcpagc (a);
a->sample_rate = rate;
calc_wcpagc (a);
sample_rate = _rate;
calc();
}
void WCPAGC::setSize_wcpagc (WCPAGC *a, int size)
void WCPAGC::setSize(int _size)
{
decalc_wcpagc (a);
a->io_buffsize = size;
calc_wcpagc (a);
io_buffsize = _size;
calc();
}
/********************************************************************************************************
* *
* RXA Properties *
* Public Properties *
* *
********************************************************************************************************/
void WCPAGC::SetAGCMode (RXA& rxa, int mode)
void WCPAGC::setMode(int _mode)
{
switch (mode)
switch (_mode)
{
case 0: //agcOFF
rxa.agc->mode = 0;
loadWcpAGC ( rxa.agc );
mode = 0;
loadWcpAGC();
break;
case 1: //agcLONG
rxa.agc->mode = 1;
rxa.agc->hangtime = 2.000;
rxa.agc->tau_decay = 2.000;
loadWcpAGC ( rxa.agc );
mode = 1;
hangtime = 2.000;
tau_decay = 2.000;
loadWcpAGC();
break;
case 2: //agcSLOW
rxa.agc->mode = 2;
rxa.agc->hangtime = 1.000;
rxa.agc->tau_decay = 0.500;
loadWcpAGC ( rxa.agc );
mode = 2;
hangtime = 1.000;
tau_decay = 0.500;
loadWcpAGC();
break;
case 3: //agcMED
rxa.agc->mode = 3;
rxa.agc->hang_thresh = 1.0;
rxa.agc->hangtime = 0.000;
rxa.agc->tau_decay = 0.250;
loadWcpAGC ( rxa.agc );
mode = 3;
hang_thresh = 1.0;
hangtime = 0.000;
tau_decay = 0.250;
loadWcpAGC();
break;
case 4: //agcFAST
rxa.agc->mode = 4;
rxa.agc->hang_thresh = 1.0;
rxa.agc->hangtime = 0.000;
rxa.agc->tau_decay = 0.050;
loadWcpAGC ( rxa.agc );
mode = 4;
hang_thresh = 1.0;
hangtime = 0.000;
tau_decay = 0.050;
loadWcpAGC();
break;
default:
rxa.agc->mode = 5;
mode = 5;
break;
}
}
void WCPAGC::SetAGCAttack (RXA& rxa, int attack)
void WCPAGC::setFixed(double _fixed_agc)
{
rxa.agc->tau_attack = (float)attack / 1000.0;
loadWcpAGC ( rxa.agc );
fixed_gain = pow (10.0, (double) _fixed_agc / 20.0);
loadWcpAGC();
}
void WCPAGC::SetAGCDecay (RXA& rxa, int decay)
void WCPAGC::setAttack(int _attack)
{
rxa.agc->tau_decay = (float)decay / 1000.0;
loadWcpAGC ( rxa.agc );
tau_attack = (double) _attack / 1000.0;
loadWcpAGC();
}
void WCPAGC::SetAGCHang (RXA& rxa, int hang)
void WCPAGC::setDecay(int _decay)
{
rxa.agc->hangtime = (float)hang / 1000.0;
loadWcpAGC ( rxa.agc );
tau_decay = (double) _decay / 1000.0;
loadWcpAGC();
}
void WCPAGC::GetAGCHangLevel(RXA& rxa, double *hangLevel)
void WCPAGC::setHang(int _hang)
{
hangtime = (double) _hang / 1000.0;
loadWcpAGC();
}
void WCPAGC::getHangLevel(double *hangLevel)
//for line on bandscope
{
*hangLevel = 20.0 * log10( rxa.agc->hang_level / 0.637 );
*hangLevel = 20.0 * log10(hang_level / 0.637);
}
void WCPAGC::SetAGCHangLevel(RXA& rxa, double hangLevel)
void WCPAGC::setHangLevel(double _hangLevel)
//for line on bandscope
{
double convert, tmp;
if (rxa.agc->max_input > rxa.agc->min_volts)
if (max_input > min_volts)
{
convert = pow (10.0, hangLevel / 20.0);
tmp = std::max(1e-8, (convert - rxa.agc->min_volts) / (rxa.agc->max_input - rxa.agc->min_volts));
rxa.agc->hang_thresh = 1.0 + 0.125 * log10 (tmp);
convert = pow (10.0, _hangLevel / 20.0);
tmp = std::max(1e-8, (convert - min_volts) / (max_input - min_volts));
hang_thresh = 1.0 + 0.125 * log10 (tmp);
}
else
rxa.agc->hang_thresh = 1.0;
hang_thresh = 1.0;
loadWcpAGC ( rxa.agc );
loadWcpAGC();
}
void WCPAGC::GetAGCHangThreshold(RXA& rxa, int *hangthreshold)
void WCPAGC::getHangThreshold(int *hangthreshold)
//for slider in setup
{
*hangthreshold = (int) (100.0 * rxa.agc->hang_thresh);
*hangthreshold = (int) (100.0 * hang_thresh);
}
void WCPAGC::SetAGCHangThreshold (RXA& rxa, int hangthreshold)
void WCPAGC::setHangThreshold(int _hangthreshold)
//For slider in setup
{
rxa.agc->hang_thresh = (double) hangthreshold / 100.0;
loadWcpAGC ( rxa.agc );
hang_thresh = (double) _hangthreshold / 100.0;
loadWcpAGC();
}
void WCPAGC::GetAGCThresh(RXA& rxa, double *thresh, double size, double rate)
//for line on bandscope.
{
double noise_offset;
noise_offset = 10.0 * log10((rxa.nbp0->fhigh - rxa.nbp0->flow) * size / rate);
*thresh = 20.0 * log10( rxa.agc->min_volts ) - noise_offset;
}
void WCPAGC::SetAGCThresh(RXA& rxa, double thresh, double size, double rate)
//for line on bandscope
{
double noise_offset;
noise_offset = 10.0 * log10((rxa.nbp0->fhigh - rxa.nbp0->flow) * size / rate);
rxa.agc->max_gain = rxa.agc->out_target / (rxa.agc->var_gain * pow (10.0, (thresh + noise_offset) / 20.0));
loadWcpAGC ( rxa.agc );
}
void WCPAGC::GetAGCTop(RXA& rxa, double *max_agc)
void WCPAGC::getTop(double *max_agc)
//for AGC Max Gain in setup
{
*max_agc = 20 * log10 (rxa.agc->max_gain);
*max_agc = 20 * log10 (max_gain);
}
void WCPAGC::SetAGCTop (RXA& rxa, double max_agc)
void WCPAGC::setTop(double _max_agc)
//for AGC Max Gain in setup
{
rxa.agc->max_gain = pow (10.0, (double) max_agc / 20.0);
loadWcpAGC ( rxa.agc );
max_gain = pow (10.0, (double) _max_agc / 20.0);
loadWcpAGC();
}
void WCPAGC::SetAGCSlope (RXA& rxa, int slope)
void WCPAGC::setSlope(int _slope)
{
rxa.agc->var_gain = pow (10.0, (double) slope / 20.0 / 10.0);
loadWcpAGC ( rxa.agc );
var_gain = pow (10.0, (double) _slope / 20.0 / 10.0);
loadWcpAGC();
}
void WCPAGC::SetAGCFixed (RXA& rxa, double fixed_agc)
void WCPAGC::setMaxInputLevel(double _level)
{
rxa.agc->fixed_gain = pow (10.0, (double) fixed_agc / 20.0);
loadWcpAGC ( rxa.agc );
max_input = _level;
loadWcpAGC();
}
void WCPAGC::SetAGCMaxInputLevel (RXA& rxa, double level)
void WCPAGC::setRun(int state)
{
rxa.agc->max_input = level;
loadWcpAGC ( rxa.agc );
}
/********************************************************************************************************
* *
* TXA Properties *
* *
********************************************************************************************************/
void WCPAGC::SetALCSt (TXA& txa, int state)
{
txa.alc->run = state;
}
void WCPAGC::SetALCAttack (TXA& txa, int attack)
{
txa.alc->tau_attack = (double) attack / 1000.0;
loadWcpAGC(txa.alc);
}
void WCPAGC::SetALCDecay (TXA& txa, int decay)
{
txa.alc->tau_decay = (double) decay / 1000.0;
loadWcpAGC(txa.alc);
}
void WCPAGC::SetALCHang (TXA& txa, int hang)
{
txa.alc->hangtime = (double) hang / 1000.0;
loadWcpAGC(txa.alc);
}
void WCPAGC::SetALCMaxGain (TXA& txa, double maxgain)
{
txa.alc->max_gain = pow (10.0,(double) maxgain / 20.0);
loadWcpAGC(txa.alc);
}
void WCPAGC::SetLevelerSt (TXA& txa, int state)
{
txa.leveler->run = state;
}
void WCPAGC::SetLevelerAttack (TXA& txa, int attack)
{
txa.leveler->tau_attack = (double) attack / 1000.0;
loadWcpAGC(txa.leveler);
}
void WCPAGC::SetLevelerDecay (TXA& txa, int decay)
{
txa.leveler->tau_decay = (double) decay / 1000.0;
loadWcpAGC(txa.leveler);
}
void WCPAGC::SetLevelerHang (TXA& txa, int hang)
{
txa.leveler->hangtime = (double) hang / 1000.0;
loadWcpAGC(txa.leveler);
}
void WCPAGC::SetLevelerTop (TXA& txa, double maxgain)
{
txa.leveler->max_gain = pow (10.0,(double) maxgain / 20.0);
loadWcpAGC(txa.leveler);
run = state;
}
} // namespace WDSP

View File

@ -28,6 +28,8 @@ warren@wpratt.com
#ifndef wdsp_wcpagc_h
#define wdsp_wcpagc_h
#include <array>
#include "export.h"
#define MAX_SAMPLE_RATE (384000.0)
@ -37,9 +39,6 @@ warren@wpratt.com
namespace WDSP {
class RXA;
class TXA;
class WDSP_API WCPAGC
{
public:
@ -71,16 +70,16 @@ public:
int in_index;
int attack_buffsize;
double* ring;
double* abs_ring;
int ring_buffsize;
std::array<double, RB_SIZE*2> ring;
std::array<double, RB_SIZE> abs_ring;
static const int ring_buffsize = RB_SIZE;
double ring_max;
double attack_mult;
double decay_mult;
double volts;
double save_volts;
double out_sample[2];
std::array<double, 2> out_sample;
double abs_out_sample;
int state;
@ -106,8 +105,7 @@ public:
double hang_decay_mult;
int decay_type;
static void xwcpagc (WCPAGC *a);
static WCPAGC* create_wcpagc (
WCPAGC(
int run,
int mode,
int pmode,
@ -132,43 +130,34 @@ public:
double hang_thresh,
double tau_hang_decay
);
static void destroy_wcpagc (WCPAGC *a);
static void flush_wcpagc (WCPAGC *a);
static void setBuffers_wcpagc (WCPAGC *a, float* in, float* out);
static void setSamplerate_wcpagc (WCPAGC *a, int rate);
static void setSize_wcpagc (WCPAGC *a, int size);
// RXA Properties
static void SetAGCMode (RXA& rxa, int mode);
static void SetAGCFixed (RXA& rxa, double fixed_agc);
static void SetAGCAttack (RXA& rxa, int attack);
static void SetAGCDecay (RXA& rxa, int decay);
static void SetAGCHang (RXA& rxa, int hang);
static void GetAGCHangLevel(RXA& rxa, double *hangLevel);
static void SetAGCHangLevel(RXA& rxa, double hangLevel);
static void GetAGCHangThreshold(RXA& rxa, int *hangthreshold);
static void SetAGCHangThreshold (RXA& rxa, int hangthreshold);
static void GetAGCTop(RXA& rxa, double *max_agc);
static void SetAGCTop (RXA& rxa, double max_agc);
static void SetAGCSlope (RXA& rxa, int slope);
static void SetAGCThresh(RXA& rxa, double thresh, double size, double rate);
static void GetAGCThresh(RXA& rxa, double *thresh, double size, double rate);
static void SetAGCMaxInputLevel (RXA& rxa, double level);
// TXA Properties
static void SetALCSt (TXA& txa, int state);
static void SetALCAttack (TXA& txa, int attack);
static void SetALCDecay (TXA& txa, int decay);
static void SetALCHang (TXA& txa, int hang);
static void SetLevelerSt (TXA& txa, int state);
static void SetLevelerAttack (TXA& txa, int attack);
static void SetLevelerDecay (TXA& txa, int decay);
static void SetLevelerHang (TXA& txa, int hang);
static void SetLevelerTop (TXA& txa, double maxgain);
static void SetALCMaxGain (TXA& txa, double maxgain);
WCPAGC(const WCPAGC&) = delete;
WCPAGC& operator=(const WCPAGC& other) = delete;
~WCPAGC() = default;
void flush();
void execute();
void setBuffers(float* in, float* out);
void setSamplerate(int rate);
void setSize(int size);
// Public Properties
void setMode(int mode);
void setFixed(double fixed_agc);
void setAttack(int attack);
void setDecay(int decay);
void setHang(int hang);
void getHangLevel(double *hangLevel);
void setHangLevel(double hangLevel);
void getHangThreshold(int *hangthreshold);
void setHangThreshold(int hangthreshold);
void getTop(double *max_agc);
void setTop(double max_agc);
void setSlope(int slope);
void setMaxInputLevel(double level);
void setRun(int state);
void loadWcpAGC();
private:
static void loadWcpAGC (WCPAGC *a);
static void calc_wcpagc (WCPAGC *a);
static void decalc_wcpagc (WCPAGC *a);
void calc();
};
} // namespace WDSP