156 lines
4.4 KiB
C
156 lines
4.4 KiB
C
#include "audio_player_mp3.h"
|
|
#include <stdio.h>
|
|
#include "main.h"
|
|
#include "ff.h"
|
|
#include "FreeRTOS.h"
|
|
#include "queue.h"
|
|
#include "elog.h"
|
|
#include "heap.h"
|
|
#include "bsp_aic3204.h"
|
|
|
|
#define MINIMP3_IMPLEMENTATION
|
|
#include "minimp3.h"
|
|
|
|
const static char *TAG = "player_mp3";
|
|
|
|
/**
|
|
* @brief 播放MP3文件
|
|
*
|
|
* @param file_name 文件路径
|
|
* @return esp_err_t 错误代码
|
|
*
|
|
* @note 本函数需要至少25600字节任务栈空间
|
|
*/
|
|
void music_mp3_play(const char *file_name)
|
|
{
|
|
FIL *file = malloc(sizeof(FIL));
|
|
uint8_t *file_buffer = malloc(FILE_BUFFER_SIZE);
|
|
|
|
FRESULT f_result = f_open(file, file_name, FA_READ);
|
|
if (f_result == FR_OK) {
|
|
elog_info(TAG, "open %s successful", file_name);
|
|
} else {
|
|
elog_error(TAG, "open %s failed, error code: %d", file_name, f_result);
|
|
return;
|
|
}
|
|
|
|
/* 创建并初始化解码器 */
|
|
mp3dec_t mp3d; //6668 bytes
|
|
mp3dec_init(&mp3d);
|
|
/* 初始化SAI */
|
|
audio_hal_start(MINIMP3_MAX_SAMPLES_PER_FRAME, sizeof(mp3d_sample_t));
|
|
|
|
int32_t file_buffer_available = 0; //剩余的缓冲区大小
|
|
while(1) {
|
|
/* 从文件中补充数据到缓冲区 */
|
|
if(file_buffer_available < FILE_BUFFER_SIZE/2) { //文件缓冲区剩余不足一半
|
|
int32_t file_buffer_consumed = (FILE_BUFFER_SIZE - file_buffer_available);
|
|
UINT br;
|
|
|
|
f_result = f_read(file, file_buffer+file_buffer_available, file_buffer_consumed, &br); //从文件中读取新的内容
|
|
if (f_result != FR_OK) {
|
|
elog_error(TAG, "file read error");
|
|
break;
|
|
}
|
|
file_buffer_available += br;
|
|
|
|
// uint32_t bytes_read = file_buffer_consumed + file_buffer_available - FILE_BUFFER_SIZE;
|
|
// if (bytes_read > 0) {
|
|
// elog_verbose(TAG, "reading %d bytes from file", (int)bytes_read);
|
|
// }
|
|
HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin);
|
|
|
|
if(file_buffer_available <= 0) { //文件已经读取完毕
|
|
elog_info(TAG, "play done");
|
|
break; //结束播放
|
|
}
|
|
}
|
|
|
|
/* 解码新一帧MP3数据 */
|
|
mp3dec_frame_info_t info;
|
|
mp3d_sample_t *sample = malloc(MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t));
|
|
uint32_t sample_count = mp3dec_decode_frame(&mp3d, file_buffer, file_buffer_available, sample, &info);
|
|
/* 将解码后的PCM数据写入SAI */
|
|
if (sample_count != 0) {
|
|
audio_hal_write(sample, sample_count * 2 * sizeof(mp3d_sample_t)); //sample_count只包含一个声道的采样数
|
|
} else {
|
|
free(sample);
|
|
}
|
|
/* 从缓冲区中删除解码完毕的帧 */
|
|
file_buffer_available -= info.frame_bytes; //从剩余缓冲区大小中减去被消耗的缓冲区大小
|
|
memmove(file_buffer, file_buffer+info.frame_bytes, file_buffer_available); //删除已消耗的缓冲区内容
|
|
|
|
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) {
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
while (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) {
|
|
vTaskDelay(pdMS_TO_TICKS(1));
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
static uint8_t samplerate = 0;
|
|
|
|
switch (samplerate) {
|
|
case 0:
|
|
bsp_aic3204_set_fs(&hi2c1, 8000);
|
|
break;
|
|
case 1:
|
|
bsp_aic3204_set_fs(&hi2c1, 11025);
|
|
break;
|
|
case 2:
|
|
bsp_aic3204_set_fs(&hi2c1, 12000);
|
|
break;
|
|
case 3:
|
|
bsp_aic3204_set_fs(&hi2c1, 16000);
|
|
break;
|
|
case 4:
|
|
bsp_aic3204_set_fs(&hi2c1, 22050);
|
|
break;
|
|
case 5:
|
|
bsp_aic3204_set_fs(&hi2c1, 24000);
|
|
break;
|
|
case 6:
|
|
bsp_aic3204_set_fs(&hi2c1, 32000);
|
|
break;
|
|
case 7:
|
|
bsp_aic3204_set_fs(&hi2c1, 44100);
|
|
break;
|
|
case 8:
|
|
bsp_aic3204_set_fs(&hi2c1, 48000);
|
|
break;
|
|
case 9:
|
|
bsp_aic3204_set_fs(&hi2c1, 88200);
|
|
break;
|
|
case 10:
|
|
bsp_aic3204_set_fs(&hi2c1, 96000);
|
|
break;
|
|
case 11:
|
|
bsp_aic3204_set_fs(&hi2c1, 176400);
|
|
break;
|
|
case 12:
|
|
bsp_aic3204_set_fs(&hi2c1, 192000);
|
|
break;
|
|
}
|
|
|
|
samplerate ++;
|
|
if (samplerate >= 13) {
|
|
samplerate = 0;
|
|
}
|
|
|
|
while (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
|
|
vTaskDelay(pdMS_TO_TICKS(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 关闭文件 */
|
|
audio_hal_stop();
|
|
f_close(file);
|
|
free(file_buffer);
|
|
free(file);
|
|
// size_t free_heap = xPortGetFreeHeapSize();
|
|
// elog_verbose(TAG, "free heap: %d", free_heap);
|
|
}
|