93 lines
3.5 KiB
C
93 lines
3.5 KiB
C
/**
|
||
****************************************************************************************************
|
||
* @file audio_source.h
|
||
* @author HiFi Player Project
|
||
* @version V1.5
|
||
* @date 2026-01-01
|
||
* @brief 统一音源接口(WAV / FLAC)
|
||
*
|
||
* 上层播放器只关心“给我一块立体声 PCM 和它对应的位宽”,不必区分容器格式:
|
||
*
|
||
* audio_source_open() ── 按文件头自动识别 RIFF(WAV) / fLaC、OggS(FLAC)
|
||
* │ 同时给出该曲目应使用的 I2S 位宽 out_bits(16/24/32)
|
||
* audio_source_read() ── 输出 **源文件原生位深** 的立体声交错 PCM
|
||
* │ 单声道自动复制;>2 声道只取前两声道;不做降位
|
||
* audio_source_close()
|
||
*
|
||
* 时间进度统一用“已播放帧数 / 采样率”计算,对两种格式都准确。
|
||
*
|
||
* 位宽映射(源位深 → I2S 位宽):
|
||
* ≤16bit → 16bit(每采样 2 字节)
|
||
* 17~24bit → 24bit(每采样 3 字节)
|
||
* 25~32bit → 32bit(每采样 4 字节)
|
||
* 非整字节位深(如 20bit)按左对齐放入更宽的槽位,音量不受影响。
|
||
*
|
||
* 采样率限制:
|
||
* ES8388 的 MCLK 由 I2S 产生(MCLK = mclk_multiple × fs),24bit 时
|
||
* mclk_multiple 必须是 384。若直接播放 192kHz,MCLK 会到 73.7MHz,
|
||
* 远超 codec 能力。因此 88.2k/96k/192k 等会做整数抽取降到 ≤48kHz,
|
||
* audio_info_t.sample_rate 返回的始终是「实际输出采样率」。
|
||
****************************************************************************************************
|
||
*/
|
||
|
||
#ifndef __AUDIO_SOURCE_H
|
||
#define __AUDIO_SOURCE_H
|
||
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/** 支持的音频容器 */
|
||
typedef enum {
|
||
AUDIO_CODEC_WAV = 0, /* RIFF/WAVE,PCM 16/24/32bit */
|
||
AUDIO_CODEC_FLAC, /* 原生 FLAC 或 Ogg FLAC */
|
||
} audio_codec_t;
|
||
|
||
/** 音源信息 */
|
||
typedef struct {
|
||
audio_codec_t codec; /* 容器类型 */
|
||
uint32_t sample_rate; /* 采样率 → 用于配置 I2S 频率(已按输出上限抽取) */
|
||
uint16_t bits; /* 源位深(界面显示用) */
|
||
uint16_t channels; /* 源声道数 */
|
||
uint16_t out_bits; /* I2S 输出位宽:16 / 24 / 32 */
|
||
uint8_t out_bytes; /* 输出每采样字节数:2 / 3 / 4 */
|
||
uint32_t total_sec; /* 总时长(秒),0 表示未知 */
|
||
} audio_info_t;
|
||
|
||
typedef struct audio_source audio_source_t;
|
||
|
||
/**
|
||
* @brief 打开音频文件并解析头部
|
||
* @param path 文件路径
|
||
* @param info 输出音源信息(可为 NULL)
|
||
* @retval 句柄;失败返回 NULL
|
||
*/
|
||
audio_source_t *audio_source_open(const char *path, audio_info_t *info);
|
||
|
||
/**
|
||
* @brief 读取一块 PCM
|
||
* @param src 音源句柄
|
||
* @param out 输出缓冲区(立体声交错,位宽 = info.out_bits)
|
||
* @param max_frames 最多读取多少帧(1 帧 = 左右各 1 个采样)
|
||
* @retval >0 实际帧数
|
||
* 0 播放结束
|
||
* <0 解码/读取错误
|
||
* @note 每帧占用 2 * out_bytes 字节,调用者需保证缓冲区足够
|
||
*/
|
||
int audio_source_read(audio_source_t *src, void *out, int max_frames);
|
||
|
||
/** @brief 已播放的秒数(按解码帧数计算) */
|
||
uint32_t audio_source_elapsed_sec(const audio_source_t *src);
|
||
|
||
/** @brief 关闭音源并释放资源(可传 NULL) */
|
||
void audio_source_close(audio_source_t *src);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* __AUDIO_SOURCE_H */
|