wch-code/ch32v307_mp3_dac/User/audio/audio_wav.c

234 lines
8.3 KiB
C

#include "audio_wav.h"
#include "debug.h"
#include "delay.h"
#include "bsp_led.h"
#include "ff.h"
#include "tlsf.h"
typedef struct __attribute__((packed)) { //RIFF块 用于指示文件类型
uint32_t chunk_id; /* ID:"RIFF" 即0x46464952 */
uint32_t chunk_size ;/* 集合大小 等于文件总大小-8 */
uint32_t format;/* 格式:"WAVE" 即0x45564157 */
} audio_wav_riff_chunk_t;
typedef struct __attribute__((packed)) { //FMT块 用于记录WAV文件的信息
uint32_t chunk_id; /* ID:"fmt " 即0x20746D66 */
uint32_t chunk_size; /* 子集合大小(不包括ID和Size) */
uint16_t audio_format; /* 音频格式 0X01:线性PCM 0X11:IMA ADPCM */
uint16_t channel_count; /* 通道数量 1表示单声道 2表示双声道 */
uint32_t sample_rate; /* 采样率 */
uint32_t byte_rate; /* 字节速率 */
uint16_t block_align; /* 块对齐(字节) */
uint16_t sample_size; /* 单个采样数据大小;4位ADPCM,设置为4 */
} audio_wav_fmt_chunk_t;
typedef struct __attribute__((packed)) { //通用的Chunk头定义 用于寻找"data"块
uint32_t chunk_id; /* ID:"data" 即0x61746164 */
uint32_t chunk_size; /* 子集合大小(不包括ID和Size) */
} audio_wav_hdr_chunk_t;
typedef struct {
uint16_t format; /* 音频格式 0X01表示线性PCM 0X11表示IMA ADPCM */
uint16_t channel_count; /* 通道数量 1表示单声道 2表示双声道 */
uint16_t block_align; /* 块对齐(字节) */
uint32_t bitrate; /* 比特率(位速) */
uint32_t sample_rate; /* 采样率 */
uint16_t sample_size; /* 位数 如16bit, 24bit, 32bit */
uint32_t data_offset; /* 数据帧开始的位置(在文件里面的偏移) */
} audio_wav_info_t;
static audio_hal_result_t audio_wav_get_info(FIL* file, audio_wav_info_t* wav_info)
{
if (wav_info == NULL) {
LOG_E("wav_info is null");
return audio_hal_invalid_argument;
}
memset(wav_info, 0, sizeof(audio_wav_info_t));
uint8_t read_buffer[sizeof(audio_wav_fmt_chunk_t)]; //最大的头类型
UINT br;
FRESULT f_result = f_lseek(file, 0); //定位到文件最开头
if (f_result != FR_OK) {
LOG_E("seeking file failed, error code=%d", f_result);
return audio_hal_error_read_file;
}
f_result = f_read(file, read_buffer, sizeof(audio_wav_riff_chunk_t), &br);
if (f_result != FR_OK) {
LOG_E("error while reading file, error code=%d", f_result);
return audio_hal_error_read_file;
}
audio_wav_riff_chunk_t *riff_chunk = (audio_wav_riff_chunk_t*)read_buffer; //RIFF块
if(riff_chunk->chunk_id != 0x46464952 || riff_chunk->format != 0x45564157) { //如果块ID不是RIFF或格式不是WAVE
LOG_E("RIFF chunk mismatch, file is not valid RIFF file");
return audio_hal_error_unsupported_format; //不是RIFF文件
}
uint32_t fptr = sizeof(audio_wav_riff_chunk_t); //跳过RIFF块 12bytes
f_result = f_lseek(file, fptr); //定位到fptr处
if (f_result != FR_OK) {
LOG_E("seeking file failed, error code=%d", f_result);
return audio_hal_error_read_file;
}
f_result = f_read(file, read_buffer, sizeof(audio_wav_fmt_chunk_t), &br);
if (f_result != FR_OK) {
LOG_E("error while reading file, error code=%d", f_result);
return audio_hal_error_read_file;
}
audio_wav_fmt_chunk_t *fmt_chunk = (audio_wav_fmt_chunk_t*)read_buffer; //FMT块
if(fmt_chunk->chunk_id != 0x20746D66) { //判断是否为FMT块
LOG_E("FMT chunk mismatch, file is not valid WAVE file");
return audio_hal_error_unsupported_format; //文件格式不是WAVE
}
wav_info->format = fmt_chunk->audio_format; //音频格式
wav_info->channel_count = fmt_chunk->channel_count; //通道数
wav_info->sample_rate = fmt_chunk->sample_rate; //采样率
wav_info->bitrate = fmt_chunk->byte_rate*8; //位速率是8倍的字节速率
wav_info->block_align = fmt_chunk->block_align; //块对齐
wav_info->sample_size = fmt_chunk->sample_size; //位数 16/24/32位
fptr += fmt_chunk->chunk_size + 8; //去掉FMTChunk的大小 注意chunk_size不包含ID和Size的大小
while(1) { //找到PCM数据的开始
f_result = f_lseek(file, fptr);
if (f_result != FR_OK) {
LOG_E("seeking file failed, error code=%d", f_result);
return audio_hal_error_read_file;
}
f_result = f_read(file, read_buffer, sizeof(audio_wav_hdr_chunk_t), &br);
if (f_result != FR_OK) {
LOG_E("error while reading file, error code=%d", f_result);
return audio_hal_error_read_file;
}
audio_wav_hdr_chunk_t *chunk_hdr = (audio_wav_hdr_chunk_t*)read_buffer;
if(chunk_hdr->chunk_id == 0x61746164) { //是"data"块
wav_info->data_offset = fptr + 8; //跳过Chunkt头
break;
}
fptr += chunk_hdr->chunk_size + 8; //继续寻找下一个Chunk
if(fptr > 4096) { //找了4k还没有找到
LOG_E("cannot find valid data chunk, file is not valid WAVE file");
return audio_hal_error_unsupported_format; //文件格式不是WAVE
}
}
return audio_hal_ok;
}
audio_hal_result_t audio_wav_play(const char* file_name, audio_hal_result_t (*playing_routine)(void))
{
audio_hal_result_t error_code = audio_hal_ok;
FIL *file = NULL;
file = tlsf_malloc(sizeof(FIL));
if (file == NULL) {
LOG_E("error while allocating memory for mp3 file");
error_code = audio_hal_error_insufficient_memory;
goto error;
}
FRESULT f_result = f_open(file, file_name, FA_READ);
if (f_result == FR_OK) {
LOG_I("open %s successful", file_name);
} else {
LOG_E("open %s failed, error code=%d", file_name, f_result);
error_code = audio_hal_error_open_file;
goto error;
}
audio_wav_info_t wav_info;
error_code = audio_wav_get_info(file, &wav_info); //获取文件信息
if(error_code != audio_hal_ok) {
LOG_E("error while getting wave file info of %s", file_name);
goto error;
}
if (wav_info.format == 0x01) { //音频格式不PCM
LOG_I("wave file format: PCM, bitrate: %dkbps", wav_info.bitrate / 1000);
} else {
LOG_E("format of wave file(0x%02X) is not supported", wav_info.format);
error_code = audio_hal_error_unsupported_parameter;
goto error;
}
/* 初始化Audio HAL */
error_code = audio_hal_start(AUDIO_WAV_FILE_BUFFER_SIZE / wav_info.channel_count / (wav_info.sample_size / 8),
wav_info.sample_size, wav_info.sample_rate, wav_info.channel_count);
if (error_code != audio_hal_ok) {
LOG_E("error while starting audio hal, error code=%d", error_code);
goto error;
}
f_result = f_lseek(file, wav_info.data_offset);
if (f_result != FR_OK) {
LOG_E("seeking file failed, error code=%d", f_result);
error_code = audio_hal_error_read_file;
goto error;
}
UINT br;
uint8_t paused = 0;
while(1) {
/* 执行播放中用户事件处理代码 */
if (playing_routine != NULL) {
error_code = playing_routine();
if (error_code == audio_hal_result_pause) {
paused = !paused;
if (paused != 0) {
audio_hal_pause();
LOG_D("play paused");
} else {
audio_hal_resume();
LOG_D("play resumed");
}
} else if (error_code != audio_hal_ok) {
LOG_W("user routine returned %d, exiting", error_code);
break;
}
}
if (paused) {
delay_ms(10);
continue;
}
/* 等待播放完成并获取空闲缓冲区 */
void *sample = audio_hal_get_free_buffer();
f_result = f_read(file, sample, AUDIO_WAV_FILE_BUFFER_SIZE, &br); //填充缓冲区
if (f_result != FR_OK) {
LOG_E("error while reading file, error code=%d", f_result);
error_code = audio_hal_error_read_file;
goto error;
}
audio_hal_dac_postprocess(sample);
if(br < AUDIO_WAV_FILE_BUFFER_SIZE) { //文件读取到末尾
LOG_I("play done");
break;
}
}
error:
audio_hal_stop();
if (file) {
f_close(file);
tlsf_free(file);
}
return error_code;
}