EQ
EQ is an audio effect used to adjust the relative strength of different frequencies in an audio signal. It can control the frequency range of the audio, thereby affecting the overall sound quality and timbre. It can be used to enhance certain frequencies or attenuate unwanted frequencies, making the sound more balanced, clear, and layered. This document provides a comprehensive overview of EQ, focusing on its basic concepts, types, CFG methods, control mechanisms, and associated APIs.
The Types of EQ
As illustrated in the following figure, there are two types of EQ: SPK EQ and MIC EQ.
SPK EQ
When playing music, SPK EQ is used. It has four modes: line-in EQ, gaming EQ, ANC EQ, and normal EQ.
Line-in EQ, gaming EQ, and ANC EQ are specifically designed for line-in, gaming, and ANC scenarios respectively.
MIC EQ
The MIC EQ has only one mode: APT mode.
This APT mode means the DSP APT EQ. However, it should be noted that LLAPT does not support the EQ function.
How to Configure EQ
EQ CFG mainly includes EQ CFG in DSPConfig Tool, EQ CFG in MCUConfig Tool, and user EQ.
EQ CFG in DSPConfig Tool
The EQ CFG in DSPConfig Tool is the CFG of EQ parameters, including whether to enable EQ, modify the number of EQ groups, the stage of a certain group, the default EQ, etc. The following steps can be used as a reference.
For the SPK EQ, the first step is to enable this feature as follows:
Check ‘Effect #0’ on the Audio page to enable SPK EQ.
Click ‘Parametric EQ’ on the Audio page to open the setting page.
Next is the specific parameter setting, Audio SPK Parametric EQ Setting. It can also refer to the following figure.
Here is a description of some parameters.
Global Gain
The settings for global gain.
Application
The four options represent normal EQ, gaming EQ, ANC EQ, and line-in EQ respectively. All settings are shared between these options except the IsEnable and IsDefault fields.
StageNum
The number of stages for EQ.
Increasing the number of stages will increase the size of the DSP CFG image. Each stage contains approximately 45 bytes.
IsEnable
Specifies the EQ index available in the current EQ mode.
For gaming, ANC, and line-in EQ, there may be no active EQ index. In this case, the corresponding feature will be considered disabled.
IsDefault
Specifies which EQ index is the default value in the current EQ mode.
Freq, Gain, Q, and Type
The settings for the current EQ.
Total Response
The waveform of the current setting.
Exactly, the same logic applies to MIC EQ CFG as well. Since MIC EQ is only DSP APT EQ, it needs to enable APT first. As shown below, the way to open the setting page is:
Enter the Audio page.
Enable normal APT.
Click ‘APT Process’.
Click ‘MIC EQ Settings’.
Same as SPK EQ, the Audio MIC Parametric EQ Setting is shown below.
EQ CFG in MCUConfig Tool
The EQ CFG in MCUConfig Tool is the CFG of EQ settings, including EQ switching, EQ ringtones, etc.
If the number of EQ is greater than 1, SoC can switch EQ by MMI. As illustrated in the following figure, ‘Audio EQ Switch (0x6B)’ is used to switch SPK EQ, and ‘APT EQ Switch (0x91)’ is used to switch APT EQ.
Ringtones can be configured for different EQs, refer to the two pictures below. So when the EQ is switched by MMI or Audio Connect, SoC will play a ringtone to notify the user.
Then there is Reset EQ index when power on. This feature is shown below.
If this option is checked, SoC will reset the EQ index to default value when power on.
The feature named ‘RWS separate adjust apt eq by audio connect’ can be referred to in the following figure.
This option is applicable to RWS product.
It allows adjusting APT EQ of the left earbud and right earbud separately by Audio Connect.
The number of user EQs can also be configured, which is described in User EQ.
User EQ
User EQ refers to the EQ adjusted by Audio Connect. These EQs can be stored in SoC or phone, which is controlled by the F_APP_USER_EQ_SUPPORT
flag in the app_flags.h
file. When F_APP_USER_EQ_SUPPORT
is set to 1, these EQs can be stored in SoC. Otherwise, they are stored in the phone.
// app_flags.h
#define F_APP_USER_EQ_SUPPORT 1
As shown below, the number of user EQs can be configured by MCUConfig Tool, including SPK and MIC EQs. For example, if the number of SPK EQs is set to 10, all SPK EQs in DSPConfig Tool will be stored in the SoC. And if the number of SPK EQs is set to 6 (less than 10), the first 6 groups of SPK EQs can be saved in the SoC, while the remaining 4 groups will be stored on the phone.
These user EQs will be saved to FTL, and the location is in the EQ_EXT_FTL_PARTITION_NAME
module.
void eq_ext_ftl_storage_init(void)
{
static const T_STORAGE_PARTITION_INFO eq_partitions[] =
{
{
.name = EQ_EXT_FTL_PARTITION_NAME,
.address = NULL,
.size = NULL,
...
},
};
storage_partition_init(eq_partitions, sizeof(eq_partitions) / sizeof(eq_partitions[0]));
}
When switching EQ, SoC will give priority to the user EQ stored in FTL. Only if the user EQ is unavailable will it use the default EQ in the DSP CFG image.
static uint16_t app_eq_dsp_param_get(T_EQ_TYPE eq_type, T_EQ_STREAM_TYPE stream_type,
uint8_t eq_mode, uint8_t index, void *data, uint16_t len, T_EQ_DATA_DEST eq_data_dest,
uint32_t sample_rate)
{
uint16_t eq_len = 0;
#if F_APP_USER_EQ_SUPPORT
if ((stream_type == EQ_STREAM_TYPE_AUDIO) || ((stream_type == EQ_STREAM_TYPE_VOICE) &&
(eq_type == SPK_SW_EQ)))
{
eq_len = app_eq_load_user_eq_from_ftl(eq_type, eq_mode, index, data, len, eq_data_dest,
sample_rate); // use EQ stored in FTL first
}
if (eq_len == 0)
#endif
{
eq_len = eq_utils_param_get(eq_type, stream_type, eq_mode, index, data, len, eq_data_dest,
sample_rate); // use EQ in the DSP CFG image second
}
...
return eq_len;
}
One group of EQs has roughly the following structure, which includes:
EQ data (maximum 208 bytes): McuToSdkCmdHdr (4 bytes), public value (4 bytes), and stage parameter (StageNum * 5 * 4 bytes, StageNum is between 0 and 10). This part is used to send to DSP.
Byte 0~3
Byte 4~7
Byte 8~N
McuToSdkCmdHdr
Public UInt32 Stage; //:4
Public Int32 GuadBit; //:4
Public Int32 Gain; //:24Stage parameter
EQ information (maximum 54 bytes): EQ information header (4 bytes), and EQ information parameter (StageNum * 5 bytes, StageNum is between 0 and 10). This part is used to send to phone.
Byte 0~3
Byte 4~N
Public UInt16 StageNum;//:4
Public UInt16 SampleFreqIndex;//:4 SampleRate_T
Public UInt16 resv;//:8
Public Int16 GlobalGain;//:16 s5.10Public UInt16 BiquadType;//:3 EQ_FILTER_TYPE_E
Public UInt16 Q;//:10
Public Int16 Gain;//:12
Public Uint16 Freq;//15
Note
Different sample rates are handled differently. If the sample rate is 48k, the SoC does not need to report EQ information to the phone. Other sample rates (including 44.1K, 16K, 32K, etc.) must report EQ information.
For example, if StageNum is 5, the overall EQ size of this group that sent to dsp is about 108 bytes, which mainly includes McuToSdkCmdHdr (4 bytes), public value (4 bytes), and stage parameter (5 * 5 * 4 = 100 bytes). And for phone interaction, the EQ size is about 29 bytes, including EQ information header (4 bytes), and EQ information parameter (5 * 5 = 25 bytes).
EQ Modes Mechanism
The mechanism of EQ modes is as follows:
EQ Mode Change
When entering/exiting a special mode, SoC automatically applies the corresponding EQ without an EQ ringtone.
For example, when entering game mode, SoC applies game EQ. When exiting game mode, normal EQ is applied.
When SoC is in multiple modes, the priority of EQ from high to low is line-in EQ, gaming EQ, ANC EQ, and normal EQ.
For example, when game mode and ANC are enabled at the same time, SoC applies gaming EQ.
If the corresponding EQ is not set, it will be regarded as disabling the gaming/ANC/line-in EQ feature.
For example, if any IsEnable field of gaming EQ is not checked, the EQ will not change when entering/exiting gaming mode.
The code to determine the EQ mode is as follows.
uint8_t app_eq_judge_audio_eq_mode(void) { uint8_t new_eq_mode = NORMAL_MODE; #if F_APP_LINEIN_SUPPORT if (app_line_in_plug_state_get() && (eq_utils_num_get(SPK_SW_EQ, LINE_IN_MODE) != 0)) { new_eq_mode = LINE_IN_MODE; } else #endif { if (app_db.gaming_mode && (eq_utils_num_get(SPK_SW_EQ, GAMING_MODE) != 0)) { new_eq_mode = GAMING_MODE; } #if F_APP_ANC_SUPPORT else if (app_anc_is_anc_on_state(app_db.current_listening_state) && (eq_utils_num_get(SPK_SW_EQ, ANC_MODE) != 0)) { new_eq_mode = ANC_MODE; } #endif else { new_eq_mode = NORMAL_MODE; } } return new_eq_mode; }
Last Used EQ Index
SoC records the last used EQ index. This EQ will be applied automatically next time.
For example, the user switches to the third EQ. SoC will apply the third EQ until the user changes to another EQ.
For multiple EQ modes, the last used EQ index is recorded separately. When EQ mode changes, SoC will apply a separate EQ index. The variables are as follows:
uint8_t eq_idx_line_in_mode_record; uint8_t eq_idx_gaming_mode_record; uint8_t eq_idx_anc_mode_record; uint8_t eq_idx_normal_mode_record;
When the user controls the EQ index by MMI or CMD settings, SoC only changes the EQ index of the current EQ mode.
Note
Since the MIC EQ has only one mode, SoC does not consider the EQ mode switching of the MIC EQ.
How to Control EQ
EQ control can be supported in multiple ways:
EQ Control by MMI
If the number of EQs in the current EQ mode is greater than 1, the user can switch the EQ index by MMI.
EQ Control by Audio Connect (Command Set)
On the setting page shown below, the user can click ‘Equalizer’ to control the SPK EQ, and click ‘Real Hearing Enhancement’ to control the APT EQ.
As illustrated in the following figure, for SPK EQ:
The user can click the EQ below to switch to other EQ indexes.
The user can adjust the gain value of the current EQ. Other parameters such as Freq, Gain, Q, and Type are the same as the settings in the DSP CFG image.
The method to get the EQ parameters is described in The Adjusted EQ Parameter.
When SoC is in special EQ mode, Audio Connect updates the information automatically.
As shown below, APT EQ can be controlled by clicking ‘APT EQ’ on the ‘Real Hearing Enhancement’ page.
There are a few points to note:
The APT EQ is controlled the same way as the audio EQ.
The method to get the EQ parameters is described in The Adjusted EQ Parameter.
If ‘RWS separate adjust apt eq by audio connect’ is checked, there are ‘Left’ and ‘Right’ options.
The Adjusted EQ Parameter
Users can adjust the gain of EQ by Audio Connect.
Depending on the capacity and settings of SoC, the adjusted EQ parameters may be saved in the phone or SoC.
If the adjusted EQ parameters are saved in the SoC (
F_APP_USER_EQ_SUPPORT
flag is enabled, as described in User EQ), SoC can obtain the parameters at any time. Otherwise, SoC needs to report the EQ index to request Audio Connect to send the adjusted EQ parameters to SoC.If the adjusted EQ parameters are saved in the phone, Audio Connect needs to keep running in the background.
If Audio Connect is terminated, the EQ effect will revert to the original settings.
The Command Set about EQ
The EQ command set includes EQ commands and EQ events.
The EQ commands are as follows:
typedef enum
{
CMD_AUDIO_EQ_QUERY = 0x0200,
...
CMD_AUDIO_EQ_PARAM_SET = 0x0203,
CMD_AUDIO_EQ_PARAM_GET = 0x0204,
CMD_AUDIO_EQ_INDEX_SET = 0x0205,
CMD_AUDIO_EQ_INDEX_GET = 0x0206,
...
CMD_APT_EQ_INDEX_SET = 0x020B,
CMD_APT_EQ_INDEX_GET = 0x020C,
...
CMD_AUDIO_EQ_QUERY_PARAM = 0x0210,
...
CMD_RESET_EQ_DATA = 0x0214,
} T_CMD_ID;
The EQ events are as follows:
typedef enum
{
EVENT_ACK = 0x0000,
...
EVENT_AUDIO_EQ_REPLY = 0x0200,
EVENT_AUDIO_EQ_PARAM_REPORT = 0x0201,
EVENT_AUDIO_EQ_INDEX_REPORT = 0x0202,
...
EVENT_APT_EQ_INDEX_INFO = 0x0206,
EVENT_AUDIO_EQ_REPLY_PARAM = 0x0208,
} T_EVENT_ID;
For SPK EQ, SoC reports T_EQ_DATA_UPDATE_EVENT
with the following parameters.
typedef enum
{
EQ_INDEX_REPORT_BY_PLAYING,
EQ_INDEX_REPORT_BY_CHANGE_MODE,
EQ_INDEX_REPORT_BY_SWITCH_EQ_INDEX,
EQ_INDEX_REPORT_BY_GET_EQ_INDEX,
EQ_INDEX_REPORT_BY_UPDATE_EQ_INDEX,
EQ_INDEX_REPORT_BY_GET_UNSAVED_EQ,
} T_EQ_DATA_UPDATE_EVENT;
Note
If the adjusted EQ parameters are saved in the phone, SoC reports the following parameters to get the EQ settings.
EQ_INDEX_REPORT_BY_PLAYING
SoC sends this parameter when playing music. SoC will expect a response about the current EQ.
EQ_INDEX_REPORT_BY_CHANGE_MODE
SoC sends this parameter when the EQ mode changes. SoC will expect a response about the current EQ.
EQ_INDEX_REPORT_BY_SWITCH_EQ_INDEX
SoC sends this parameter when the EQ is switched by MMI. SoC will expect a response about the current EQ.
If the adjusted EQ parameters are saved in the SoC.
When the EQ mode/index is changed, SoC reports
EQ_INDEX_REPORT_BY_UPDATE_EQ_INDEX
to let Audio Connect update the UI.When RWS is engaged, SoC reports
EQ_INDEX_REPORT_BY_GET_UNSAVED_EQ
to get unsaved EQ parameters.
EQ_INDEX_REPORT_BY_GET_EQ_INDEX
SoC sends this parameter when receiving
CMD_AUDIO_EQ_INDEX_GET
.
And for APT EQ, SoC reports T_APT_EQ_DATA_UPDATE_EVENT
with the following parameters.
typedef enum
{
EQ_INDEX_REPORT_BY_APT_ENABLE,
EQ_INDEX_REPORT_BY_RWS_CONNECTED,
EQ_INDEX_REPORT_BY_SWITCH_APT_EQ_INDEX,
EQ_INDEX_REPORT_BY_GET_APT_EQ_INDEX,
EQ_INDEX_REPORT_BY_UPDATE_APT_EQ_INDEX,
EQ_INDEX_REPORT_BY_GET_UNSAVED_APT_EQ,
} T_APT_EQ_DATA_UPDATE_EVENT;
Note
If the adjusted EQ parameters are saved in the phone, SoC reports the following parameters to get the EQ settings.
EQ_INDEX_REPORT_BY_APT_ENABLE
SoC sends this parameter when DSP APT is enabled. SoC will expect a response about the current EQ.
EQ_INDEX_REPORT_BY_RWS_CONNECTED
SoC sends this parameter when the EQ mode is changed. SoC will expect a response about the current EQ.
EQ_INDEX_REPORT_BY_SWITCH_APT_EQ_INDEX
SoC sends this parameter when EQ is switched by MMI. SoC will expect a response about the current EQ.
If the adjusted EQ parameters are saved in the SoC.
When EQ index is changed, SoC reports
EQ_INDEX_REPORT_BY_UPDATE_APT_EQ_INDEX
to let Audio Connect update the UI.When RWS is engaged, SoC reports
EQ_INDEX_REPORT_BY_GET_UNSAVED_APT_EQ
to get unsaved EQ parameters.
EQ_INDEX_REPORT_BY_GET_APT_EQ_INDEX
SoC sends this parameter when receiving
CMD_APT_EQ_INDEX_GET
.
APIs
There are EQ related APIs, including EQ Framework APIs and EQ APP APIs.
EQ Framework APIs are as follows:
eq_create
Create an EQ instance.
Usage example:
eq_instance = eq_create(eq_content_type, dynamic_eq_buf, eq_len);
eq_release
Release the specific EQ instance.
Usage example:
// SPK EQ eq_release(p_link->eq_instance); // APT EQ eq_release(app_db.apt_eq_instance);
eq_enable
Enable the specific EQ instance.
Usage example:
eq_enable(app_db.apt_eq_instance);
eq_disable
Disable the specific EQ instance.
Usage example:
eq_disable(app_db.apt_eq_instance);
audio_track_effect_attach
Attach the Audio Effect instance to the specific Audio Track session.
Usage example:
audio_track_effect_attach(p_link->a2dp_track_handle, p_link->eq_instance);
audio_passthrough_effect_attach
Attach the Audio Effect instance to the Audio Pass-through stream.
Usage example:
audio_passthrough_effect_attach(app_db.apt_eq_instance);
line_in_effect_attach
Attach the Audio Effect instance to the line-in stream.
Usage example:
line_in_effect_attach(app_db.line_in_eq_instance);
audio_track_effect_detach
Detach the Audio Effect instance from the specific Audio Track session.
Usage example:
audio_track_effect_detach(p_link->a2dp_track_handle, p_link->eq_instance);
audio_passthrough_effect_detach
Detach the Audio Effect instance from the Audio Pass-through stream.
Usage example:
audio_passthrough_effect_detach(app_db.apt_eq_instance);
line_in_effect_detach
Detach the Audio Effect instance from the line-in stream.
Usage example:
line_in_effect_detach(app_db.line_in_eq_instance);
eq_set
Set the specific EQ instance band parameter.
Usage example:
eq_set(link->eq_instance, dynamic_eq_buf, eq_len);
And EQ APP APIs are as follows:
app_eq_init
Init APP EQ module.
Usage example:
app_eq_init();
app_eq_deinit
Deinit APP EQ module.
Usage example:
app_eq_deinit();
app_eq_create
Create EQ instance.
Usage example:
// SPK EQ p_link->eq_instance = app_eq_create(EQ_CONTENT_TYPE_AUDIO, SPK_SW_EQ, app_db.spk_eq_mode, app_cfg_nv.eq_idx); // APT EQ app_db.apt_eq_instance = app_eq_create(EQ_CONTENT_TYPE_PASSTHROUGH, MIC_SW_EQ, APT_MODE, app_cfg_nv.apt_eq_idx);
app_eq_index_set
Set the specific EQ index.
Usage example:
// SPK EQ app_eq_index_set(SPK_SW_EQ, app_db.spk_eq_mode, app_cfg_nv.eq_idx); // APT EQ app_eq_index_set(MIC_SW_EQ, APT_MODE, app_cfg_nv.apt_eq_idx);
app_eq_dsp_param_get
Get specific EQ parameter.
Usage example:
// get the EQ parameter sent to DSP eq_len = app_eq_dsp_param_get(eq_type, stream_type, mode, index, dynamic_eq_buf, app_db.max_eq_len, EQ_DATA_TO_DSP, sample_rate); // get the EQ parameter sent to source eq_len = app_eq_dsp_param_get((T_EQ_TYPE)p_eq_info->sw_eq_type, stream_type, p_eq_info->eq_mode, p_eq_info->eq_idx, eq_data_temp, app_db.max_eq_len, EQ_DATA_TO_PHONE, sample_rate);
app_eq_param_set
Set the specific EQ index parameter.
Usage example:
app_eq_param_set(eq_mode, eq_idx, &cmd_ptr[0], eq_len_to_dsp);
app_eq_play_audio_eq_tone
Play audio EQ tone.
Usage example:
app_eq_play_audio_eq_tone();
app_eq_play_apt_eq_tone
Play APT EQ tone.
Usage example:
app_eq_play_apt_eq_tone();
app_eq_report_eq_param
Report EQ parameter.
Usage example:
app_eq_report_eq_param(cmd_path, app_idx);
app_eq_report_terminate_param_report
Terminate report EQ parameter.
Usage example:
app_eq_report_terminate_param_report(cmd_path, app_idx);
app_eq_sample_rate_get
Get current sample rate.
Usage example:
app_eq_sample_rate_get();
app_eq_idx_check_accord_mode
Check idx accord EQ mode.
Usage example:
app_eq_idx_check_accord_mode();
app_eq_sync_idx_accord_eq_mode
Check EQ mode then sync idx
Usage example:
app_eq_sync_idx_accord_eq_mode(eq_mode, eq_idx);
app_eq_cmd_handle
EQ related command handler.
Usage example:
app_eq_cmd_handle(cmd_ptr, cmd_len, cmd_path, app_idx, ack_pkt);
app_eq_audio_eq_enable
Enable the EQ effect.
Usage example:
app_eq_audio_eq_enable(&p_link->eq_instance, &p_link->audio_eq_enabled);
app_eq_change_audio_eq_mode
Change audio speaker EQ mode.
Usage example:
app_eq_change_audio_eq_mode(true);
app_eq_judge_audio_eq_mode
Judge audio speaker EQ mode.
Usage example:
app_db.spk_eq_mode = app_eq_judge_audio_eq_mode();
app_eq_save_user_eq_to_ftl
Save specific user EQ to FTL.
Usage example:
app_eq_save_user_eq_to_ftl((T_EQ_TYPE)app_db.sw_eq_type, eq_mode, eq_idx, eq_data[0], eq_adjust_side, &eq_data[1], eq_len_to_dsp, &eq_data[1 + eq_len_to_dsp], p_audio_eq_info->eq_data_len - eq_len_to_dsp - 1);
app_eq_is_valid_user_eq_index
Check the specific EQ is valid user EQ or not.
Usage example:
#if (F_APP_USER_EQ_SUPPORT == 1) if (app_eq_is_valid_user_eq_index(SPK_SW_EQ, app_db.spk_eq_mode, app_cfg_nv.eq_idx)) { app_report_eq_idx(EQ_INDEX_REPORT_BY_GET_UNSAVED_EQ); } else #endif { app_report_eq_idx(EQ_INDEX_REPORT_BY_PLAYING); }
app_eq_reset_user_eq
Reset specific user EQ.
Usage example:
app_eq_reset_user_eq((T_EQ_TYPE)eq_type, eq_mode, eq_idx);
app_eq_reset_all_user_eq
Reset all user EQ.
Usage example:
app_eq_reset_all_user_eq();
app_eq_reset_unsaved_user_eq
Reset unsaved user EQ.
Usage example:
app_eq_reset_unsaved_user_eq();
app_eq_sync_user_eq_when_connected
Sync user EQ when bud connected.
Usage example:
app_eq_sync_user_eq_when_connected();
app_eq_continue_sync_user_eq_when_connected
Continue sync user EQ when bud connected.
Usage example:
app_eq_continue_sync_user_eq_when_connected(false, eq_type, eq_index, offset, len - 5);
app_eq_process_sync_user_eq_when_b2b_connected
Process sync user EQ message when bud connected.
Usage example:
app_eq_process_sync_user_eq_when_b2b_connected(eq_type, eq_index, offset, &buf[5], len - 5);
app_eq_report_sec_eq_to_pri
Report the EQ of secondary to primary.
Usage example:
app_eq_report_sec_eq_to_pri(eq_type, eq_mode, eq_index, cmd_path, app_idx);
app_eq_report_sec_eq_to_src
Report the EQ of secondary to source.
Usage example:
app_eq_report_sec_eq_to_src(cmd_path, app_idx, eq_len, &buf[7]);