mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	
		
			
	
	
		
			861 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			861 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*  eq.c
 | ||
|  | 
 | ||
|  | This file is part of a program that implements a Software-Defined Radio. | ||
|  | 
 | ||
|  | Copyright (C) 2013, 2016, 2017 Warren Pratt, NR0V | ||
|  | Copyright (C) 2024 Edouard Griffiths, F4EXB Adapted to SDRangel | ||
|  | 
 | ||
|  | 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.hpp"
 | ||
|  | #include "eq.hpp"
 | ||
|  | #include "firmin.hpp"
 | ||
|  | #include "fir.hpp"
 | ||
|  | #include "RXA.hpp"
 | ||
|  | #include "TXA.hpp"
 | ||
|  | 
 | ||
|  | namespace WDSP { | ||
|  | 
 | ||
|  | int EQP::fEQcompare (const void * a, const void * b) | ||
|  | { | ||
|  |     if (*(double*)a < *(double*)b) | ||
|  |         return -1; | ||
|  |     else if (*(double*)a == *(double*)b) | ||
|  |         return 0; | ||
|  |     else | ||
|  |         return 1; | ||
|  | } | ||
|  | 
 | ||
|  | double* EQP::eq_impulse (int N, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype) | ||
|  | { | ||
|  |     double* fp = new double[nfreqs + 2]; // (double *) malloc0 ((nfreqs + 2)   * sizeof (double));
 | ||
|  |     double* gp = new double[nfreqs + 2]; // (double *) malloc0 ((nfreqs + 2)   * sizeof (double));
 | ||
|  |     double* A  = new double[N / 2 + 1]; // (double *) malloc0 ((N / 2 + 1) * sizeof (double));
 | ||
|  |     double* sary = new double[2 * nfreqs]; // (double *) malloc0 (2 * nfreqs * sizeof (double));
 | ||
|  |     double gpreamp, f, frac; | ||
|  |     double* impulse; | ||
|  |     int i, j, mid; | ||
|  |     fp[0] = 0.0; | ||
|  |     fp[nfreqs + 1] = 1.0; | ||
|  |     gpreamp = G[0]; | ||
|  |     for (i = 1; i <= nfreqs; i++) | ||
|  |     { | ||
|  |         fp[i] = 2.0 * F[i] / samplerate; | ||
|  |         if (fp[i] < 0.0) fp[i] = 0.0; | ||
|  |         if (fp[i] > 1.0) fp[i] = 1.0; | ||
|  |         gp[i] = G[i]; | ||
|  |     } | ||
|  |     for (i = 1, j = 0; i <= nfreqs; i++, j+=2) | ||
|  |     { | ||
|  |         sary[j + 0] = fp[i]; | ||
|  |         sary[j + 1] = gp[i]; | ||
|  |     } | ||
|  |     qsort (sary, nfreqs, 2 * sizeof (double), fEQcompare); | ||
|  |     for (i = 1, j = 0; i <= nfreqs; i++, j+=2) | ||
|  |     { | ||
|  |         fp[i] = sary[j + 0]; | ||
|  |         gp[i] = sary[j + 1]; | ||
|  |     } | ||
|  |     gp[0] = gp[1]; | ||
|  |     gp[nfreqs + 1] = gp[nfreqs]; | ||
|  |     mid = N / 2; | ||
|  |     j = 0; | ||
|  |     if (N & 1) | ||
|  |     { | ||
|  |         for (i = 0; i <= mid; i++) | ||
|  |         { | ||
|  |             f = (double)i / (double)mid; | ||
|  |             while (f > fp[j + 1]) j++; | ||
|  |             frac = (f - fp[j]) / (fp[j + 1] - fp[j]); | ||
|  |             A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale; | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         for (i = 0; i < mid; i++) | ||
|  |         { | ||
|  |             f = ((double)i + 0.5) / (double)mid; | ||
|  |             while (f > fp[j + 1]) j++; | ||
|  |             frac = (f - fp[j]) / (fp[j + 1] - fp[j]); | ||
|  |             A[i] = pow (10.0, 0.05 * (frac * gp[j + 1] + (1.0 - frac) * gp[j] + gpreamp)) * scale; | ||
|  |         } | ||
|  |     } | ||
|  |     if (ctfmode == 0) | ||
|  |     { | ||
|  |         int k, low, high; | ||
|  |         double lowmag, highmag, flow4, fhigh4; | ||
|  |         if (N & 1) | ||
|  |         { | ||
|  |             low = (int)(fp[1] * mid); | ||
|  |             high = (int)(fp[nfreqs] * mid + 0.5); | ||
|  |             lowmag = A[low]; | ||
|  |             highmag = A[high]; | ||
|  |             flow4 = pow((double)low / (double)mid, 4.0); | ||
|  |             fhigh4 = pow((double)high / (double)mid, 4.0); | ||
|  |             k = low; | ||
|  |             while (--k >= 0) | ||
|  |             { | ||
|  |                 f = (double)k / (double)mid; | ||
|  |                 lowmag *= (f * f * f * f) / flow4; | ||
|  |                 if (lowmag < 1.0e-100) lowmag = 1.0e-100; | ||
|  |                 A[k] = lowmag; | ||
|  |             } | ||
|  |             k = high; | ||
|  |             while (++k <= mid) | ||
|  |             { | ||
|  |                 f = (double)k / (double)mid; | ||
|  |                 highmag *= fhigh4 / (f * f * f * f); | ||
|  |                 if (highmag < 1.0e-100) highmag = 1.0e-100; | ||
|  |                 A[k] = highmag; | ||
|  |             } | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             low = (int)(fp[1] * mid - 0.5); | ||
|  |             high = (int)(fp[nfreqs] * mid - 0.5); | ||
|  |             lowmag = A[low]; | ||
|  |             highmag = A[high]; | ||
|  |             flow4 = pow((double)low / (double)mid, 4.0); | ||
|  |             fhigh4 = pow((double)high / (double)mid, 4.0); | ||
|  |             k = low; | ||
|  |             while (--k >= 0) | ||
|  |             { | ||
|  |                 f = (double)k / (double)mid; | ||
|  |                 lowmag *= (f * f * f * f) / flow4; | ||
|  |                 if (lowmag < 1.0e-100) lowmag = 1.0e-100; | ||
|  |                 A[k] = lowmag; | ||
|  |             } | ||
|  |             k = high; | ||
|  |             while (++k < mid) | ||
|  |             { | ||
|  |                 f = (double)k / (double)mid; | ||
|  |                 highmag *= fhigh4 / (f * f * f * f); | ||
|  |                 if (highmag < 1.0e-100) highmag = 1.0e-100; | ||
|  |                 A[k] = highmag; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     if (N & 1) | ||
|  |         impulse = FIR::fir_fsamp_odd(N, A, 1, 1.0, wintype); | ||
|  |     else | ||
|  |         impulse = FIR::fir_fsamp(N, A, 1, 1.0, wintype); | ||
|  |     // print_impulse("eq.txt", N, impulse, 1, 0);
 | ||
|  |     delete[] (sary); | ||
|  |     delete[] (A); | ||
|  |     delete[] (gp); | ||
|  |     delete[] (fp); | ||
|  |     return impulse; | ||
|  | } | ||
|  | 
 | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                                   Partitioned Overlap-Save Equalizer                                  * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | 
 | ||
|  | EQP* EQP::create_eqp ( | ||
|  |     int run, | ||
|  |     int size, | ||
|  |     int nc, | ||
|  |     int mp, | ||
|  |     double *in, | ||
|  |     double *out, | ||
|  |     int nfreqs, | ||
|  |     double* F, | ||
|  |     double* G, | ||
|  |     int ctfmode, | ||
|  |     int wintype, | ||
|  |     int samplerate | ||
|  | ) | ||
|  | { | ||
|  |     // NOTE:  'nc' must be >= 'size'
 | ||
|  |     EQP *a = new EQP; | ||
|  |     double* impulse; | ||
|  |     a->run = run; | ||
|  |     a->size = size; | ||
|  |     a->nc = nc; | ||
|  |     a->mp = mp; | ||
|  |     a->in = in; | ||
|  |     a->out = out; | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     a->ctfmode = ctfmode; | ||
|  |     a->wintype = wintype; | ||
|  |     a->samplerate = (double)samplerate; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     a->p = FIRCORE::create_fircore (a->size, a->in, a->out, a->nc, a->mp, impulse); | ||
|  |     delete[] (impulse); | ||
|  |     return a; | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::destroy_eqp (EQP *a) | ||
|  | { | ||
|  |     FIRCORE::destroy_fircore (a->p); | ||
|  |     delete (a); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::flush_eqp (EQP *a) | ||
|  | { | ||
|  |     FIRCORE::flush_fircore (a->p); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::xeqp (EQP *a) | ||
|  | { | ||
|  |     if (a->run) | ||
|  |         FIRCORE::xfircore (a->p); | ||
|  |     else | ||
|  |         memcpy (a->out, a->in, a->size * sizeof (dcomplex)); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::setBuffers_eqp (EQP *a, double* in, double* out) | ||
|  | { | ||
|  |     a->in = in; | ||
|  |     a->out = out; | ||
|  |     FIRCORE::setBuffers_fircore (a->p, a->in, a->out); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::setSamplerate_eqp (EQP *a, int rate) | ||
|  | { | ||
|  |     double* impulse; | ||
|  |     a->samplerate = rate; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::setSize_eqp (EQP *a, int size) | ||
|  | { | ||
|  |     double* impulse; | ||
|  |     a->size = size; | ||
|  |     FIRCORE::setSize_fircore (a->p, a->size); | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                           Partitioned Overlap-Save Equalizer:  RXA Properties                         * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | 
 | ||
|  | void EQP::SetEQRun (RXA& rxa, int run) | ||
|  | { | ||
|  |     rxa.csDSP.lock(); | ||
|  |     rxa.eqp.p->run = run; | ||
|  |     rxa.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQNC (RXA& rxa, int nc) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     rxa.csDSP.lock(); | ||
|  |     a = rxa.eqp.p; | ||
|  |     if (a->nc != nc) | ||
|  |     { | ||
|  |         a->nc = nc; | ||
|  |         impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |         FIRCORE::setNc_fircore (a->p, a->nc, impulse); | ||
|  |         delete[] (impulse); | ||
|  |     } | ||
|  |     rxa.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQMP (RXA& rxa, int mp) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     a = rxa.eqp.p; | ||
|  |     if (a->mp != mp) | ||
|  |     { | ||
|  |         a->mp = mp; | ||
|  |         FIRCORE::setMp_fircore (a->p, a->mp); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQProfile (RXA& rxa, int nfreqs, double* F, double* G) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = rxa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, | ||
|  |         a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQCtfmode (RXA& rxa, int mode) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = rxa.eqp.p; | ||
|  |     a->ctfmode = mode; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQWintype (RXA& rxa, int wintype) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = rxa.eqp.p; | ||
|  |     a->wintype = wintype; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetGrphEQ (RXA& rxa, int *rxeq) | ||
|  | {   // three band equalizer (legacy compatibility)
 | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = rxa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 4; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->F[1] =  150.0; | ||
|  |     a->F[2] =  400.0; | ||
|  |     a->F[3] = 1500.0; | ||
|  |     a->F[4] = 6000.0; | ||
|  |     a->G[0] = (double)rxeq[0]; | ||
|  |     a->G[1] = (double)rxeq[1]; | ||
|  |     a->G[2] = (double)rxeq[1]; | ||
|  |     a->G[3] = (double)rxeq[2]; | ||
|  |     a->G[4] = (double)rxeq[3]; | ||
|  |     a->ctfmode = 0; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetGrphEQ10 (RXA& rxa, int *rxeq) | ||
|  | {   // ten band equalizer (legacy compatibility)
 | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     int i; | ||
|  |     a = rxa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 10; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->F[1]  =    32.0; | ||
|  |     a->F[2]  =    63.0; | ||
|  |     a->F[3]  =   125.0; | ||
|  |     a->F[4]  =   250.0; | ||
|  |     a->F[5]  =   500.0; | ||
|  |     a->F[6]  =  1000.0; | ||
|  |     a->F[7]  =  2000.0; | ||
|  |     a->F[8]  =  4000.0; | ||
|  |     a->F[9]  =  8000.0; | ||
|  |     a->F[10] = 16000.0; | ||
|  |     for (i = 0; i <= a->nfreqs; i++) | ||
|  |         a->G[i] = (double)rxeq[i]; | ||
|  |     a->ctfmode = 0; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     // print_impulse ("rxeq.txt", a->nc, impulse, 1, 0);
 | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                           Partitioned Overlap-Save Equalizer:  TXA Properties                         * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | 
 | ||
|  | void EQP::SetEQRun (TXA& txa, int run) | ||
|  | { | ||
|  |     txa.csDSP.lock(); | ||
|  |     txa.eqp.p->run = run; | ||
|  |     txa.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQNC (TXA& txa, int nc) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     txa.csDSP.lock(); | ||
|  |     a = txa.eqp.p; | ||
|  |     if (a->nc != nc) | ||
|  |     { | ||
|  |         a->nc = nc; | ||
|  |         impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |         FIRCORE::setNc_fircore (a->p, a->nc, impulse); | ||
|  |         delete[] (impulse); | ||
|  |     } | ||
|  |     txa.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQMP (TXA& txa, int mp) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     a = txa.eqp.p; | ||
|  |     if (a->mp != mp) | ||
|  |     { | ||
|  |         a->mp = mp; | ||
|  |         FIRCORE::setMp_fircore (a->p, a->mp); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQProfile (TXA& txa, int nfreqs, double* F, double* G) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = txa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQCtfmode (TXA& txa, int mode) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = txa.eqp.p; | ||
|  |     a->ctfmode = mode; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetEQWintype (TXA& txa, int wintype) | ||
|  | { | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = txa.eqp.p; | ||
|  |     a->wintype = wintype; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetGrphEQ (TXA& txa, int *txeq) | ||
|  | {   // three band equalizer (legacy compatibility)
 | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     a = txa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 4; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->F[1] =  150.0; | ||
|  |     a->F[2] =  400.0; | ||
|  |     a->F[3] = 1500.0; | ||
|  |     a->F[4] = 6000.0; | ||
|  |     a->G[0] = (double)txeq[0]; | ||
|  |     a->G[1] = (double)txeq[1]; | ||
|  |     a->G[2] = (double)txeq[1]; | ||
|  |     a->G[3] = (double)txeq[2]; | ||
|  |     a->G[4] = (double)txeq[3]; | ||
|  |     a->ctfmode = 0; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | void EQP::SetGrphEQ10 (TXA& txa, int *txeq) | ||
|  | {   // ten band equalizer (legacy compatibility)
 | ||
|  |     EQP *a; | ||
|  |     double* impulse; | ||
|  |     int i; | ||
|  |     a = txa.eqp.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 10; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->F[1]  =    32.0; | ||
|  |     a->F[2]  =    63.0; | ||
|  |     a->F[3]  =   125.0; | ||
|  |     a->F[4]  =   250.0; | ||
|  |     a->F[5]  =   500.0; | ||
|  |     a->F[6]  =  1000.0; | ||
|  |     a->F[7]  =  2000.0; | ||
|  |     a->F[8]  =  4000.0; | ||
|  |     a->F[9]  =  8000.0; | ||
|  |     a->F[10] = 16000.0; | ||
|  |     for (i = 0; i <= a->nfreqs; i++) | ||
|  |         a->G[i] = (double)txeq[i]; | ||
|  |     a->ctfmode = 0; | ||
|  |     impulse = eq_impulse (a->nc, a->nfreqs, a->F, a->G, a->samplerate, 1.0 / (2.0 * a->size), a->ctfmode, a->wintype); | ||
|  |     FIRCORE::setImpulse_fircore (a->p, impulse, 1); | ||
|  |     delete[] (impulse); | ||
|  | } | ||
|  | 
 | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                                           Overlap-Save Equalizer                                      * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | 
 | ||
|  | 
 | ||
|  | double* EQP::eq_mults (int size, int nfreqs, double* F, double* G, double samplerate, double scale, int ctfmode, int wintype) | ||
|  | { | ||
|  |     double* impulse = eq_impulse (size + 1, nfreqs, F, G, samplerate, scale, ctfmode, wintype); | ||
|  |     double* mults = FIR::fftcv_mults(2 * size, impulse); | ||
|  |     delete[] (impulse); | ||
|  |     return mults; | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::calc_eq (EQ *a) | ||
|  | { | ||
|  |     a->scale = 1.0 / (double)(2 * a->size); | ||
|  |     a->infilt = new double[2 * a->size * 2]; // (double *)malloc0(2 * a->size * sizeof(complex));
 | ||
|  |     a->product = new double[2 * a->size * 2]; // (double *)malloc0(2 * a->size * sizeof(complex));
 | ||
|  |     a->CFor = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->infilt, (fftw_complex *)a->product, FFTW_FORWARD, FFTW_PATIENT); | ||
|  |     a->CRev = fftw_plan_dft_1d(2 * a->size, (fftw_complex *)a->product, (fftw_complex *)a->out, FFTW_BACKWARD, FFTW_PATIENT); | ||
|  |     a->mults = EQP::eq_mults(a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::decalc_eq (EQ *a) | ||
|  | { | ||
|  |     fftw_destroy_plan(a->CRev); | ||
|  |     fftw_destroy_plan(a->CFor); | ||
|  |     delete[] (a->mults); | ||
|  |     delete[] (a->product); | ||
|  |     delete[] (a->infilt); | ||
|  | } | ||
|  | 
 | ||
|  | EQ* EQ::create_eq (int run, int size, double *in, double *out, int nfreqs, double* F, double* G, int ctfmode, int wintype, int samplerate) | ||
|  | { | ||
|  |     EQ *a = new EQ; | ||
|  |     a->run = run; | ||
|  |     a->size = size; | ||
|  |     a->in = in; | ||
|  |     a->out = out; | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     a->G = new double[a->nfreqs + 1]; // (double *) malloc0 ((a->nfreqs + 1) * sizeof (double));
 | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     a->ctfmode = ctfmode; | ||
|  |     a->wintype = wintype; | ||
|  |     a->samplerate = (double)samplerate; | ||
|  |     calc_eq (a); | ||
|  |     return a; | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::destroy_eq (EQ *a) | ||
|  | { | ||
|  |     decalc_eq (a); | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     delete[] (a); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::flush_eq (EQ *a) | ||
|  | { | ||
|  |     memset (a->infilt, 0, 2 * a->size * sizeof (dcomplex)); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::xeq (EQ *a) | ||
|  | { | ||
|  |     int i; | ||
|  |     double I, Q; | ||
|  |     if (a->run) | ||
|  |     { | ||
|  |         memcpy (&(a->infilt[2 * a->size]), a->in, a->size * sizeof (dcomplex)); | ||
|  |         fftw_execute (a->CFor); | ||
|  |         for (i = 0; i < 2 * a->size; i++) | ||
|  |         { | ||
|  |             I = a->product[2 * i + 0]; | ||
|  |             Q = a->product[2 * i + 1]; | ||
|  |             a->product[2 * i + 0] = I * a->mults[2 * i + 0] - Q * a->mults[2 * i + 1]; | ||
|  |             a->product[2 * i + 1] = I * a->mults[2 * i + 1] + Q * a->mults[2 * i + 0]; | ||
|  |         } | ||
|  |         fftw_execute (a->CRev); | ||
|  |         memcpy (a->infilt, &(a->infilt[2 * a->size]), a->size * sizeof(dcomplex)); | ||
|  |     } | ||
|  |     else if (a->in != a->out) | ||
|  |         memcpy (a->out, a->in, a->size * sizeof (dcomplex)); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::setBuffers_eq (EQ *a, double* in, double* out) | ||
|  | { | ||
|  |     decalc_eq (a); | ||
|  |     a->in = in; | ||
|  |     a->out = out; | ||
|  |     calc_eq (a); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::setSamplerate_eq (EQ *a, int rate) | ||
|  | { | ||
|  |     decalc_eq (a); | ||
|  |     a->samplerate = rate; | ||
|  |     calc_eq (a); | ||
|  | } | ||
|  | 
 | ||
|  | void EQ::setSize_eq (EQ *a, int size) | ||
|  | { | ||
|  |     decalc_eq (a); | ||
|  |     a->size = size; | ||
|  |     calc_eq (a); | ||
|  | } | ||
|  | 
 | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                               Overlap-Save Equalizer:  RXA Properties                                 * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | /*  // UNCOMMENT properties when a pointer is in place in rxa
 | ||
|  | PORT | ||
|  | void SetRXAEQRun (int channel, int run) | ||
|  | { | ||
|  |     ch.csDSP.lock(); | ||
|  |     rxa.eq.p->run = run; | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetRXAEQProfile (int channel, int nfreqs, double* F, double* G) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = rxa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetRXAEQCtfmode (int channel, int mode) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = rxa.eq.p; | ||
|  |     a->ctfmode = mode; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetRXAEQWintype (int channel, int wintype) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = rxa.eq.p; | ||
|  |     a->wintype = wintype; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetRXAGrphEQ (int channel, int *rxeq) | ||
|  | {   // three band equalizer (legacy compatibility)
 | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = rxa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 4; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->F[1] =  150.0; | ||
|  |     a->F[2] =  400.0; | ||
|  |     a->F[3] = 1500.0; | ||
|  |     a->F[4] = 6000.0; | ||
|  |     a->G[0] = (double)rxeq[0]; | ||
|  |     a->G[1] = (double)rxeq[1]; | ||
|  |     a->G[2] = (double)rxeq[1]; | ||
|  |     a->G[3] = (double)rxeq[2]; | ||
|  |     a->G[4] = (double)rxeq[3]; | ||
|  |     a->ctfmode = 0; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetRXAGrphEQ10 (int channel, int *rxeq) | ||
|  | {   // ten band equalizer (legacy compatibility)
 | ||
|  |     EQ a; | ||
|  |     int i; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = rxa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 10; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->F[1]  =    32.0; | ||
|  |     a->F[2]  =    63.0; | ||
|  |     a->F[3]  =   125.0; | ||
|  |     a->F[4]  =   250.0; | ||
|  |     a->F[5]  =   500.0; | ||
|  |     a->F[6]  =  1000.0; | ||
|  |     a->F[7]  =  2000.0; | ||
|  |     a->F[8]  =  4000.0; | ||
|  |     a->F[9]  =  8000.0; | ||
|  |     a->F[10] = 16000.0; | ||
|  |     for (i = 0; i <= a->nfreqs; i++) | ||
|  |         a->G[i] = (double)rxeq[i]; | ||
|  |     a->ctfmode = 0; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | */ | ||
|  | /********************************************************************************************************
 | ||
|  | *                                                                                                       * | ||
|  | *                               Overlap-Save Equalizer:  TXA Properties                                 * | ||
|  | *                                                                                                       * | ||
|  | ********************************************************************************************************/ | ||
|  | /*  // UNCOMMENT properties when a pointer is in place in rxa
 | ||
|  | PORT | ||
|  | void SetTXAEQRun (int channel, int run) | ||
|  | { | ||
|  |     ch.csDSP.lock(); | ||
|  |     txa.eq.p->run = run; | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetTXAEQProfile (int channel, int nfreqs, double* F, double* G) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = txa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = nfreqs; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->F, F, (nfreqs + 1) * sizeof (double)); | ||
|  |     memcpy (a->G, G, (nfreqs + 1) * sizeof (double)); | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetTXAEQCtfmode (int channel, int mode) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = txa.eq.p; | ||
|  |     a->ctfmode = mode; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetTXAEQMethod (int channel, int wintype) | ||
|  | { | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = txa.eq.p; | ||
|  |     a->wintype = wintype; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetTXAGrphEQ (int channel, int *txeq) | ||
|  | {   // three band equalizer (legacy compatibility)
 | ||
|  |     EQ a; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = txa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 4; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->F[1] =  150.0; | ||
|  |     a->F[2] =  400.0; | ||
|  |     a->F[3] = 1500.0; | ||
|  |     a->F[4] = 6000.0; | ||
|  |     a->G[0] = (double)txeq[0]; | ||
|  |     a->G[1] = (double)txeq[1]; | ||
|  |     a->G[2] = (double)txeq[1]; | ||
|  |     a->G[3] = (double)txeq[2]; | ||
|  |     a->G[4] = (double)txeq[3]; | ||
|  |     a->ctfmode = 0; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | 
 | ||
|  | PORT | ||
|  | void SetTXAGrphEQ10 (int channel, int *txeq) | ||
|  | {   // ten band equalizer (legacy compatibility)
 | ||
|  |     EQ a; | ||
|  |     int i; | ||
|  |     ch.csDSP.lock(); | ||
|  |     a = txa.eq.p; | ||
|  |     delete[] (a->G); | ||
|  |     delete[] (a->F); | ||
|  |     a->nfreqs = 10; | ||
|  |     a->F = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->G = (double *) malloc0 ((a->nfreqs + 1) * sizeof (double)); | ||
|  |     a->F[1]  =    32.0; | ||
|  |     a->F[2]  =    63.0; | ||
|  |     a->F[3]  =   125.0; | ||
|  |     a->F[4]  =   250.0; | ||
|  |     a->F[5]  =   500.0; | ||
|  |     a->F[6]  =  1000.0; | ||
|  |     a->F[7]  =  2000.0; | ||
|  |     a->F[8]  =  4000.0; | ||
|  |     a->F[9]  =  8000.0; | ||
|  |     a->F[10] = 16000.0; | ||
|  |     for (i = 0; i <= a->nfreqs; i++) | ||
|  |         a->G[i] = (double)txeq[i]; | ||
|  |     a->ctfmode = 0; | ||
|  |     delete[] (a->mults); | ||
|  |     a->mults = eq_mults (a->size, a->nfreqs, a->F, a->G, a->samplerate, a->scale, a->ctfmode, a->wintype); | ||
|  |     ch.csDSP.unlock(); | ||
|  | } | ||
|  | */ | ||
|  | 
 | ||
|  | } // namespace WDSP
 |