936 lines
36 KiB
C
936 lines
36 KiB
C
/* TXA.c
|
|
|
|
This file is part of a program that implements a Software-Defined Radio.
|
|
|
|
Copyright (C) 2013, 2014, 2016, 2017, 2021, 2023 Warren Pratt, NR0V
|
|
|
|
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 2
|
|
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, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
The author can be reached by email at
|
|
|
|
warren@wpratt.com
|
|
|
|
*/
|
|
|
|
#include "comm.h"
|
|
|
|
struct _txa txa[MAX_CHANNELS];
|
|
|
|
void create_txa (int channel)
|
|
{
|
|
txa[channel].mode = TXA_LSB;
|
|
txa[channel].f_low = -5000.0;
|
|
txa[channel].f_high = - 100.0;
|
|
txa[channel].inbuff = (double *) malloc0 (1 * ch[channel].dsp_insize * sizeof (complex));
|
|
txa[channel].outbuff = (double *) malloc0 (1 * ch[channel].dsp_outsize * sizeof (complex));
|
|
txa[channel].midbuff = (double *) malloc0 (2 * ch[channel].dsp_size * sizeof (complex));
|
|
|
|
txa[channel].rsmpin.p = create_resample (
|
|
0, // run - will be turned on below if needed
|
|
ch[channel].dsp_insize, // input buffer size
|
|
txa[channel].inbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
ch[channel].in_rate, // input sample rate
|
|
ch[channel].dsp_rate, // output sample rate
|
|
0.0, // select cutoff automatically
|
|
0, // select ncoef automatically
|
|
1.0); // gain
|
|
|
|
txa[channel].gen0.p = create_gen (
|
|
0, // run
|
|
ch[channel].dsp_size, // buffer size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // sample rate
|
|
2); // mode
|
|
|
|
txa[channel].panel.p = create_panel (
|
|
channel, // channel number
|
|
1, // run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
1.0, // gain1
|
|
1.0, // gain2I
|
|
1.0, // gain2Q
|
|
2, // 1 to use Q, 2 to use I for input
|
|
0); // 0, no copy
|
|
|
|
txa[channel].phrot.p = create_phrot (
|
|
0, // run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
338.0, // 1/2 of phase frequency
|
|
8); // number of stages
|
|
|
|
txa[channel].micmeter.p = create_meter (
|
|
1, // run
|
|
0, // optional pointer to another 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_MIC_AV, // index for average value
|
|
TXA_MIC_PK, // index for peak value
|
|
-1, // index for gain value
|
|
0); // pointer for gain computation
|
|
|
|
txa[channel].amsq.p = create_amsq (
|
|
0, // run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
txa[channel].midbuff, // trigger buffer
|
|
ch[channel].dsp_rate, // sample rate
|
|
0.010, // time constant for averaging signal
|
|
0.004, // up-slew time
|
|
0.004, // down-slew time
|
|
0.180, // signal level to initiate tail
|
|
0.200, // signal level to initiate unmute
|
|
0.000, // minimum tail length
|
|
0.025, // maximum tail length
|
|
0.200); // muted gain
|
|
|
|
{
|
|
double default_F[11] = {0.0, 32.0, 63.0, 125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0, 8000.0, 16000.0};
|
|
double default_G[11] = {0.0, -12.0, -12.0, -12.0, -1.0, +1.0, +4.0, +9.0, +12.0, -10.0, -10.0};
|
|
//double default_G[11] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
|
txa[channel].eqp.p = create_eqp (
|
|
0, // run - OFF by default
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
|
0, // minimum phase flag
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
10, // nfreqs
|
|
default_F, // vector of frequencies
|
|
default_G, // vector of gain values
|
|
0, // cutoff mode
|
|
0, // wintype
|
|
ch[channel].dsp_rate); // samplerate
|
|
}
|
|
|
|
txa[channel].eqmeter.p = create_meter (
|
|
1, // run
|
|
&(txa[channel].eqp.p->run), // pointer to eqp 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_EQ_AV, // index for average value
|
|
TXA_EQ_PK, // index for peak value
|
|
-1, // index for gain value
|
|
0); // pointer for gain computation
|
|
|
|
txa[channel].preemph.p = create_emphp (
|
|
0, // run
|
|
1, // position
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
|
0, // minimum phase flag
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer,
|
|
ch[channel].dsp_rate, // sample rate
|
|
0, // pre-emphasis type
|
|
300.0, // f_low
|
|
3000.0); // f_high
|
|
|
|
txa[channel].leveler.p = create_wcpagc (
|
|
0, // run - OFF by default
|
|
5, // mode
|
|
0, // 0 for max(I,Q), 1 for envelope
|
|
txa[channel].midbuff, // input buff pointer
|
|
txa[channel].midbuff, // output buff pointer
|
|
ch[channel].dsp_size, // io_buffsize
|
|
ch[channel].dsp_rate, // sample rate
|
|
0.001, // tau_attack
|
|
0.500, // tau_decay
|
|
6, // n_tau
|
|
1.778, // max_gain
|
|
1.0, // var_gain
|
|
1.0, // fixed_gain
|
|
1.0, // max_input
|
|
1.05, // out_targ
|
|
0.250, // tau_fast_backaverage
|
|
0.005, // tau_fast_decay
|
|
5.0, // pop_ratio
|
|
0, // hang_enable
|
|
0.500, // tau_hang_backmult
|
|
0.500, // hangtime
|
|
2.000, // hang_thresh
|
|
0.100); // tau_hang_decay
|
|
|
|
txa[channel].lvlrmeter.p = create_meter (
|
|
1, // run
|
|
&(txa[channel].leveler.p->run), // pointer to leveler 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_LVLR_AV, // index for average value
|
|
TXA_LVLR_PK, // index for peak value
|
|
TXA_LVLR_GAIN, // index for gain value
|
|
&txa[channel].leveler.p->gain); // pointer for gain computation
|
|
|
|
{
|
|
double default_F[5] = {200.0, 1000.0, 2000.0, 3000.0, 4000.0};
|
|
double default_G[5] = {0.0, 5.0, 10.0, 10.0, 5.0};
|
|
double default_E[5] = {7.0, 7.0, 7.0, 7.0, 7.0};
|
|
txa[channel].cfcomp.p = create_cfcomp(
|
|
0, // run
|
|
0, // position
|
|
0, // post-equalizer run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
2048, // fft size
|
|
4, // overlap
|
|
ch[channel].dsp_rate, // samplerate
|
|
1, // window type
|
|
0, // compression method
|
|
5, // nfreqs
|
|
0.0, // pre-compression
|
|
0.0, // pre-postequalization
|
|
default_F, // frequency array
|
|
default_G, // compression array
|
|
default_E, // eq array
|
|
0.25, // metering time constant
|
|
0.50); // display time constant
|
|
}
|
|
|
|
txa[channel].cfcmeter.p = create_meter (
|
|
1, // run
|
|
&(txa[channel].cfcomp.p->run), // pointer to eqp 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_CFC_AV, // index for average value
|
|
TXA_CFC_PK, // index for peak value
|
|
TXA_CFC_GAIN, // index for gain value
|
|
&txa[channel].cfcomp.p->gain); // pointer for gain computation
|
|
|
|
txa[channel].bp0.p = create_bandpass (
|
|
1, // always runs
|
|
0, // position
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
|
0, // flag for minimum phase
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
txa[channel].f_low, // low freq cutoff
|
|
txa[channel].f_high, // high freq cutoff
|
|
ch[channel].dsp_rate, // samplerate
|
|
1, // wintype
|
|
2.0); // gain
|
|
|
|
txa[channel].compressor.p = create_compressor (
|
|
0, // run - OFF by default
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
3.0); // gain
|
|
|
|
txa[channel].bp1.p = create_bandpass (
|
|
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
|
0, // position
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
|
0, // flag for minimum phase
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
txa[channel].f_low, // low freq cutoff
|
|
txa[channel].f_high, // high freq cutoff
|
|
ch[channel].dsp_rate, // samplerate
|
|
1, // wintype
|
|
2.0); // gain
|
|
|
|
txa[channel].osctrl.p = create_osctrl (
|
|
0, // run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // sample rate
|
|
1.95); // gain for clippings
|
|
|
|
txa[channel].bp2.p = create_bandpass (
|
|
0, // ONLY RUNS WHEN COMPRESSOR IS USED
|
|
0, // position
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of coefficients
|
|
0, // flag for minimum phase
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
txa[channel].f_low, // low freq cutoff
|
|
txa[channel].f_high, // high freq cutoff
|
|
ch[channel].dsp_rate, // samplerate
|
|
1, // wintype
|
|
1.0); // gain
|
|
|
|
txa[channel].compmeter.p = create_meter (
|
|
1, // run
|
|
&(txa[channel].compressor.p->run), // pointer to compressor 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_COMP_AV, // index for average value
|
|
TXA_COMP_PK, // index for peak value
|
|
-1, // index for gain value
|
|
0); // pointer for gain computation
|
|
|
|
txa[channel].alc.p = create_wcpagc (
|
|
1, // run - always ON
|
|
5, // mode
|
|
1, // 0 for max(I,Q), 1 for envelope
|
|
txa[channel].midbuff, // input buff pointer
|
|
txa[channel].midbuff, // output buff pointer
|
|
ch[channel].dsp_size, // io_buffsize
|
|
ch[channel].dsp_rate, // sample rate
|
|
0.001, // tau_attack
|
|
0.010, // tau_decay
|
|
6, // n_tau
|
|
1.0, // max_gain
|
|
1.0, // var_gain
|
|
1.0, // fixed_gain
|
|
1.0, // max_input
|
|
1.0, // out_targ
|
|
0.250, // tau_fast_backaverage
|
|
0.005, // tau_fast_decay
|
|
5.0, // pop_ratio
|
|
0, // hang_enable
|
|
0.500, // tau_hang_backmult
|
|
0.500, // hangtime
|
|
2.000, // hang_thresh
|
|
0.100); // tau_hang_decay
|
|
|
|
txa[channel].ammod.p = create_ammod (
|
|
0, // run - OFF by default
|
|
0, // mode: 0=>AM, 1=>DSB
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to output buffer
|
|
0.5); // carrier level
|
|
|
|
|
|
txa[channel].fmmod.p = create_fmmod (
|
|
0, // run - OFF by default
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
5000.0, // deviation
|
|
300.0, // low cutoff frequency
|
|
3000.0, // high cutoff frequency
|
|
1, // ctcss run control
|
|
0.10, // ctcss level
|
|
100.0, // ctcss frequency
|
|
1, // run bandpass filter
|
|
max(2048, ch[channel].dsp_size), // number coefficients for bandpass filter
|
|
0); // minimum phase flag
|
|
|
|
txa[channel].gen1.p = create_gen (
|
|
0, // run
|
|
ch[channel].dsp_size, // buffer size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // sample rate
|
|
0); // mode
|
|
|
|
txa[channel].uslew.p = create_uslew (
|
|
channel, // channel
|
|
&ch[channel].iob.ch_upslew, // pointer to channel upslew flag
|
|
ch[channel].dsp_size, // buffer size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // sample rate
|
|
0.000, // delay time
|
|
0.005); // upslew time
|
|
|
|
txa[channel].alcmeter.p = create_meter (
|
|
1, // run
|
|
0, // optional pointer to a 'run'
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // pointer to buffer
|
|
ch[channel].dsp_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_ALC_AV, // index for average value
|
|
TXA_ALC_PK, // index for peak value
|
|
TXA_ALC_GAIN, // index for gain value
|
|
&txa[channel].alc.p->gain); // pointer for gain computation
|
|
|
|
txa[channel].sip1.p = create_siphon (
|
|
1, // run
|
|
0, // position
|
|
0, // mode
|
|
0, // disp
|
|
ch[channel].dsp_size, // input buffer size
|
|
txa[channel].midbuff, // input buffer
|
|
16384, // number of samples to buffer
|
|
16384, // fft size for spectrum
|
|
1); // specmode
|
|
|
|
txa[channel].calcc.p = create_calcc (
|
|
channel, // channel number
|
|
1, // run calibration
|
|
1024, // input buffer size
|
|
ch[channel].in_rate, // samplerate
|
|
16, // ints
|
|
256, // spi
|
|
(1.0 / 0.4072), // hw_scale
|
|
0.1, // mox delay
|
|
0.0, // loop delay
|
|
0.8, // ptol
|
|
0, // mox
|
|
0, // solidmox
|
|
1, // pin mode
|
|
1, // map mode
|
|
0, // stbl mode
|
|
256, // pin samples
|
|
0.9); // alpha
|
|
|
|
txa[channel].iqc.p0 = txa[channel].iqc.p1 = create_iqc (
|
|
0, // run
|
|
ch[channel].dsp_size, // size
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
(double)ch[channel].dsp_rate, // sample rate
|
|
16, // ints
|
|
0.005, // changeover time
|
|
256); // spi
|
|
|
|
txa[channel].cfir.p = create_cfir(
|
|
0, // run
|
|
ch[channel].dsp_size, // size
|
|
max(2048, ch[channel].dsp_size), // number of filter coefficients
|
|
0, // minimum phase flag
|
|
txa[channel].midbuff, // input buffer
|
|
txa[channel].midbuff, // output buffer
|
|
ch[channel].dsp_rate, // input sample rate
|
|
ch[channel].out_rate, // CIC input sample rate
|
|
1, // CIC differential delay
|
|
640, // CIC interpolation factor
|
|
5, // CIC integrator-comb pairs
|
|
20000.0, // cutoff frequency
|
|
2, // brick-wall windowed rolloff
|
|
0.0, // raised-cosine transition width
|
|
0); // window type
|
|
|
|
txa[channel].rsmpout.p = create_resample (
|
|
0, // run - will be turned ON below if needed
|
|
ch[channel].dsp_size, // input size
|
|
txa[channel].midbuff, // pointer to input buffer
|
|
txa[channel].outbuff, // pointer to output buffer
|
|
ch[channel].dsp_rate, // input sample rate
|
|
ch[channel].out_rate, // output sample rate
|
|
0.0, // select cutoff automatically
|
|
0, // select ncoef automatically
|
|
0.980); // gain
|
|
|
|
txa[channel].outmeter.p = create_meter (
|
|
1, // run
|
|
0, // optional pointer to another 'run'
|
|
ch[channel].dsp_outsize, // size
|
|
txa[channel].outbuff, // pointer to buffer
|
|
ch[channel].out_rate, // samplerate
|
|
0.100, // averaging time constant
|
|
0.100, // peak decay time constant
|
|
txa[channel].meter, // result vector
|
|
txa[channel].pmtupdate, // locks for meter access
|
|
TXA_OUT_AV, // index for average value
|
|
TXA_OUT_PK, // index for peak value
|
|
-1, // index for gain value
|
|
0); // pointer for gain computation
|
|
|
|
// turn OFF / ON resamplers as needed
|
|
TXAResCheck (channel);
|
|
}
|
|
|
|
void destroy_txa (int channel)
|
|
{
|
|
// in reverse order, free each item we created
|
|
destroy_meter (txa[channel].outmeter.p);
|
|
destroy_resample (txa[channel].rsmpout.p);
|
|
destroy_cfir(txa[channel].cfir.p);
|
|
destroy_calcc (txa[channel].calcc.p);
|
|
destroy_iqc (txa[channel].iqc.p0);
|
|
destroy_siphon (txa[channel].sip1.p);
|
|
destroy_meter (txa[channel].alcmeter.p);
|
|
destroy_uslew (txa[channel].uslew.p);
|
|
destroy_gen (txa[channel].gen1.p);
|
|
destroy_fmmod (txa[channel].fmmod.p);
|
|
destroy_ammod (txa[channel].ammod.p);
|
|
destroy_wcpagc (txa[channel].alc.p);
|
|
destroy_meter (txa[channel].compmeter.p);
|
|
destroy_bandpass (txa[channel].bp2.p);
|
|
destroy_osctrl (txa[channel].osctrl.p);
|
|
destroy_bandpass (txa[channel].bp1.p);
|
|
destroy_compressor (txa[channel].compressor.p);
|
|
destroy_bandpass (txa[channel].bp0.p);
|
|
destroy_meter (txa[channel].cfcmeter.p);
|
|
destroy_cfcomp (txa[channel].cfcomp.p);
|
|
destroy_meter (txa[channel].lvlrmeter.p);
|
|
destroy_wcpagc (txa[channel].leveler.p);
|
|
destroy_emphp (txa[channel].preemph.p);
|
|
destroy_meter (txa[channel].eqmeter.p);
|
|
destroy_eqp (txa[channel].eqp.p);
|
|
destroy_amsq (txa[channel].amsq.p);
|
|
destroy_meter (txa[channel].micmeter.p);
|
|
destroy_phrot (txa[channel].phrot.p);
|
|
destroy_panel (txa[channel].panel.p);
|
|
destroy_gen (txa[channel].gen0.p);
|
|
destroy_resample (txa[channel].rsmpin.p);
|
|
_aligned_free (txa[channel].midbuff);
|
|
_aligned_free (txa[channel].outbuff);
|
|
_aligned_free (txa[channel].inbuff);
|
|
}
|
|
|
|
void flush_txa (int channel)
|
|
{
|
|
memset (txa[channel].inbuff, 0, 1 * ch[channel].dsp_insize * sizeof (complex));
|
|
memset (txa[channel].outbuff, 0, 1 * ch[channel].dsp_outsize * sizeof (complex));
|
|
memset (txa[channel].midbuff, 0, 2 * ch[channel].dsp_size * sizeof (complex));
|
|
flush_resample (txa[channel].rsmpin.p);
|
|
flush_gen (txa[channel].gen0.p);
|
|
flush_panel (txa[channel].panel.p);
|
|
flush_phrot (txa[channel].phrot.p);
|
|
flush_meter (txa[channel].micmeter.p);
|
|
flush_amsq (txa[channel].amsq.p);
|
|
flush_eqp (txa[channel].eqp.p);
|
|
flush_meter (txa[channel].eqmeter.p);
|
|
flush_emphp (txa[channel].preemph.p);
|
|
flush_wcpagc (txa[channel].leveler.p);
|
|
flush_meter (txa[channel].lvlrmeter.p);
|
|
flush_cfcomp (txa[channel].cfcomp.p);
|
|
flush_meter (txa[channel].cfcmeter.p);
|
|
flush_bandpass (txa[channel].bp0.p);
|
|
flush_compressor (txa[channel].compressor.p);
|
|
flush_bandpass (txa[channel].bp1.p);
|
|
flush_osctrl (txa[channel].osctrl.p);
|
|
flush_bandpass (txa[channel].bp2.p);
|
|
flush_meter (txa[channel].compmeter.p);
|
|
flush_wcpagc (txa[channel].alc.p);
|
|
flush_ammod (txa[channel].ammod.p);
|
|
flush_fmmod (txa[channel].fmmod.p);
|
|
flush_gen (txa[channel].gen1.p);
|
|
flush_uslew (txa[channel].uslew.p);
|
|
flush_meter (txa[channel].alcmeter.p);
|
|
flush_siphon (txa[channel].sip1.p);
|
|
flush_iqc (txa[channel].iqc.p0);
|
|
flush_cfir(txa[channel].cfir.p);
|
|
flush_resample (txa[channel].rsmpout.p);
|
|
flush_meter (txa[channel].outmeter.p);
|
|
}
|
|
|
|
void xtxa (int channel)
|
|
{
|
|
xresample (txa[channel].rsmpin.p); // input resampler
|
|
xgen (txa[channel].gen0.p); // input signal generator
|
|
xpanel (txa[channel].panel.p); // includes MIC gain
|
|
xphrot (txa[channel].phrot.p); // phase rotator
|
|
xmeter (txa[channel].micmeter.p); // MIC meter
|
|
xamsqcap (txa[channel].amsq.p); // downward expander capture
|
|
xamsq (txa[channel].amsq.p); // downward expander action
|
|
xeqp (txa[channel].eqp.p); // pre-EQ
|
|
xmeter (txa[channel].eqmeter.p); // EQ meter
|
|
xemphp (txa[channel].preemph.p, 0); // FM pre-emphasis (first option)
|
|
xwcpagc (txa[channel].leveler.p); // Leveler
|
|
xmeter (txa[channel].lvlrmeter.p); // Leveler Meter
|
|
xcfcomp (txa[channel].cfcomp.p, 0); // Continuous Frequency Compressor with post-EQ
|
|
xmeter (txa[channel].cfcmeter.p); // CFC+PostEQ Meter
|
|
xbandpass (txa[channel].bp0.p, 0); // primary bandpass filter
|
|
xcompressor (txa[channel].compressor.p); // COMP compressor
|
|
xbandpass (txa[channel].bp1.p, 0); // aux bandpass (runs if COMP)
|
|
xosctrl (txa[channel].osctrl.p); // CESSB Overshoot Control
|
|
xbandpass (txa[channel].bp2.p, 0); // aux bandpass (runs if CESSB)
|
|
xmeter (txa[channel].compmeter.p); // COMP meter
|
|
xwcpagc (txa[channel].alc.p); // ALC
|
|
xammod (txa[channel].ammod.p); // AM Modulator
|
|
xemphp (txa[channel].preemph.p, 1); // FM pre-emphasis (second option)
|
|
xfmmod (txa[channel].fmmod.p); // FM Modulator
|
|
xgen (txa[channel].gen1.p); // output signal generator (TUN and Two-tone)
|
|
xuslew (txa[channel].uslew.p); // up-slew for AM, FM, and gens
|
|
xmeter (txa[channel].alcmeter.p); // ALC Meter
|
|
xsiphon (txa[channel].sip1.p, 0); // siphon data for display
|
|
xiqc (txa[channel].iqc.p0); // PureSignal correction
|
|
xcfir(txa[channel].cfir.p); // compensating FIR filter (used Protocol_2 only)
|
|
xresample (txa[channel].rsmpout.p); // output resampler
|
|
xmeter (txa[channel].outmeter.p); // output meter
|
|
// print_peak_env ("env_exception.txt", ch[channel].dsp_outsize, txa[channel].outbuff, 0.7);
|
|
}
|
|
|
|
void setInputSamplerate_txa (int channel)
|
|
{
|
|
// buffers
|
|
_aligned_free (txa[channel].inbuff);
|
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
|
// input resampler
|
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
|
setInRate_resample (txa[channel].rsmpin.p, ch[channel].in_rate);
|
|
TXAResCheck (channel);
|
|
}
|
|
|
|
void setOutputSamplerate_txa (int channel)
|
|
{
|
|
// buffers
|
|
_aligned_free (txa[channel].outbuff);
|
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
|
// cfir - needs to know input rate of firmware CIC
|
|
setOutRate_cfir (txa[channel].cfir.p, ch[channel].out_rate);
|
|
// output resampler
|
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
|
setOutRate_resample (txa[channel].rsmpout.p, ch[channel].out_rate);
|
|
TXAResCheck (channel);
|
|
// output meter
|
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
|
setSamplerate_meter (txa[channel].outmeter.p, ch[channel].out_rate);
|
|
}
|
|
|
|
void setDSPSamplerate_txa (int channel)
|
|
{
|
|
// buffers
|
|
_aligned_free (txa[channel].inbuff);
|
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
|
_aligned_free (txa[channel].outbuff);
|
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
|
// input resampler
|
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
|
setOutRate_resample (txa[channel].rsmpin.p, ch[channel].dsp_rate);
|
|
// dsp_rate blocks
|
|
setSamplerate_gen (txa[channel].gen0.p, ch[channel].dsp_rate);
|
|
setSamplerate_panel (txa[channel].panel.p, ch[channel].dsp_rate);
|
|
setSamplerate_phrot (txa[channel].phrot.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].micmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_amsq (txa[channel].amsq.p, ch[channel].dsp_rate);
|
|
setSamplerate_eqp (txa[channel].eqp.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].eqmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_emphp (txa[channel].preemph.p, ch[channel].dsp_rate);
|
|
setSamplerate_wcpagc (txa[channel].leveler.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].lvlrmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_cfcomp (txa[channel].cfcomp.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].cfcmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_bandpass (txa[channel].bp0.p, ch[channel].dsp_rate);
|
|
setSamplerate_compressor (txa[channel].compressor.p, ch[channel].dsp_rate);
|
|
setSamplerate_bandpass (txa[channel].bp1.p, ch[channel].dsp_rate);
|
|
setSamplerate_osctrl (txa[channel].osctrl.p, ch[channel].dsp_rate);
|
|
setSamplerate_bandpass (txa[channel].bp2.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].compmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_wcpagc (txa[channel].alc.p, ch[channel].dsp_rate);
|
|
setSamplerate_ammod (txa[channel].ammod.p, ch[channel].dsp_rate);
|
|
setSamplerate_fmmod (txa[channel].fmmod.p, ch[channel].dsp_rate);
|
|
setSamplerate_gen (txa[channel].gen1.p, ch[channel].dsp_rate);
|
|
setSamplerate_uslew (txa[channel].uslew.p, ch[channel].dsp_rate);
|
|
setSamplerate_meter (txa[channel].alcmeter.p, ch[channel].dsp_rate);
|
|
setSamplerate_siphon (txa[channel].sip1.p, ch[channel].dsp_rate);
|
|
setSamplerate_iqc (txa[channel].iqc.p0, ch[channel].dsp_rate);
|
|
setSamplerate_cfir (txa[channel].cfir.p, ch[channel].dsp_rate);
|
|
// output resampler
|
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
|
setInRate_resample (txa[channel].rsmpout.p, ch[channel].dsp_rate);
|
|
TXAResCheck (channel);
|
|
// output meter
|
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
|
}
|
|
|
|
void setDSPBuffsize_txa (int channel)
|
|
{
|
|
// buffers
|
|
_aligned_free (txa[channel].inbuff);
|
|
txa[channel].inbuff = (double *)malloc0(1 * ch[channel].dsp_insize * sizeof(complex));
|
|
_aligned_free (txa[channel].midbuff);
|
|
txa[channel].midbuff = (double *)malloc0(2 * ch[channel].dsp_size * sizeof(complex));
|
|
_aligned_free (txa[channel].outbuff);
|
|
txa[channel].outbuff = (double *)malloc0(1 * ch[channel].dsp_outsize * sizeof(complex));
|
|
// input resampler
|
|
setBuffers_resample (txa[channel].rsmpin.p, txa[channel].inbuff, txa[channel].midbuff);
|
|
setSize_resample (txa[channel].rsmpin.p, ch[channel].dsp_insize);
|
|
// dsp_size blocks
|
|
setBuffers_gen (txa[channel].gen0.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_gen (txa[channel].gen0.p, ch[channel].dsp_size);
|
|
setBuffers_panel (txa[channel].panel.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_panel (txa[channel].panel.p, ch[channel].dsp_size);
|
|
setBuffers_phrot (txa[channel].phrot.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_phrot (txa[channel].phrot.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].micmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].micmeter.p, ch[channel].dsp_size);
|
|
setBuffers_amsq (txa[channel].amsq.p, txa[channel].midbuff, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_amsq (txa[channel].amsq.p, ch[channel].dsp_size);
|
|
setBuffers_eqp (txa[channel].eqp.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_eqp (txa[channel].eqp.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].eqmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].eqmeter.p, ch[channel].dsp_size);
|
|
setBuffers_emphp (txa[channel].preemph.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_emphp (txa[channel].preemph.p, ch[channel].dsp_size);
|
|
setBuffers_wcpagc (txa[channel].leveler.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_wcpagc (txa[channel].leveler.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].lvlrmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].lvlrmeter.p, ch[channel].dsp_size);
|
|
setBuffers_cfcomp (txa[channel].cfcomp.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_cfcomp (txa[channel].cfcomp.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].cfcmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].cfcmeter.p, ch[channel].dsp_size);
|
|
setBuffers_bandpass (txa[channel].bp0.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_bandpass (txa[channel].bp0.p, ch[channel].dsp_size);
|
|
setBuffers_compressor (txa[channel].compressor.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_compressor (txa[channel].compressor.p, ch[channel].dsp_size);
|
|
setBuffers_bandpass (txa[channel].bp1.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_bandpass (txa[channel].bp1.p, ch[channel].dsp_size);
|
|
setBuffers_osctrl (txa[channel].osctrl.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_osctrl (txa[channel].osctrl.p, ch[channel].dsp_size);
|
|
setBuffers_bandpass (txa[channel].bp2.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_bandpass (txa[channel].bp2.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].compmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].compmeter.p, ch[channel].dsp_size);
|
|
setBuffers_wcpagc (txa[channel].alc.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_wcpagc (txa[channel].alc.p, ch[channel].dsp_size);
|
|
setBuffers_ammod (txa[channel].ammod.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_ammod (txa[channel].ammod.p, ch[channel].dsp_size);
|
|
setBuffers_fmmod (txa[channel].fmmod.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_fmmod (txa[channel].fmmod.p, ch[channel].dsp_size);
|
|
setBuffers_gen (txa[channel].gen1.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_gen (txa[channel].gen1.p, ch[channel].dsp_size);
|
|
setBuffers_uslew (txa[channel].uslew.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_uslew (txa[channel].uslew.p, ch[channel].dsp_size);
|
|
setBuffers_meter (txa[channel].alcmeter.p, txa[channel].midbuff);
|
|
setSize_meter (txa[channel].alcmeter.p, ch[channel].dsp_size);
|
|
setBuffers_siphon (txa[channel].sip1.p, txa[channel].midbuff);
|
|
setSize_siphon (txa[channel].sip1.p, ch[channel].dsp_size);
|
|
setBuffers_iqc (txa[channel].iqc.p0, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_iqc (txa[channel].iqc.p0, ch[channel].dsp_size);
|
|
setBuffers_cfir (txa[channel].cfir.p, txa[channel].midbuff, txa[channel].midbuff);
|
|
setSize_cfir (txa[channel].cfir.p, ch[channel].dsp_size);
|
|
// output resampler
|
|
setBuffers_resample (txa[channel].rsmpout.p, txa[channel].midbuff, txa[channel].outbuff);
|
|
setSize_resample (txa[channel].rsmpout.p, ch[channel].dsp_size);
|
|
// output meter
|
|
setBuffers_meter (txa[channel].outmeter.p, txa[channel].outbuff);
|
|
setSize_meter (txa[channel].outmeter.p, ch[channel].dsp_outsize);
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* TXA Properties *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
PORT
|
|
void SetTXAMode (int channel, int mode)
|
|
{
|
|
if (txa[channel].mode != mode)
|
|
{
|
|
EnterCriticalSection (&ch[channel].csDSP);
|
|
txa[channel].mode = mode;
|
|
txa[channel].ammod.p->run = 0;
|
|
txa[channel].fmmod.p->run = 0;
|
|
txa[channel].preemph.p->run = 0;
|
|
switch (mode)
|
|
{
|
|
case TXA_AM:
|
|
case TXA_SAM:
|
|
txa[channel].ammod.p->run = 1;
|
|
txa[channel].ammod.p->mode = 0;
|
|
break;
|
|
case TXA_DSB:
|
|
txa[channel].ammod.p->run = 1;
|
|
txa[channel].ammod.p->mode = 1;
|
|
break;
|
|
case TXA_AM_LSB:
|
|
case TXA_AM_USB:
|
|
txa[channel].ammod.p->run = 1;
|
|
txa[channel].ammod.p->mode = 2;
|
|
break;
|
|
case TXA_FM:
|
|
txa[channel].fmmod.p->run = 1;
|
|
txa[channel].preemph.p->run = 1;
|
|
break;
|
|
default:
|
|
|
|
break;
|
|
}
|
|
TXASetupBPFilters (channel);
|
|
LeaveCriticalSection (&ch[channel].csDSP);
|
|
}
|
|
}
|
|
|
|
PORT
|
|
void SetTXABandpassFreqs (int channel, double f_low, double f_high)
|
|
{
|
|
if ((txa[channel].f_low != f_low) || (txa[channel].f_high != f_high))
|
|
{
|
|
txa[channel].f_low = f_low;
|
|
txa[channel].f_high = f_high;
|
|
TXASetupBPFilters (channel);
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* TXA Internal Functions *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
void TXAResCheck (int channel)
|
|
{
|
|
RESAMPLE a = txa[channel].rsmpin.p;
|
|
if (ch[channel].in_rate != ch[channel].dsp_rate) a->run = 1;
|
|
else a->run = 0;
|
|
a = txa[channel].rsmpout.p;
|
|
if (ch[channel].dsp_rate != ch[channel].out_rate) a->run = 1;
|
|
else a->run = 0;
|
|
}
|
|
|
|
int TXAUslewCheck (int channel)
|
|
{
|
|
return (txa[channel].ammod.p->run == 1) ||
|
|
(txa[channel].fmmod.p->run == 1) ||
|
|
(txa[channel].gen0.p->run == 1) ||
|
|
(txa[channel].gen1.p->run == 1);
|
|
}
|
|
|
|
void TXASetupBPFilters (int channel)
|
|
{
|
|
txa[channel].bp0.p->run = 1;
|
|
txa[channel].bp1.p->run = 0;
|
|
txa[channel].bp2.p->run = 0;
|
|
switch (txa[channel].mode)
|
|
{
|
|
case TXA_LSB:
|
|
case TXA_USB:
|
|
case TXA_CWL:
|
|
case TXA_CWU:
|
|
case TXA_DIGL:
|
|
case TXA_DIGU:
|
|
case TXA_SPEC:
|
|
case TXA_DRM:
|
|
CalcBandpassFilter (txa[channel].bp0.p, txa[channel].f_low, txa[channel].f_high, 2.0);
|
|
if (txa[channel].compressor.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp1.p, txa[channel].f_low, txa[channel].f_high, 2.0);
|
|
txa[channel].bp1.p->run = 1;
|
|
if (txa[channel].osctrl.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp2.p, txa[channel].f_low, txa[channel].f_high, 1.0);
|
|
txa[channel].bp2.p->run = 1;
|
|
}
|
|
}
|
|
break;
|
|
case TXA_DSB:
|
|
case TXA_AM:
|
|
case TXA_SAM:
|
|
case TXA_FM:
|
|
if (txa[channel].compressor.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
|
CalcBandpassFilter (txa[channel].bp1.p, 0.0, txa[channel].f_high, 2.0);
|
|
txa[channel].bp1.p->run = 1;
|
|
if (txa[channel].osctrl.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp2.p, 0.0, txa[channel].f_high, 1.0);
|
|
txa[channel].bp2.p->run = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp0.p, txa[channel].f_low, txa[channel].f_high, 1.0);
|
|
}
|
|
break;
|
|
case TXA_AM_LSB:
|
|
CalcBandpassFilter (txa[channel].bp0.p, -txa[channel].f_high, 0.0, 2.0);
|
|
if (txa[channel].compressor.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp1.p, -txa[channel].f_high, 0.0, 2.0);
|
|
txa[channel].bp1.p->run = 1;
|
|
if (txa[channel].osctrl.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp2.p, -txa[channel].f_high, 0.0, 1.0);
|
|
txa[channel].bp2.p->run = 1;
|
|
}
|
|
}
|
|
break;
|
|
case TXA_AM_USB:
|
|
CalcBandpassFilter (txa[channel].bp0.p, 0.0, txa[channel].f_high, 2.0);
|
|
if (txa[channel].compressor.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp1.p, 0.0, txa[channel].f_high, 2.0);
|
|
txa[channel].bp1.p->run = 1;
|
|
if (txa[channel].osctrl.p->run)
|
|
{
|
|
CalcBandpassFilter (txa[channel].bp2.p, 0.0, txa[channel].f_high, 1.0);
|
|
txa[channel].bp2.p->run = 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/********************************************************************************************************
|
|
* *
|
|
* Collectives *
|
|
* *
|
|
********************************************************************************************************/
|
|
|
|
PORT
|
|
void TXASetNC (int channel, int nc)
|
|
{
|
|
int oldstate = SetChannelState (channel, 0, 1);
|
|
SetTXABandpassNC (channel, nc);
|
|
SetTXAFMEmphNC (channel, nc);
|
|
SetTXAEQNC (channel, nc);
|
|
SetTXAFMNC (channel, nc);
|
|
SetTXACFIRNC (channel, nc);
|
|
SetChannelState (channel, oldstate, 0);
|
|
}
|
|
|
|
PORT
|
|
void TXASetMP (int channel, int mp)
|
|
{
|
|
SetTXABandpassMP (channel, mp);
|
|
SetTXAFMEmphMP (channel, mp);
|
|
SetTXAEQMP (channel, mp);
|
|
SetTXAFMMP (channel, mp);
|
|
}
|
|
|
|
PORT
|
|
void SetTXAFMAFFilter (int channel, double low, double high)
|
|
{
|
|
SetTXAFMPreEmphFreqs (channel, low, high);
|
|
SetTXAFMAFFreqs (channel, low, high);
|
|
}
|