KT24-1110_65E-HA-651B/cpu/br25/audio_mic/loud_speaker.c
2024-11-10 18:44:17 +08:00

537 lines
15 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system/includes.h"
#include "media/includes.h"
#include "app_config.h"
#include "app_online_cfg.h"
/* #include "audio_drc.h" */
/* #include "audio_reverb.h" */
#include "clock_cfg.h"
#include "audio_config.h"
#include "storage_dev/storage_dev.h"
#include "loud_speaker.h"
#include "audio_dec.h"
#include "audio_enc.h"
#include "media/pcm_decoder.h"
#include "media/audio_howling.h"
#include "media/audio_voice_changer.h"
#include "media/audio_echo_reverb.h"
#define LOG_TAG "[APP-SPEAKER]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#include "debug.h"
#define ECHO_ENABLE 0 //K歌混响
#define HOWLING_ENABLE 0 //啸叫抑制
#define PITCH_ENABLE 0 //变声
// mic 采样率 若存在与mic录音/usb mic 等同开情况 需保证采样率一致
#define LOUND_SPEAKER_MIC_SAMPLE_RATE 44100
//简易版扩音器功能 使用解码数据流程把mic数据接入mix能把数据输出到DAC/FM/IIS等 (mic_effect.c里面的混响只能输出到DAC)
// 可用于mic to dac的测试 /mic混响数据到fm/iis输出功能
//
#if 0
extern struct audio_adc_hdl adc_hdl;
extern struct audio_decoder_task decode_task;
extern struct audio_mixer mixer;
#define PCM_BUF_LEN (2*1024)
enum {
REVERB_STATUS_STOP = 0,
REVERB_STATUS_START,
REVERB_STATUS_PAUSE,
};
struct s_speaker_hdl {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
u32 process_len;
struct audio_stream *stream; // 音频流
int mic_gain;
u16 mic_sr;
u16 src_out_sr;
u16 src_out_sr_n;
int begin_size;
int top_size;
int bottom_size;
u16 audio_new_rate;
u16 audio_max_speed;
u16 audio_min_speed;
u8 sync_start;
u8 pcm_buf[PCM_BUF_LEN ];
cbuffer_t pcm_cbuf;
u32 status : 2;
u32 source_ch_num : 2;
u32 reverb_en : 2;
u32 howling_en : 2;
u8 first_start;
u8 speaker_pause;
/* struct audio_decoder decoder; */
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
struct pcm_decoder pcm_dec; // pcm解码句柄
#if ECHO_ENABLE
ECHO_API_STRUCT *p_echo_hdl;
#endif
#if HOWLING_ENABLE
HOWLING_API_STRUCT *p_howling_hdl;
#endif
#if PITCH_ENABLE
s_pitch_hdl *p_pitch_hdl;
#endif
struct channel_switch *channel_zoom;
};
static struct s_speaker_hdl *speaker_hdl = NULL;
static u8 pcm_dec_maigc = 0;
//echo 参数
EF_REVERB_FIX_PARM effect_echo_fix_parm = {
.wetgain = 2048, ////湿声增益:[0:4096]
.drygain = 4096, ////干声增益: [0:4096]
.sr = LOUND_SPEAKER_MIC_SAMPLE_RATE, ////采样率
.max_ms = 200, ////所需要的最大延时,影响 need_buf 大小
};
ECHO_PARM_SET effect_echo_parm = {
.delay = 200, //回声的延时时间 0-300ms
.decayval = 50, // 0-70%
.direct_sound_enable = 1, //直达声使能 0/1
.filt_enable = 0, //发散滤波器使能
};
static void adc_output_to_buf(void *priv, s16 *data, int len)
{
if ((!speaker_hdl) || (speaker_hdl->status != REVERB_STATUS_START)) {
return;
}
if (speaker_hdl->speaker_pause) {
return;
}
int wlen = cbuf_write(&speaker_hdl->pcm_cbuf, data, len);
if (!wlen) {
putchar('W');
}
audio_decoder_resume(&speaker_hdl->pcm_dec.decoder);
}
static void pcm_dec_relaese()
{
audio_decoder_task_del_wait(&decode_task, &speaker_hdl->wait);
}
static void pcm_dec_close(void)
{
audio_decoder_close(&speaker_hdl->pcm_dec.decoder);
audio_mixer_ch_close(&speaker_hdl->mix_ch);
if (speaker_hdl->stream) {
audio_stream_close(speaker_hdl->stream);
speaker_hdl->stream = NULL;
}
}
static int pcm_fread(void *hdl, void *buf, int len)
{
struct s_speaker_hdl *dec = (struct s_speaker_hdl *)hdl;
int rlen = cbuf_read(&dec->pcm_cbuf, buf, len);
/* printf("rlen %d",rlen); */
return rlen;
}
static void pcm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
if ((u8)argv[1] != (u8)(pcm_dec_maigc - 1)) {
log_i("maigc err, %s\n", __FUNCTION__);
break;
}
/* pcm_dec_close(); */
break;
}
}
/*----------------------------------------------------------------------------*/
/**@brief pcm解码数据输出
@param *entry: 音频流句柄
@param *in: 输入信息
@param *out: 输出信息
@return 输出长度
@note *out未使用
*/
/*----------------------------------------------------------------------------*/
static int pcm_dec_data_handler(struct audio_stream_entry *entry,
struct audio_data_frame *in,
struct audio_data_frame *out)
{
struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry);
struct pcm_decoder *pcm_dec = container_of(decoder, struct pcm_decoder, decoder);
struct s_speaker_hdl *dec = container_of(pcm_dec, struct s_speaker_hdl, pcm_dec);
audio_stream_run(&decoder->entry, in);
return decoder->process_len;
}
/*----------------------------------------------------------------------------*/
/**@brief pcm解码数据流激活
@param *p: 私有句柄
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void dec_out_stream_resume(void *p)
{
struct s_speaker_hdl *dec = (struct s_speaker_hdl *)p;
audio_decoder_resume(&dec->pcm_dec.decoder);
}
static int pcm_dec_start(void)
{
int err;
struct audio_fmt f;
struct s_speaker_hdl *dec = speaker_hdl;
log_i("\n--func=%s\n", __FUNCTION__);
err = pcm_decoder_open(&dec->pcm_dec, &decode_task);
if (err) {
goto __err1;
}
pcm_decoder_set_event_handler(&dec->pcm_dec, pcm_dec_event_handler, 0);
pcm_decoder_set_read_data(&dec->pcm_dec, pcm_fread, dec);
pcm_decoder_set_data_handler(&dec->pcm_dec, pcm_dec_data_handler);
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_src(&dec->mix_ch, 1, 1);
/* audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 10); // 超时自动丢数 */
// 数据流串联
struct audio_stream_entry *entries[8] = {NULL};
u8 entry_cnt = 0;
entries[entry_cnt++] = &dec->pcm_dec.decoder.entry;
#if HOWLING_ENABLE
entries[entry_cnt++] = &dec->p_howling_hdl->entry;
#endif
#if ECHO_ENABLE
entries[entry_cnt++] = &dec->p_echo_hdl->entry;
#endif
#if PITCH_ENABLE
entries[entry_cnt++] = &dec->p_pitch_hdl->entry;
//for test pitch
loundspeaker_set_pitch_para(66, LOUND_SPEAKER_MIC_SAMPLE_RATE, EFFECT_VOICECHANGE_KIN0, 150);
#endif
if (dec->channel_zoom) {
entries[entry_cnt++] = &dec->channel_zoom->entry;
}
entries[entry_cnt++] = &dec->mix_ch.entry;
dec->stream = audio_stream_open(dec, dec_out_stream_resume);
audio_stream_add_list(dec->stream, entries, entry_cnt);
audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC);
/* audio_adc_mic_start(&dec->mic_ch); */
log_i("\n\n audio decoder start \n");
dec->status = REVERB_STATUS_START;
err = audio_decoder_start(&dec->pcm_dec.decoder);
if (err) {
goto __err3;
}
log_i("\n\n audio mic start 1 \n");
return 0;
__err3:
dec->status = 0;
audio_mic_close(&dec->mic_ch, &dec->adc_output);
__err2:
if (dec->stream) {
audio_stream_close(dec->stream);
dec->stream = NULL;
}
pcm_decoder_close(&dec->pcm_dec);
__err1:
audio_decoder_task_del_wait(&decode_task, &dec->wait);
return err;
}
static int pcmdec_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (!speaker_hdl) {
log_e("speaker_hdl err \n");
return -1;
}
log_i("pcmdec_wait_res_handler, event:%d;status:%d; \n", event, speaker_hdl->status);
if (event == AUDIO_RES_GET) {
if (speaker_hdl->status == REVERB_STATUS_STOP) {
err = pcm_dec_start();
} else if (speaker_hdl->status == REVERB_STATUS_PAUSE) {
speaker_hdl->status = REVERB_STATUS_START;
}
} else if (event == AUDIO_RES_PUT) {
if (speaker_hdl->status == REVERB_STATUS_START) {
/* reverb_hdl->status = REVERB_STATUS_PAUSE; */
}
}
return err;
}
//************************* MIC to DAC API *****************************//
void stop_loud_speaker(void)
{
if (!speaker_hdl) {
return;
}
log_i("\n--func=%s\n", __FUNCTION__);
speaker_hdl->status = REVERB_STATUS_STOP;
audio_mic_close(&speaker_hdl->mic_ch, &speaker_hdl->adc_output);
pcm_dec_close();
#if ECHO_ENABLE
close_echo(speaker_hdl->p_echo_hdl);
#endif
#if HOWLING_ENABLE
close_howling(speaker_hdl->p_howling_hdl);
#endif
#if PITCH_ENABLE
close_pitch(speaker_hdl->p_pitch_hdl);
#endif
if (speaker_hdl->channel_zoom) {
channel_switch_close(&speaker_hdl->channel_zoom);
}
pcm_dec_relaese();
free(speaker_hdl);
speaker_hdl = NULL;
clock_remove_set(REVERB_CLK);
}
void start_loud_speaker(struct audio_fmt *fmt)
{
struct s_speaker_hdl *reverb = NULL;
int err;
if (speaker_hdl) {
stop_loud_speaker();
}
clock_add_set(REVERB_CLK);
reverb = zalloc(sizeof(struct s_speaker_hdl));
log_i("speaker hdl:%lu", sizeof(struct s_speaker_hdl));
ASSERT(reverb);
struct audio_fmt f = {0};
if (fmt) {
f.sample_rate = fmt->sample_rate;
}
if (f.sample_rate == 0) {
f.sample_rate = LOUND_SPEAKER_MIC_SAMPLE_RATE;
}
f.channel = 1;
reverb->source_ch_num = f.channel;
reverb->mic_sr = f.sample_rate;
reverb->mic_gain = 2;
#if ECHO_ENABLE
reverb->p_echo_hdl = open_echo(&effect_echo_parm, &effect_echo_fix_parm);
ASSERT(reverb->p_echo_hdl);
#endif
#if HOWLING_ENABLE
reverb->p_howling_hdl = open_howling(NULL, f.sample_rate, audio_output_channel_num(), 1);
#endif
#if PITCH_ENABLE
reverb->p_pitch_hdl = open_pitch(NULL);
/* pause_pitch(reverb->p_pitch_hdl, 1); */
#endif
if (audio_output_channel_num() != 1) {
reverb->channel_zoom = channel_switch_open(audio_output_channel_type(), 1024);
}
#if 1
cbuf_init(&reverb->pcm_cbuf, reverb->pcm_buf, sizeof(reverb->pcm_buf));
if (audio_mic_open(&reverb->mic_ch, f.sample_rate, reverb->mic_gain) == 0) {
reverb->adc_output.handler = adc_output_to_buf;
audio_mic_add_output(&reverb->adc_output);
audio_mic_start(&reverb->mic_ch);
}
#endif
reverb->pcm_dec.ch_num = 1;
reverb->pcm_dec.output_ch_num = 1;//audio_output_channel_num(); echo/pitch 只能处理单声道数据
reverb->pcm_dec.output_ch_type = audio_output_channel_type();
reverb->pcm_dec.sample_rate = reverb->mic_sr;
reverb->wait.priority = 0;
reverb->wait.preemption = 0;
reverb->wait.protect = 1;
reverb->wait.handler = pcmdec_wait_res_handler;
speaker_hdl = reverb;
err = audio_decoder_task_add_wait(&decode_task, &reverb->wait);
if (err == 0) {
return ;
}
log_e("audio decoder task add wait err \n");
audio_mic_close(&reverb->mic_ch, &reverb->adc_output);
#if ECHO_ENABLE
close_echo(reverb->p_echo_hdl);
#endif
#if HOWLING_ENABLE
close_howling(reverb->p_howling_hdl);
#endif
#if PITCH_ENABLE
close_pitch(reverb->p_pitch_hdl);
#endif
if (speaker_hdl->channel_zoom) {
channel_switch_close(&speaker_hdl->channel_zoom);
}
clock_remove_set(REVERB_CLK);
}
/***************************************************************/
int speaker_if_working(void)
{
if (speaker_hdl && (speaker_hdl->status == REVERB_STATUS_START)) {
return 1;
}
return 0;
}
void loud_speaker_pause(void)
{
if (speaker_hdl) {
speaker_hdl->speaker_pause = 1;
audio_mixer_ch_pause(&speaker_hdl->mix_ch, 1);
printf("speaker_pause [%d]", speaker_hdl->speaker_pause);
}
}
void loud_speaker_resume(void)
{
if (speaker_hdl) {
audio_mixer_ch_pause(&speaker_hdl->mix_ch, 0);
speaker_hdl->speaker_pause = 0;
printf("speaker_pause [%d]", speaker_hdl->speaker_pause);
}
}
/****************************效果设置接口***********************************/
void switch_holwing_en(void)
{
if (speaker_hdl) {
speaker_hdl->howling_en ^= 1;
#if HOWLING_ENABLE
if (speaker_hdl->p_howling_hdl) {
pause_howling(speaker_hdl->p_howling_hdl, speaker_hdl->howling_en);
printf("howling_en [%d]", speaker_hdl->howling_en);
}
#endif
}
}
void switch_echo_en(void)
{
if (speaker_hdl) {
speaker_hdl->reverb_en ^= 1;
printf("reverb_en [%d]", speaker_hdl->reverb_en);
#if ECHO_ENABLE
if (speaker_hdl->reverb_en) {
pause_echo(speaker_hdl->p_echo_hdl, speaker_hdl->reverb_en);
}
#endif
}
}
/*----------------------------------------------------------------------------*/
/**@brief loundspeaker echo 回声延时调节接口
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void loundspeaker_set_echo_delay(u32 delay)
{
#if ECHO_ENABLE
if (speaker_hdl == NULL || speaker_hdl->p_echo_hdl == NULL) {
return ;
}
effect_echo_parm.delay = delay;
update_echo_parm(speaker_hdl->p_echo_hdl, &effect_echo_parm);
#endif
}
u32 loundspeaker_get_echo_delay(void)
{
#if ECHO_ENABLE
if (speaker_hdl && speaker_hdl->p_echo_hdl) {
return effect_echo_parm.delay;
}
#endif
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief loundspeaker echo 回声衰减系数调节接口
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void loundspeaker_set_echo_decay(u32 decay)
{
#if ECHO_ENABLE
if (speaker_hdl == NULL || speaker_hdl->p_echo_hdl == NULL) {
return ;
}
effect_echo_parm.decayval = decay;
update_echo_parm(speaker_hdl->p_echo_hdl, &effect_echo_parm);
#endif
}
u32 loundspeaker_get_echo_decay(void)
{
#if ECHO_ENABLE
if (speaker_hdl && speaker_hdl->p_echo_hdl) {
return effect_echo_parm.decayval;
}
#endif
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief loundspeaker 变声参数设置
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void loundspeaker_set_pitch_para(u32 shiftv, u32 sr, u8 effect, u32 formant_shift)
{
#if PITCH_ENABLE
if (speaker_hdl == NULL || speaker_hdl->p_pitch_hdl == NULL) {
return ;
}
PITCH_SHIFT_PARM p_pitch_parm = {0};//get_pitch_parm();
p_pitch_parm.sr = sr;
p_pitch_parm.shiftv = shiftv;
p_pitch_parm.effect_v = effect;
p_pitch_parm.formant_shift = formant_shift;
printf("\n\n\nshiftv[%d],sr[%d],effect[%d],formant_shift[%d] \n\n", p_pitch_parm.shiftv, p_pitch_parm.sr, p_pitch_parm.effect_v, p_pitch_parm.formant_shift);
update_picth_parm(speaker_hdl->p_pitch_hdl, &p_pitch_parm);
#endif
}
#endif /*TCFG_LOUDSPEAKER_ENABLE*/