跳转至

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” 切换音频开始循环播放。