/* 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); }