diff --git a/CMakeLists.txt b/CMakeLists.txt index e98755d..83876ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE freertos easylogger fatfs - FLAC + dr_lib # lvgl # lvgl_demos minimp3 diff --git a/Middlewares/CMakeLists.txt b/Middlewares/CMakeLists.txt index 80035d9..fa36009 100644 --- a/Middlewares/CMakeLists.txt +++ b/Middlewares/CMakeLists.txt @@ -5,26 +5,27 @@ project(middlewares) add_subdirectory(Third_Party/freertos) add_subdirectory(Third_Party/easylogger) add_subdirectory(Third_Party/fatfs) -add_subdirectory(Third_Party/flac) -add_subdirectory(Third_Party/lvgl) +# add_subdirectory(Third_Party/flac) +# add_subdirectory(Third_Party/lvgl) +add_subdirectory(Third_Party/dr_lib) add_subdirectory(Third_Party/minimp3) add_subdirectory(Third_Party/tlsf) # 屏蔽第三方库中的警告 -target_compile_options(FLAC PRIVATE - -Wformat=0 - -Wno-incompatible-pointer-types -) +# target_compile_options(FLAC PRIVATE +# -Wformat=0 +# -Wno-incompatible-pointer-types +# ) -target_compile_options(grabbag PRIVATE - -Wformat=0 -) +# target_compile_options(grabbag PRIVATE +# -Wformat=0 +# ) -target_compile_options(lvgl_demos PRIVATE - -Wformat=0 -) +# target_compile_options(lvgl_demos PRIVATE +# -Wformat=0 +# ) -target_compile_options(lvgl_examples PRIVATE - -Wformat=0 - -Wno-unused-variable -) +# target_compile_options(lvgl_examples PRIVATE +# -Wformat=0 +# -Wno-unused-variable +# ) diff --git a/User/audio/audio_flac.c b/User/audio/audio_flac.c new file mode 100644 index 0000000..0248f07 --- /dev/null +++ b/User/audio/audio_flac.c @@ -0,0 +1,159 @@ +#include "audio_flac.h" +#include "main.h" +#include "ff.h" +#include "FreeRTOS.h" +#include "queue.h" +#include "elog.h" +#include "heap.h" + +#define DR_FLAC_IMPLEMENTATION +#include "dr_flac.h" + +const static char *TAG = "audio_flac"; + +static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + HAL_GPIO_TogglePin(LED_Y_GPIO_Port, LED_Y_Pin); + + UINT br; + FRESULT f_result = f_read(pUserData, pBufferOut, bytesToRead, &br); //从文件中读取新的内容 + + elog_verbose(TAG, "flac_read: reading %d bytes, %d bytes read", bytesToRead, br); + + if (f_result != FR_OK) { + elog_error(TAG, "file read error"); + return 0; + } + + return br; +} + +static drflac_bool32 flac_seek(void* pUserData, int offset, drflac_seek_origin origin) +{ + FIL *file = (FIL*)pUserData; + HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin); + + if (origin == drflac_seek_origin_start) { + f_lseek(file, offset); + elog_debug(TAG, "flac_seek: drflac_seek_origin_start, offset=%d, fptr=%d", offset, f_tell(file)); + } else { + uint32_t fptr = f_tell(file); + if (fptr + offset > f_size(file)) { + elog_warn(TAG, "flac_seek: seeking beyond the end of the file"); + return false; + } + f_lseek(file, fptr + offset); + elog_debug(TAG, "flac_seek: drflac_seek_origin_current, offset=%d, fptr original=%d, fptr=%d", offset, fptr, f_tell((FIL*)pUserData)); + } + + return true; +} + +void* flac_malloc(size_t sz, void* pUserData) +{ + UNUSED(pUserData); + + void *ptr = malloc(sz); + + elog_warn(TAG, "flac_malloc: %d bytes", sz); + tlsf_pool_statistics *dtcm_heap_statistics = get_dtcm_heap_statistics(); + tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics(); + elog_verbose(TAG, "free heap: DTCM: %d, AXI: %d", dtcm_heap_statistics->free_size, ahb_heap_statistics->free_size); + + return ptr; +} +void* flac_realloc(void* p, size_t sz, void* pUserData) +{ + UNUSED(pUserData); + + void *ptr = realloc(p, sz); + + elog_warn(TAG, "flac_realloc: %d bytes", sz); + return ptr; +} + +void flac_free(void* p, void* pUserData) +{ + UNUSED(pUserData); + + elog_warn(TAG, "flac_free"); + free(p); +} + +static const drflac_allocation_callbacks callbacks = { + .onMalloc = flac_malloc, + .onFree = flac_free, + .onRealloc = flac_realloc, + .pUserData = NULL +}; + +// static void flac_on_meta(void* pUserData, drflac_metadata* pMetadata) +// { +// elog_warn(TAG, "on metadata %d", pMetadata->type); +// } + +void music_flac_play(const char *file_name) +{ + FIL *file = malloc(sizeof(FIL)); + if (file == NULL) { + elog_error(TAG, "error while allocating file object"); + return; + } + + FRESULT f_result = f_open(file, file_name, FA_READ); + if (f_result == FR_OK) { + elog_info(TAG, "successfully opened %s for playing", file_name); + } else { + elog_error(TAG, "error while opening %s, error code=%d", file_name, f_result); + free(file); + return; + } + + /* 创建并初始化解码器 */ + // drflac* pFlac = drflac_open_with_metadata(flac_read, flac_seek, flac_on_meta, file, NULL); + drflac* pFlac = drflac_open(flac_read, flac_seek, file, &callbacks); + if (pFlac == NULL) { + elog_error(TAG, "error while creating opening flac file"); + goto exit; + } + + /* 初始化SAI */ + uint32_t frame_pcm_size = pFlac->maxBlockSizeInPCMFrames * pFlac->channels; + audio_hal_start(frame_pcm_size, pFlac->bitsPerSample / 8); + + elog_info(TAG, "start playing"); + + while(1) { + /* 解码新一帧FLAC数据 */ + drflac_int16 *sample = malloc(frame_pcm_size * (pFlac->bitsPerSample / 8)); + if (sample == NULL) { + elog_error(TAG, "memory allocation failed"); + goto exit; + } + uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, frame_pcm_size, sample); + /* 将解码后的PCM数据写入SAI */ + if (frame_count != 0) { + // elog_verbose(TAG, "writing %d bytes of pcm data", frame_count * sizeof(drflac_int16)); + audio_hal_write(sample, frame_count * pFlac->channels); + } else { //文件已经读取完毕 + free(sample); + elog_info(TAG, "play done"); + break; //结束播放 + } + } + + audio_hal_stop(); + + /* 关闭文件 */ + f_close(file); + free(file); + +exit: + if (pFlac) { + drflac_close(pFlac); + } + + tlsf_pool_statistics *dtcm_heap_statistics = get_dtcm_heap_statistics(); + tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics(); + elog_verbose(TAG, "free heap: DTCM: %d, AXI: %d", dtcm_heap_statistics->free_size, ahb_heap_statistics->free_size); +} diff --git a/User/audio/audio_flac.h b/User/audio/audio_flac.h new file mode 100644 index 0000000..d25fdd5 --- /dev/null +++ b/User/audio/audio_flac.h @@ -0,0 +1,8 @@ +#ifndef __AUDIO_FLAC_H +#define __AUDIO_FLAC_H + +#include "audio_hal.h" + +void music_flac_play(const char *file_name); + +#endif diff --git a/User/audio/audio_hal.h b/User/audio/audio_hal.h index a06c983..dec380b 100644 --- a/User/audio/audio_hal.h +++ b/User/audio/audio_hal.h @@ -3,7 +3,7 @@ #include "main.h" -#define AUDIO_HAL_SAMPLE_QUEUE_SIZE 5 +#define AUDIO_HAL_SAMPLE_QUEUE_SIZE 3 void audio_hal_start(uint32_t sample_count, uint8_t sample_size); void audio_hal_stop(void); diff --git a/User/tasks/task_main.c b/User/tasks/task_main.c index ac39655..3289ccd 100644 --- a/User/tasks/task_main.c +++ b/User/tasks/task_main.c @@ -8,6 +8,7 @@ #include "main.h" #include "ff.h" #include "audio_player_mp3.h" +#include "audio_flac.h" #include "bsp_aic3204.h" // #include "lvgl.h" // #include "lv_demos.h" @@ -151,6 +152,7 @@ void task_main_entry(void *param) util_i2c_scan(&hi2c1); while (1) { + music_flac_play("四季音色 - 斑光.flac"); music_mp3_play("夏川椎菜 - No.1.mp3"); music_mp3_play("HoneyWorks,早見沙織 - 可愛くてごめん.mp3"); music_mp3_play("堀江由衣 - silky heart.mp3");