232 lines
6.6 KiB
C
232 lines
6.6 KiB
C
#include "audio_player.h"
|
|
#include <stdlib.h>
|
|
#include "debug.h"
|
|
#include "bsp_key.h"
|
|
#include "bsp_led.h"
|
|
#include "ff.h"
|
|
#include "tlsf.h"
|
|
|
|
#define AUDIO_PLAYER_MUSIC_FILE_LIST_MAX 600 //最大音频文件数量
|
|
#define AUDIO_PLAYER_MUSIC_FILE_NAME_LENGTH 13 //FAT32中短文件名占用13字节
|
|
#define AUDIO_PLAYER_MUSIC_DEFAULT_DIR "" //默认音频文件存储目录
|
|
|
|
static const char* audio_player_music_ext_names[] = {"MP3", "WAV", ""};
|
|
|
|
typedef enum {
|
|
audio_player_mode_normal, //顺序播放
|
|
audio_player_mode_single_repeat, //单曲循环
|
|
} audio_player_mode_e;
|
|
|
|
audio_hal_result_t audio_player_playing_routine(void)
|
|
{
|
|
bsp_key_event_e key_event = bsp_key_get_event();
|
|
|
|
switch (key_event){
|
|
case bsp_key_none:
|
|
return audio_hal_ok;
|
|
|
|
case bsp_key_next_short:
|
|
return audio_hal_result_next;
|
|
|
|
case bsp_key_prev_short:
|
|
return audio_hal_result_prev;
|
|
|
|
case bsp_key_pause_short:
|
|
return audio_hal_ok;
|
|
|
|
case bsp_key_next_long:
|
|
return audio_hal_result_random;
|
|
|
|
case bsp_key_prev_long:
|
|
return audio_hal_result_repeat;
|
|
|
|
default:
|
|
LOG_W("unhandled key event: %s", bsp_key_get_event_string(key_event));
|
|
}
|
|
|
|
return audio_hal_ok;
|
|
}
|
|
|
|
audio_hal_result_t audio_player_play_file(const char *path)
|
|
{
|
|
char* ext_name = strrchr(path, '.') + 1; //指针定位到扩展名
|
|
|
|
if(!strcasecmp(ext_name, "MP3")) {
|
|
return audio_mp3_play(path, audio_player_playing_routine);
|
|
// } else if(!strcasecmp(ext_name, "WAV")) {
|
|
// return audio_wav_play(path, audio_player_playing_routine);
|
|
}
|
|
|
|
LOG_W("unknown file format \"%s\" of %s", ext_name, path);
|
|
return audio_hal_error_unsupported_format;
|
|
}
|
|
|
|
bool audio_player_check_file_ext(const char* path, const char** ext_table)
|
|
{
|
|
char* ext_name = strrchr(path,'.') + 1; //指针定位到扩展名
|
|
|
|
if(ext_name == NULL) { //不存在扩展名
|
|
return false;
|
|
}
|
|
|
|
if(ext_table[0][0] == '\0') {
|
|
return true;//未指定扩展名 均返回真
|
|
}
|
|
|
|
uint8_t i = 0;
|
|
while(ext_table[i][0] != '\0') { //以此检查是否与每个扩展名匹配
|
|
if(!strcasecmp(ext_name, ext_table[i])) {
|
|
return true;
|
|
}
|
|
|
|
i ++;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32_t audio_player_search_file(const char* music_dir, char *file_list)
|
|
{
|
|
uint16_t file_count = 0;
|
|
|
|
DIR dir;
|
|
FRESULT f_result = f_opendir(&dir, music_dir);
|
|
if (f_result != FR_OK) {
|
|
LOG_E("error while reading directory, error code=%d", f_result);
|
|
return 0;
|
|
}
|
|
|
|
while (1) {
|
|
FILINFO fileinfo;
|
|
f_result = f_readdir(&dir, &fileinfo);
|
|
if (f_result != FR_OK) {
|
|
LOG_E("error while reading directory, error code=%d", f_result);
|
|
break;
|
|
}
|
|
|
|
if (fileinfo.fname[0] == '\0') { //文件夹遍历完毕
|
|
LOG_I("%d files saved in list", file_count);
|
|
break;
|
|
}
|
|
|
|
if(audio_player_check_file_ext(fileinfo.fname, audio_player_music_ext_names) == 0) { //不受支持的文件类型
|
|
continue;
|
|
}
|
|
|
|
if(fileinfo.fattrib & AM_DIR) { //是一个目录
|
|
continue;
|
|
}
|
|
|
|
if (file_list != NULL) { //如果指针非空 则复制到文件列表中
|
|
strcpy(file_list + file_count * AUDIO_PLAYER_MUSIC_FILE_NAME_LENGTH, fileinfo.fname);
|
|
}
|
|
|
|
file_count ++;
|
|
if (file_count >= AUDIO_PLAYER_MUSIC_FILE_LIST_MAX) {
|
|
LOG_W("more than %d files are found, discarding more files", AUDIO_PLAYER_MUSIC_FILE_LIST_MAX);
|
|
break;
|
|
}
|
|
}
|
|
|
|
f_result = f_closedir(&dir);
|
|
if (f_result != FR_OK) {
|
|
LOG_E("error while closing directory, error code=%d", f_result);
|
|
}
|
|
|
|
return file_count;
|
|
}
|
|
|
|
void audio_player(void)
|
|
{
|
|
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_RNG, ENABLE);
|
|
RNG_Cmd(ENABLE);
|
|
|
|
uint32_t current_file_index = 0;
|
|
uint32_t audio_file_count = audio_player_search_file(AUDIO_PLAYER_MUSIC_DEFAULT_DIR, NULL); //首先搜索音频文件数
|
|
if (audio_file_count == 0) {
|
|
LOG_E("error while searching for music files");
|
|
return;
|
|
}
|
|
|
|
LOG_D("allocating %d bytes of memory for music file list", audio_file_count * AUDIO_PLAYER_MUSIC_FILE_NAME_LENGTH);
|
|
char *audio_file_list = tlsf_malloc(audio_file_count * AUDIO_PLAYER_MUSIC_FILE_NAME_LENGTH); //为文件列表申请内存
|
|
if (audio_file_list == NULL) {
|
|
LOG_E("error while allocating memory for music file list");
|
|
return;
|
|
}
|
|
|
|
audio_player_search_file(AUDIO_PLAYER_MUSIC_DEFAULT_DIR, audio_file_list); //然后将文件名保存到列表中
|
|
|
|
uint8_t switch_direction = 1; //1为下一首 0为上一首
|
|
while(1) {
|
|
char dir[20];
|
|
sprintf(dir, AUDIO_PLAYER_MUSIC_DEFAULT_DIR "/%s", audio_file_list + current_file_index * AUDIO_PLAYER_MUSIC_FILE_NAME_LENGTH);
|
|
|
|
LOG_D("index of playing file: %d, total files: %d", current_file_index+1, audio_file_count);
|
|
audio_hal_result_t play_result = audio_player_play_file(dir);
|
|
|
|
switch (play_result)
|
|
{
|
|
case audio_hal_error_open_file:
|
|
case audio_hal_error_read_file: //文件系统错误
|
|
goto error;
|
|
|
|
case audio_hal_error_insufficient_memory: //无法恢复的错误
|
|
LOG_E("unrecoverable error, resetting system");
|
|
NVIC_SystemReset();
|
|
break;
|
|
|
|
case audio_hal_error_unsupported_format:
|
|
case audio_hal_error_unsupported_parameter: //文件不支持
|
|
if (switch_direction == 1) { //上次切换方向是下一曲
|
|
goto next_file;
|
|
} else {
|
|
goto prev_file;
|
|
}
|
|
break;
|
|
|
|
case audio_hal_result_repeat: //重复播放当前文件
|
|
break;
|
|
|
|
case audio_hal_ok: //正常播放完成
|
|
case audio_hal_result_next:
|
|
next_file:
|
|
switch_direction = 1;
|
|
current_file_index ++;
|
|
if(current_file_index >= audio_file_count) {
|
|
current_file_index = 0;
|
|
}
|
|
break;
|
|
|
|
case audio_hal_result_prev:
|
|
prev_file:
|
|
switch_direction = 0;
|
|
if(current_file_index != 0) {
|
|
current_file_index --;
|
|
} else {
|
|
current_file_index = audio_file_count - 1;
|
|
}
|
|
break;
|
|
|
|
case audio_hal_result_random:
|
|
uint32_t new_file_index = RNG_GetRandomNumber() % audio_file_count;
|
|
if (new_file_index > current_file_index) {
|
|
switch_direction = 1;
|
|
} else {
|
|
switch_direction = 0;
|
|
}
|
|
current_file_index = new_file_index;
|
|
break;
|
|
|
|
default:
|
|
LOG_W("unhandled play result: %d", play_result);
|
|
break;
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (audio_file_list != NULL) {
|
|
tlsf_free(audio_file_list);
|
|
}
|
|
}
|