AudioOut使用指南
AudioOut使用指南*
第一章 功能特性*
1.1 数据格式*
- 支持交织或非交织存储
- 支持16bit位宽数据
- 支持32bit位宽数据
- 32bit 全有效
- 32bit 中高24bit有效
- 32bit 中中24bit有效
- 32bit 中低24bit有效
- 支持大端存储和小端存储数据
1.2 数据采样率*
- 8000Hz
- 11025Hz
- 16000Hz
- 22050Hz
- 24000Hz
- 32000Hz
- 44100Hz
- 48000Hz
1.3 输出端口*
- 输出至I2S Out端口
- 输出至Audio In
1.4 输出声道*
- 单声道模式: 只输出左声道数据
- 双声道模式
- 混合模式: 每个声道输出左右声道叠加的数据
第二章 API接口说明*
注意
API 里的 DRC 和 EQ 接口不可用,芯片不支持
/*
* NationalChip Apus Project
* Copyright (C) 2001-2023 NationalChip Co., Ltd
* ALL RIGHTS RESERVED!
*
* audio_output.h: audio output header file
*
*/
#ifndef __AUDIO_OUTPUT_H__
#define __AUDIO_OUTPUT_H__
#include <common.h>
#include <soc.h>
#include <gx_hal_aout_v110.h>
#define AUDIO_OUT_SAMPLE_WIDTHZ(bit_cfg) ((bit_cfg = 8) ? 2 : 4)
#define AUDIO_OUT_FRAME_SAMPLE_NUM(sample_rate, frame_ms) ((sample_rate) * (frame_ms) / 1000)
#define AUDIO_OUT_FRAME_SIZE(frame_sample_num, sample_widthz) ((frame_sample_num) * (sample_widthz))
#define AUDIO_OUT_CHANNEL_BUFFER_SIZE(frame_size, channel_frame_num) \
((frame_size) * (channel_frame_num))
#define AUIDO_OUTPUT_PCM_BUFFER_SIZE(channel_bufz, channel_num) ((channel_bufz) * (channel_num))
typedef int (*audio_output_frame_done_cb_t)(int saddr, int eaddr, void* priv);
typedef int (*audio_output_frame_empty_cb_t)(void* priv);
typedef int (*audio_output_fade_done_cb_t)(void* priv);
typedef int (*audio_output_error_cb_t)(void* priv);
typedef struct {
audio_output_frame_done_cb_t frame_done_cb;
audio_output_frame_empty_cb_t frame_empty_cb;
audio_output_fade_done_cb_t fade_done_cb;
audio_output_error_cb_t error_cb;
void *user_data;
}audio_output_cb_t;
typedef struct {
uint16_t sample_rate; // 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000
GX_HAL_AOUT_PCM_BIT bits;
uint8_t channel_num; //1:single 2:double
uint8_t interlace; // 0:uninterlace 1:interlace
uint8_t endian; // 0:little endian 1:big endian
uint8_t i2s_port_en;// 0:off 1:on
uint8_t loadc_port_en;// 0:off 1:on
uint8_t echo_port_en; // 0:off 1:on
uint8_t channel_out_mode; //0 :single channel 1:double channel 2:double channel but mix two channel
uint8_t *pcm_buffer;
uint32_t pcm_size;
audio_output_cb_t audio_output_cb;
}audio_output_config_t;
int audio_output_init(audio_output_config_t *config);
void audio_output_deinit(void);
int audio_output_play(uint32_t offset, uint32_t len);
void audio_output_stop(void);
int audio_output_set_mute(uint8_t mute);
int audio_output_get_mute(void);
int audio_output_set_volume(uint8_t percent);
int audio_output_get_volume(uint8_t *percent);
int audio_output_set_fade(uint8_t fade);
int audio_output_get_fade(void);
int audio_output_drc_enable(uint8_t enable);
int audio_output_set_drc(GX_HAL_AOUT_DRC *drc);
int audio_output_eq_enable(uint8_t enable);
int audio_output_set_eq(GX_HAL_AOUT_EQ *eq, int order_num);
int audio_output_get_eq(GX_HAL_AOUT_EQ *eq, int order_num);
#endif // __AUDIO_OUTPUT_H__
第三章 参考示例*
3.1 示例 app*
参考 apus\apps\audio_out_sample
3.2 示例说明*
#include <stdio.h>
#include <osal.h>
#include <osal.h>
#include <gx_dcache.h>
#include <gx_hal_clk_apus.h>
#include <audio_output.h>
#include <gx_hal_aout_v110.h>
#include <attr_def.h>
#include <stdlib.h>
#include <osal.h>
#include "wo_zai_16k_1ch_s16.h"
#include "xiao_peng_you_16k_2ch_s16.h"
// 本示例演示了,如何播放PCM格式的音频。包含单声道,双声道音频播放,停止播放,音频切换播放,继续播放功能。
#define ALIGN_TO_64(length) ((length) & ~63) // 64字节向下对齐,比如输入65,输出64
#define PCM_SIZE (89600)
static uint8_t pcm_buffer[ALIGN_TO_64(PCM_SIZE)] ATTR_SECTION_PSRAM_BUF __attribute__((aligned(64)));
// 单通道,16K 16bit PCM
static uint8_t *wo_zai_pcm = (uint8_t *)sample_buffer_16k_wo_zai;
static uint32_t wo_zai_pcm_len = ALIGN_TO_64(sizeof(sample_buffer_16k_wo_zai));
// 双通道,16K 16bit PCM
uint8_t *xiap_peng_you_pcm = (uint8_t *)sample_buffer_16k_xiao_peng_you;
static uint32_t xiap_peng_you_pcm_len = ALIGN_TO_64(sizeof(sample_buffer_16k_xiao_peng_you));
static uint32_t play_wav_len = 0;
static int wav_frame_done_cb(int saddr, int eaddr, void* priv)
{
//printf("wav_frame_done_cb\n");
// 这里也可以调用 audio_output_play 继续播放新的音频数据。只要pcm_buffer里面的数据更新了
return 0;
}
static int wav_frame_empty_cb(void* priv)
{
//printf("wav_frame_empty_cb\n");
audio_output_play(0, play_wav_len); // 播放结束了,就继续从头播放,达到循环播放的效果
return 0;
}
static void audio_out_one_channel_init(void)
{
audio_output_config_t config;
memset(&config, 0 ,sizeof(audio_output_config_t));
config.sample_rate = 16000;
config.bits = GX_HAL_AOUT_BIT_16;
config.channel_num = 1;
config.interlace = 0;
config.endian = 0;
config.pcm_buffer = pcm_buffer;
config.pcm_size = sizeof(pcm_buffer); // 注意:config.pcm_size 必须 64 字节对齐
config.channel_out_mode = 1;
config.i2s_port_en = 1;
config.loadc_port_en = 1;
config.echo_port_en = 0;
config.audio_output_cb.frame_done_cb = wav_frame_done_cb;
config.audio_output_cb.frame_empty_cb = wav_frame_empty_cb;
config.audio_output_cb.fade_done_cb = NULL;
config.audio_output_cb.user_data = NULL;
audio_output_init(&config);
audio_output_set_volume(60);
}
static void audio_out_two_channel_init(void)
{
audio_output_config_t config;
memset(&config, 0 ,sizeof(audio_output_config_t));
config.sample_rate = 16000;
config.bits = GX_HAL_AOUT_BIT_16;
config.channel_num = 2;
config.interlace = 1;
config.endian = 0;
config.pcm_buffer = pcm_buffer;
config.pcm_size = sizeof(pcm_buffer); // 注意:config.pcm_size 必须 64 字节对齐
config.channel_out_mode = 2;
config.i2s_port_en = 1;
config.loadc_port_en = 1;
config.echo_port_en = 0;
config.audio_output_cb.frame_done_cb = wav_frame_done_cb;
config.audio_output_cb.frame_empty_cb = wav_frame_empty_cb;
config.audio_output_cb.fade_done_cb = NULL;
config.audio_output_cb.user_data = NULL;
audio_output_init(&config);
audio_output_set_volume(60);
}
static int audio_wav_stop(int argc, const char * argv[])
{
audio_output_stop();
return 0;
}
static int audio_wav_start(int argc, const char * argv[])
{
audio_output_stop();
audio_output_play(0, play_wav_len);
return 0;
}
static int audio_wav_change(int argc, const char * argv[])
{
audio_output_stop();
audio_output_deinit();
audio_out_two_channel_init();
memset(pcm_buffer, 0, sizeof(pcm_buffer));
memcpy(pcm_buffer, xiap_peng_you_pcm, xiap_peng_you_pcm_len);
gx_dcache_clean_range(pcm_buffer, sizeof(pcm_buffer));
play_wav_len = xiap_peng_you_pcm_len;
audio_output_play(0, play_wav_len);
return 0;
}
int main (void)
{
printf("audio out sample\n");
audio_out_one_channel_init();
memset(pcm_buffer, 0, sizeof(pcm_buffer));
memcpy(pcm_buffer, wo_zai_pcm, wo_zai_pcm_len);
gx_dcache_clean_range(pcm_buffer, sizeof(pcm_buffer));
play_wav_len = wo_zai_pcm_len;
audio_output_play(0, play_wav_len);
return 0;
}
COMMAND_EXPORT_ALIAS(audio_wav_stop, audio_wav_stop, "wav stop");
COMMAND_EXPORT_ALIAS(audio_wav_start, audio_wav_start, "wav start");
COMMAND_EXPORT_ALIAS(audio_wav_change, audio_wav_change, "wav change");
测试方法:开机后,会循环播放音频。可以在串口终端输出 "audio_wav_stop" 停止播放,输入 “audio_wav_start” 继续播放,输入 “audio_wav_change” 切换音频开始循环播放。