#include <cstdlib>
|
#include <cstring>
|
#include "const.h"
|
#include "RenderAPI.h"
|
#include "FreqResponse.h"
|
#include "IIRFilter.h"
|
#include "FIRFilter.h"
|
#include "windowsfunc.h"
|
|
enum pulse_type {
|
pulse_orginal, //Ôʼµ¼ÈëµÄÂö³å
|
pulse_invert, //Ïà·´µÄÏàλÓë·ù¶È
|
pulse_eq1, //eqµ÷ÕûµÄÂö³å
|
pulse_eq2,
|
pulse_eq3,
|
pulse_eq4,
|
pulse_eq5,
|
pulse_eq6,
|
pulse_eq7,
|
pulse_eq8,
|
pulse_out, //×îÖÕÉú³ÉµÄÂö³å
|
pulse_count,
|
};
|
|
typedef struct {
|
//ÄÚ²¿ÁÙʱÊý¾Ý
|
double linear_freq[KERNEL_HALF_FFT];
|
double gain[KERNEL_HALF_FFT];
|
double phase[KERNEL_HALF_FFT];
|
pulse_t hn_list[pulse_count];
|
}FiltersRender;
|
|
void* FiltersRenderInit()
|
{
|
FiltersRender* render = new FiltersRender;
|
FreqResponse response;
|
|
memset(render, 0 , sizeof(FiltersRender));
|
|
//²úÉúÏßÐÔÆµÂÊ
|
response.linearspace(0, KERNEL_SAMPLE_RATE / 2, render->linear_freq, KERNEL_HALF_FFT);
|
|
return render;
|
}
|
|
void FilterRenderFree(void* handle)
|
{
|
FiltersRender* render = (FiltersRender*)handle;
|
if(render)
|
delete render;
|
}
|
|
static void FilterReset(pulse_t* p) {
|
memset(p, 0, sizeof(pulse_t));
|
}
|
|
int FIRDrawFreqzData(void* handle, double coeffs[], int tap, int fs
|
, double f[], double gain[], double phase[], int num)
|
{
|
FreqResponse response;
|
FiltersRender* render = (FiltersRender*)handle;
|
if (render == 0) return ret_param_error;
|
|
|
//µ¼ÈëµÄÊÇ·ù¶ÈÐÅÏ¢.
|
if (f[tap - 1] < KERNEL_SAMPLE_RATE / 2 && f[tap - 1] > 10000) {
|
response.deg2rad(phase, tap);
|
//ÏßÐÔÄÚ²å֮ǰ±ØÐë¶ÔÏàλ½â²øÈÆ
|
response.unwrap_phase(phase, tap, render->phase);
|
|
//°´ÕÕ²úÉúµÄÏßÐÔÆµÂÊ×ö³éÈ¡gainºÍpahse.
|
response.extra(f, gain, render->phase, tap, render->linear_freq
|
, render->hn_list[pulse_orginal].gain, render->hn_list[pulse_orginal].phase, KERNEL_HALF_FFT);
|
|
//ÄÚ²åºóÏàλת»»µ½-pi~piÇø¼ä
|
for (int i =0; i < KERNEL_HALF_FFT; i++) {
|
render->hn_list[pulse_orginal].phase[i] = response.wrap_phase(render->hn_list[pulse_orginal].phase[i]);
|
}
|
|
render->hn_list[pulse_orginal].enable = true;
|
FilterReset(&render->hn_list[pulse_invert]);
|
|
return num;
|
}
|
//·ñÔòµ¼ÈëµÄÊÇϵÊýÎļþ.
|
//Ìî³äƵÂÊÐÅÏ¢.
|
response.logspace(10, 20000, f, num);
|
//ϵÊýΪ¿Õ
|
//if (coeffs[0] == 0 && coeffs[1] == 0) {
|
// return ret_param_error;
|
//}
|
|
int n = response.freqz(coeffs, tap, KERNEL_SAMPLE_NUM, KERNEL_SAMPLE_RATE, render->linear_freq
|
, render->hn_list[pulse_orginal].gain, render->hn_list[pulse_orginal].phase); //n==4097
|
|
//³éÈ¡ÎÞÐè½â²øÈÆ.
|
response.extra(render->linear_freq, render->hn_list[pulse_orginal].gain, render->hn_list[pulse_orginal].phase
|
, n, f, gain, phase, num);
|
|
response.rad2deg(phase, num);
|
|
render->hn_list[pulse_orginal].enable = true;
|
FilterReset(&render->hn_list[pulse_invert]);
|
|
return ret_success;
|
}
|
|
int FIRAutoMagCalibration(void* handle, double f[], double gain[]
|
, double start_freq, double end_freq, int smooth_type, int num)
|
{
|
FreqResponse response;
|
FiltersRender* render = (FiltersRender*)handle;
|
const double oct[] = {1./3, 1./6,1./10, 0};
|
if (render == 0) return ret_param_error;
|
|
for (int i = 0; i < KERNEL_HALF_FFT; i++) {
|
if (render->linear_freq[i] >= start_freq && render->linear_freq[i] <= end_freq) {
|
render->gain[i] = -render->hn_list[pulse_orginal].gain[i];
|
}
|
else {
|
render->gain[i] = 0; //²»¸Ä±äÔöÒæ.
|
}
|
}
|
response.sw_smooth(oct[smooth_type], start_freq, end_freq, render->linear_freq
|
, render->gain, render->hn_list[pulse_invert].gain, KERNEL_HALF_FFT);
|
|
render->hn_list[pulse_invert].enable = true;
|
|
response.mulimpulse(render->hn_list, pulse_count);
|
|
//Ìî³äƵÂÊÐÅÏ¢.
|
response.logspace(10, 20000, f, num);
|
response.extra(render->linear_freq, render->hn_list[pulse_out].gain, render->hn_list[pulse_out].phase, KERNEL_HALF_FFT
|
, f, gain, NULL, num);
|
|
return 0;
|
}
|
|
int FIRAutoPhaseCalibration(void* handle, double f[], double phase[]
|
, double start_freq, double end_freq, int smooth_type, int num)
|
{
|
FreqResponse response;
|
FiltersRender* render = (FiltersRender*)handle;
|
const double oct[] = { 1. / 3, 1. / 6,1. / 10, 0 };
|
if (render == 0) return ret_param_error;
|
for (int i = 0; i < KERNEL_HALF_FFT; i++) {
|
if (render->linear_freq[i] >= start_freq && render->linear_freq[i] <= end_freq) {
|
//-pi~piÇø¼ä.
|
render->phase[i] = -render->hn_list[pulse_orginal].phase[i];
|
}
|
else {
|
render->phase[i] = 0; //²»¸Ä±äÏàλ.
|
}
|
}
|
response.sw_smooth(oct[smooth_type], start_freq, end_freq, render->linear_freq
|
, render->phase, render->hn_list[pulse_invert].phase, KERNEL_HALF_FFT);
|
render->hn_list[pulse_invert].enable = true;
|
|
response.mulimpulse(render->hn_list, pulse_count);
|
|
//Ìî³äƵÂÊÐÅÏ¢.
|
response.logspace(10, 20000, f, num);
|
response.extra(render->linear_freq, render->hn_list[pulse_out].gain, render->hn_list[pulse_out].phase, KERNEL_HALF_FFT
|
, f, NULL, phase, num);
|
|
response.rad2deg(phase ,num);
|
return 0;
|
}
|
|
int FIRAdjustFilter(void* handle, int nsection, int bypass, int filter_type
|
, int freq, double Q, double g, double f[], double gain[], double phase[], int num)
|
{
|
FreqResponse response;
|
FiltersRender* render = (FiltersRender*)handle;
|
//param check.
|
if (render == 0 || nsection > 7 || nsection < 0) return ret_param_error;
|
if (freq < 20 || freq > 20000) return ret_param_error;
|
if (Q < 0.02 || Q > 50) return ret_param_error;
|
if (g < -24 || g > 18) return ret_param_error;
|
|
double sos[6];
|
switch (filter_type) {
|
case FIRFilterType::HIGHPASS:
|
IIRFilter().eq(IIRBANDType::highpass, freq, g, Q, KERNEL_SAMPLE_RATE, &sos);
|
break;
|
case FIRFilterType::LOWPASS:
|
IIRFilter().eq(IIRBANDType::lowpass, freq, g, Q, KERNEL_SAMPLE_RATE, &sos);
|
break;
|
case FIRFilterType::EQ:
|
IIRFilter().eq(IIRBANDType::peaking_eq, freq, g, Q, KERNEL_SAMPLE_RATE, &sos);
|
break;
|
default:
|
return ret_param_error;
|
}
|
nsection += pulse_eq1;
|
response.freqz(&sos, 1, KERNEL_HALF_FFT, KERNEL_SAMPLE_RATE, render->linear_freq, render->hn_list[nsection].gain);
|
render->hn_list[nsection].enable = bypass==0?true:false;
|
|
response.mulimpulse(render->hn_list, pulse_count);
|
|
//Ìî³äƵÂÊÐÅÏ¢.
|
response.logspace(10, 20000, f, num);
|
response.extra(render->linear_freq, render->hn_list[pulse_out].gain, render->hn_list[pulse_out].phase, KERNEL_HALF_FFT
|
, f, gain, phase, num);
|
response.rad2deg(phase, num);
|
|
return 0;
|
}
|
|
int FIRGetCoeffs(void* handle, double coffefs[], int windowType, double delay_ms, int tap)
|
{
|
FiltersRender* render = (FiltersRender*)handle;
|
FreqResponse response;
|
if (render == 0 || tap > 4096) return ret_param_error;
|
|
double wn[4096];
|
switch (windowType)
|
{
|
case FIRWindowType::Blackman:
|
Windows().BlackManWin(wn, tap);
|
break;
|
case FIRWindowType::Hamming:
|
Windows().HammingWin(wn, tap);
|
break;
|
case FIRWindowType::Hanning:
|
Windows().HannWin(wn, tap);
|
break;
|
case FIRWindowType::Kaiser:
|
Windows().KaiserWin(wn, tap);
|
break;
|
case FIRWindowType::Rectangle:
|
Windows().RectangleWin(wn, tap);
|
break;
|
case FIRWindowType::Triangle:
|
Windows().TriangularWin(wn, tap);
|
break;
|
default:
|
return ret_param_error;
|
}
|
//ifft->»ùÓÚÄÜÁ¿ÖÐÐĽØÈ¡->¼Ó´°
|
response.mulimpulse(render->hn_list, pulse_count , pulse_invert);
|
response.unwrap_phase(render->hn_list[pulse_type::pulse_out].phase, KERNEL_HALF_FFT, render->phase);
|
response.impulse_response(render->linear_freq, render->hn_list[pulse_type::pulse_out].gain, render->phase, KERNEL_HALF_FFT
|
, coffefs, tap , wn, delay_ms, true);
|
|
return 0;
|
}
|
|
void FilterRenderReset(void* handle)
|
{
|
FiltersRender* render = (FiltersRender*)handle;
|
//param check.
|
if (render) {
|
memset(render->hn_list, 0, sizeof(pulse_t) * pulse_count);
|
}
|
}
|