pinebuds/services/multimedia/audio/process/filters/cfg/eq_cfg.c

422 lines
15 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "plat_types.h"
#include "tgt_hardware.h"
#include "filter_debug_trace.h"
#include "iir_process.h"
#include "eq_cfg.h"
#include "hw_codec_iir_process.h"
#include "hw_iir_process.h"
#include "math.h"
#define IIR_FIXED_Q (1<<27)
#define PI (3.14159265358979)
static HW_CODEC_IIR_CFG_T hw_codec_iir_eq;
static HW_IIR_CFG_T hw_iir_eq;
void iir_lowshelf_coefs_generate(float gain, float fn, float Q, float *coefs)
{
float A = (float)sqrtf(powf(10, gain / 20));
float w0 = 2 * PI*fn;
float alpha = (float)sinf(w0)/(2*Q);
float a0 = (A + 1) + (A - 1)*(float)cosf(w0) + 2 * (float)sqrtf(A)*alpha;
float a1 = (-2 * ((A - 1) + (A + 1)*(float)cosf(w0)));
float a2 = ((A + 1) + (A - 1)*(float)cosf(w0) - 2 * (float)sqrtf(A)*alpha);
float b0 = (A*((A + 1) - (A - 1)*(float)cosf(w0) + 2 *(float)sqrtf(A)*alpha));
float b1 = (2 * A*((A - 1) - (A + 1)*(float)cosf(w0)));
float b2 = (A*((A + 1) - (A - 1)*(float)cosf(w0) - 2 * (float)sqrtf(A)*alpha));
coefs[0] = 1;
coefs[1] = a1 / a0;
coefs[2] = a2 / a0;
coefs[3] = b0 / a0;
coefs[4] = b1 / a0;
coefs[5] = b2 / a0;
// IIR_TRACE(6,"fn = %f, gain = %f, Q = %f, A = %f, w0 = %f, alpha = %f", fn, gain, Q, A, w0, alpha);
// FILTER_DEBUG_TRACE(7,"[%s] %f, %f, %f, %f, %f, %f", __func__, (double)coefs[0], (double)coefs[1], (double)coefs[2], (double)coefs[3], (double)coefs[4], (double)coefs[5]);
}
void iir_highshelf_coefs_generate(float gain, float fn, float Q, float *coefs)
{
float A = (float)sqrtf(powf(10, gain / 20));
float w0 = 2 * PI*fn;
float alpha = (float)sinf(w0) / (2 * Q);
float a0 = (A + 1) - (A - 1)*(float)cosf(w0) + 2 * (float)sqrtf(A)*alpha; // a0
float a1 = (2 * ((A - 1) - (A + 1)*(float)cosf(w0))); // a1
float a2 = ((A + 1) - (A - 1)*(float)cosf(w0) - 2 * (float)sqrtf(A)*alpha); //a2
float b0 = (A*((A + 1) + (A - 1)*(float)cosf(w0) + 2 * (float)sqrtf(A)*alpha)); //b0
float b1 = (-2 * A*((A - 1) + (A + 1)*(float)cosf(w0))); // b1
float b2 = (A*((A + 1) + (A - 1)*(float)cosf(w0) - 2 * (float)sqrtf(A)*alpha)); // b2
coefs[0] = 1;
coefs[1] = a1 / a0;
coefs[2] = a2 / a0;
coefs[3] = b0 / a0;
coefs[4] = b1 / a0;
coefs[5] = b2 / a0;
// IIR_TRACE(6,"fn = %f, gain = %f, Q = %f, A = %f, w0 = %f, alpha = %f", fn, gain, Q, A, w0, alpha);
// FILTER_DEBUG_TRACE(7,"[%s] %f, %f, %f, %f, %f, %f", __func__, (double)coefs[0], (double)coefs[1], (double)coefs[2], (double)coefs[3], (double)coefs[4], (double)coefs[5]);
}
// fn: Normalized frequency
void iir_peak_notch_coefs_generate(float gain, float fn, float Q, float *coefs)
{
// float Fs = 1000.0 / 48000.0;
// float gain = -5.0;
// float fo = 1000.0;
// float Q = 0.7;
float A = (float)sqrtf(powf(10, gain/20));
float w0 = 2*PI*fn;
float alpha = (float)sinf(w0)/(2*Q);
float a0 = 1 + alpha/A;
float a1 = -2*(float)cosf(w0);
float a2 = 1 - alpha/A;
float b0 = 1 + alpha*A;
float b1 = -2*(float)cosf(w0);
float b2 = 1 - alpha*A;
coefs[0] = 1;
coefs[1] = a1 / a0;
coefs[2] = a2 / a0;
coefs[3] = b0 / a0;
coefs[4] = b1 / a0;
coefs[5] = b2 / a0;
// IIR_TRACE(6,"fn = %f, gain = %f, Q = %f, A = %f, w0 = %f, alpha = %f", fn, gain, Q, A, w0, alpha);
// FILTER_DEBUG_TRACE(7,"[%s] %f, %f, %f, %f, %f, %f", __func__, (double)coefs[0], (double)coefs[1], (double)coefs[2], (double)coefs[3], (double)coefs[4], (double)coefs[5]);
}
void iir_highpass_coefs_generate(float gain, float fn, float Q, float *coefs)
{
float w0 = 2 * PI*fn;
float alpha = (float)sinf(w0) / (2 * Q);
float a0 = 1 + alpha;
float a1 = -2 * (float)cosf(w0);
float a2 = 1 - alpha;
float b0 = (1 + (float)cosf(w0))/2;
float b1 = -(1 + (float)cosf(w0));
float b2 = (1 + (float)cosf(w0))/2;
coefs[0] = 1;
coefs[1] = a1/a0;
coefs[2] = a2/a0;
coefs[3] = b0/a0;
coefs[4] = b1/a0;
coefs[5] = b2/a0;
}
void iir_lowspass_coefs_generate(float gain, float fn, float Q, float *coefs)
{
float w0 = 2 * PI*fn;
float alpha = (float)sinf(w0) / (2 * Q);
float a0 = 1 + alpha;
float a1 = -2 * (float)cosf(w0);
float a2 = 1 - alpha;
float b0 = (1 - (float)cosf(w0))/2;
float b1 = 1 - (float)cosf(w0);
float b2 = (1 - (float)cosf(w0))/2;
coefs[0] = 1;
coefs[1] = a1/a0;
coefs[2] = a2/a0;
coefs[3] = b0/a0;
coefs[4] = b1/a0;
coefs[5] = b2/a0;
}
float iir_convert_db_to_multiple(float db)
{
return (float)powf(10, db/20);
}
void iir_coefs_generate(IIR_TYPE_T type, float gain, float fn, float Q, float *coefs)
{
// As it is meaningless to set an eq at or above fs/2, just skip it when we receive
// such request.
if (fn >= 0.5f)
{
coefs[0] = 1;
coefs[1] = 0;
coefs[2] = 0;
coefs[3] = 1;
coefs[4] = 0;
coefs[5] = 0;
FILTER_DEBUG_TRACE(1,"[%s] center frequency is above nyquist frequency, skip this band", __FUNCTION__);
return;
}
if (type == IIR_TYPE_LOW_SHELF)
{
iir_lowshelf_coefs_generate(gain, fn, Q, coefs);
}
else if (type == IIR_TYPE_PEAK)
{
iir_peak_notch_coefs_generate(gain, fn, Q, coefs);
}
else if (type == IIR_TYPE_HIGH_SHELF)
{
iir_highshelf_coefs_generate(gain, fn, Q, coefs);
}
else if (type == IIR_TYPE_LOW_PASS)
{
iir_lowspass_coefs_generate(gain, fn, Q, coefs);
}
else if (type == IIR_TYPE_HIGH_PASS)
{
iir_highpass_coefs_generate(gain, fn, Q, coefs);
}
else
{
ASSERT(false, "[%s] %d is not supported", __func__, type);
}
}
HW_CODEC_IIR_CFG_T *hw_codec_iir_get_cfg(enum AUD_SAMPRATE_T sample_rate, const IIR_CFG_T *ext_cfg)
{
const IIR_CFG_T *cfg;
float coefs_l[6],coefs_r[6];
float gain0,gain1;
int sample_rate_iir=sample_rate;
#if defined(CHIP_BEST2001)
#ifdef __AUDIO_RESAMPLE__
sample_rate_iir=50781.25f*8;
#else
switch(sample_rate)
{
case AUD_SAMPRATE_22050:
case AUD_SAMPRATE_44100:
case AUD_SAMPRATE_88200:
case AUD_SAMPRATE_176400:
case AUD_SAMPRATE_352800:
case AUD_SAMPRATE_705600:
sample_rate_iir=44100*8;
break;
default:
sample_rate_iir=48000*8 ;
break;
};
#endif
#endif
FILTER_DEBUG_TRACE(2,"%s,sample_rate:%d\n", __func__,sample_rate_iir);
hw_codec_iir_eq.iir_filtes_l.iir_bypass_flag=1;
hw_codec_iir_eq.iir_filtes_r.iir_bypass_flag=1;
if (ext_cfg)
{
cfg = ext_cfg;
}
else
{
FILTER_DEBUG_TRACE(0,"Error HW IIR CODEC cfg!");
return NULL;
}
// Check parameter
ASSERT(cfg->num <= AUD_DAC_IIR_NUM_EQ, "[%s] num(%d) is too large", __func__, cfg->num);
gain0 = iir_convert_db_to_multiple(cfg->gain0);
gain1 = iir_convert_db_to_multiple(cfg->gain1);
// FILTER_DEBUG_TRACE(3,"[%s] gain0 = %f, gain1 = %f", __func__, (double)gain0, (double)gain1);
FILTER_DEBUG_TRACE(2,"[%s] len = %d", __func__, cfg->num);
for(int i=0; i<cfg->num; i++)
{
if (cfg->param[i].fc<sample_rate_iir/2)
{
iir_coefs_generate(cfg->param[i].type,
cfg->param[i].gain,
cfg->param[i].fc / sample_rate_iir,
cfg->param[i].Q,
coefs_l);
}
else
{
FILTER_DEBUG_TRACE(2,"[%s]Error iir parameters i = %d", __func__, i);
coefs_l[0]=1.0f;
coefs_l[1]=0.0f;
coefs_l[2]=0.0f;
coefs_l[3]=1.0f;
coefs_l[4]=0.0f;
coefs_l[5]=0.0f;
}
coefs_r[0]=coefs_l[0];
coefs_r[1]=coefs_l[1];
coefs_r[2]=coefs_l[2];
coefs_r[3]=coefs_l[3];
coefs_r[4]=coefs_l[4];
coefs_r[5]=coefs_l[5];
if(i==0)
{
coefs_l[3] = coefs_l[3]*gain0;
coefs_l[4] = coefs_l[4]*gain0;
coefs_l[5] = coefs_l[5]*gain0;
coefs_r[3] = coefs_r[3]*gain1;
coefs_r[4] = coefs_r[4]*gain1;
coefs_r[5] = coefs_r[5]*gain1;
}
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_a[0]=(int32_t)((double)coefs_l[0]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_a[1]=(int32_t)((double)coefs_l[1]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_a[2]=(int32_t)((double)coefs_l[2]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_b[0]=(int32_t)((double)coefs_l[3]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_b[1]=(int32_t)((double)coefs_l[4]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_l.iir_coef[i].coef_b[2]=(int32_t)((double)coefs_l[5]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_a[0]=(int32_t)((double)coefs_r[0]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_a[1]=(int32_t)((double)coefs_r[1]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_a[2]=(int32_t)((double)coefs_r[2]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_b[0]=(int32_t)((double)coefs_r[3]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_b[1]=(int32_t)((double)coefs_r[4]*(int32_t)IIR_FIXED_Q);
hw_codec_iir_eq.iir_filtes_r.iir_coef[i].coef_b[2]=(int32_t)((double)coefs_r[5]*(int32_t)IIR_FIXED_Q);
}
/*
FILTER_DEBUG_TRACE(2,"\n[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_a[0]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_a[1]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_a[2]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_b[0]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_b[1]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a = %d\n", __func__, hw_codec_iir_eq.iir_filtes_l.iir_coef[0].coef_b[2]);
*/
if(cfg->num>=0)
{
hw_codec_iir_eq.iir_filtes_l.iir_bypass_flag=0;
hw_codec_iir_eq.iir_filtes_r.iir_bypass_flag=0;
hw_codec_iir_eq.iir_filtes_l.iir_counter=cfg->num;
hw_codec_iir_eq.iir_filtes_r.iir_counter=cfg->num;
}
return &hw_codec_iir_eq;
}
HW_IIR_CFG_T *hw_iir_get_cfg(enum AUD_SAMPRATE_T sample_rate, const IIR_CFG_T* ext_cfg)
{
const IIR_CFG_T *cfg;
float coefs_l[6],coefs_r[6];
float gain0,gain1;
if (ext_cfg)
{
cfg = ext_cfg;
}
else
{
FILTER_DEBUG_TRACE(0,"Error HW IIR cfg!");
return NULL;
}
FILTER_DEBUG_TRACE(3,"[%s]sample_rate:%d,iir num:%d.", __func__,sample_rate,cfg->num);
// Check parameter
ASSERT(cfg->num <= AUD_IIR_NUM_EQ, "[%s] num(%d) is too large", __func__, cfg->num);
gain0 = iir_convert_db_to_multiple(cfg->gain0);
gain1 = iir_convert_db_to_multiple(cfg->gain1);
// FILTER_DEBUG_TRACE(3,"[%s] gain0 = %f, gain1 = %f", __func__, (double)gain0, (double)gain1);
for(int i=0; i<cfg->num; i++)
{
if (cfg->param[i].fc<sample_rate/2)
{
iir_coefs_generate(cfg->param[i].type,
cfg->param[i].gain,
cfg->param[i].fc / sample_rate,
cfg->param[i].Q,
coefs_l);
}
else
{
FILTER_DEBUG_TRACE(2,"[%s]Error iir parameters i = %d", __func__, i);
coefs_l[0]=1.0f;
coefs_l[1]=0.0f;
coefs_l[2]=0.0f;
coefs_l[3]=1.0f;
coefs_l[4]=0.0f;
coefs_l[5]=0.0f;
}
coefs_r[0]=coefs_l[0];
coefs_r[1]=coefs_l[1];
coefs_r[2]=coefs_l[2];
coefs_r[3]=coefs_l[3];
coefs_r[4]=coefs_l[4];
coefs_r[5]=coefs_l[5];
if(i==0)
{
coefs_l[3] = coefs_l[3]*gain0;
coefs_l[4] = coefs_l[4]*gain0;
coefs_l[5] = coefs_l[5]*gain0;
coefs_r[3] = coefs_r[3]*gain1;
coefs_r[4] = coefs_r[4]*gain1;
coefs_r[5] = coefs_r[5]*gain1;
}
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_a[0]=(int32_t)((double)coefs_l[0]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_a[1]=(int32_t)((double)coefs_l[1]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_a[2]=(int32_t)((double)coefs_l[2]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_b[0]=(int32_t)((double)coefs_l[3]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_b[1]=(int32_t)((double)coefs_l[4]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_l.iir_coef[i].coef_b[2]=(int32_t)((double)coefs_l[5]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_a[0]=(int32_t)((double)coefs_r[0]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_a[1]=(int32_t)((double)coefs_r[1]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_a[2]=(int32_t)((double)coefs_r[2]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_b[0]=(int32_t)((double)coefs_r[3]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_b[1]=(int32_t)((double)coefs_r[4]*(int32_t)IIR_FIXED_Q);
hw_iir_eq.iir_filtes_r.iir_coef[i].coef_b[2]=(int32_t)((double)coefs_r[5]*(int32_t)IIR_FIXED_Q);
}
/*
FILTER_DEBUG_TRACE(2,"\n[%s] coef_a0 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_a[0]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a1 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_a[1]);
FILTER_DEBUG_TRACE(2,"[%s] coef_a2 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_a[2]);
FILTER_DEBUG_TRACE(2,"[%s] coef_b0 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_b[0]);
FILTER_DEBUG_TRACE(2,"[%s] coef_b1 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_b[1]);
FILTER_DEBUG_TRACE(2,"[%s] coef_b2 = %d\n", __func__, hw_iir_eq.iir_filtes_l.iir_coef[0].coef_b[2]);
*/
if(cfg->num>=0)
{
hw_iir_eq.iir_filtes_l.iir_counter=cfg->num;
hw_iir_eq.iir_filtes_r.iir_counter=cfg->num;
}
return &hw_iir_eq;
}