/*************************************************************************** * * 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; inum; i++) { if (cfg->param[i].fcparam[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; inum; i++) { if (cfg->param[i].fcparam[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; }