#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; }