From ace169decb0e905bb5ba161a4f14e3ad4c13671b Mon Sep 17 00:00:00 2001 From: wangyz1997 Date: Tue, 9 Apr 2024 19:25:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dflac=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- User/audio/audio_flac.c | 118 +++++++++++++++++++++++----------------- User/audio/audio_hal.c | 13 ++++- User/tasks/task_main.c | 4 +- 3 files changed, 81 insertions(+), 54 deletions(-) diff --git a/User/audio/audio_flac.c b/User/audio/audio_flac.c index b52a484..3d6baf8 100644 --- a/User/audio/audio_flac.c +++ b/User/audio/audio_flac.c @@ -5,6 +5,7 @@ #include "queue.h" #include "elog.h" #include "heap.h" +#include "bsp_aic3204.h" #define DR_FLAC_NO_STDIO #define DR_FLAC_NO_OGG @@ -21,8 +22,6 @@ static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead) 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; @@ -34,52 +33,67 @@ static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead) static drflac_bool32 flac_seek(void* pUserData, int offset, drflac_seek_origin origin) { FIL *file = (FIL*)pUserData; + uint32_t fptr = f_tell(file); + uint32_t fsize = f_size(file); + 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)) { + switch (origin) { + case drflac_seek_origin_start: + if (offset < fsize) { //未超过文件末尾 + f_lseek(file, offset); + return DRFLAC_TRUE; + } else { elog_warn(TAG, "flac_seek: seeking beyond the end of the file"); - return false; + return DRFLAC_FALSE; + } + case drflac_seek_origin_current: + if (fptr + offset < fsize) { //未超过文件末尾 + f_lseek(file, fptr + offset); + return DRFLAC_TRUE; + } else { + elog_warn(TAG, "flac_seek: seeking beyond the end of the file"); + return DRFLAC_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; + default: + elog_warn(TAG, "flac_seek: unimplemented seek origin type: %d", origin); + return DRFLAC_FALSE; + } } -void* flac_malloc(size_t sz, void* pUserData) +static 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 *axi_heap_statistics = get_axi_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); + elog_debug(TAG, "flac_malloc: allocated %d bytes memory @%p, free memory: AXI %d bytes, AHB %d bytes", + sz, ptr, axi_heap_statistics->free_size, ahb_heap_statistics->free_size); return ptr; } -void* flac_realloc(void* p, size_t sz, void* pUserData) + +static 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) +static void flac_free(void* p, void* pUserData) { UNUSED(pUserData); - elog_warn(TAG, "flac_free"); + tlsf_pool_statistics *axi_heap_statistics = get_axi_heap_statistics(); + tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics(); + elog_debug(TAG, "flac_free: memory freed @%p, free memory: AXI %d bytes, AHB %d bytes", + p, axi_heap_statistics->free_size, ahb_heap_statistics->free_size); + free(p); } @@ -90,11 +104,6 @@ static const drflac_allocation_callbacks callbacks = { .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)); @@ -113,52 +122,61 @@ void music_flac_play(const char *file_name) } /* 创建并初始化解码器 */ - // 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 pcm_sample_count = pFlac->maxBlockSizeInPCMFrames * pFlac->channels; //每一个PCM块的采样数量 - audio_hal_start(pcm_sample_count, pFlac->bitsPerSample / 8); - elog_info(TAG, "music_flac_play: maxBlockSizeInPCMFrames=%d, channels=%d, bitsPerSample=%d", pFlac->maxBlockSizeInPCMFrames, pFlac->channels, pFlac->bitsPerSample); + /* TODO: 判断flac文件参数并返回错误 */ + + bsp_aic3204_set_fs(&hi2c1, pFlac->sampleRate); //设置采样率 + + /* 初始化SAI */ + uint32_t pcm_sample_count = pFlac->maxBlockSizeInPCMFrames * pFlac->channels; //PCM块中所有声道总的采样数量 + uint32_t pcm_sample_size = pFlac->bitsPerSample / 8; //PCM块中每个采样的字节数(采样精度) + audio_hal_start(pcm_sample_count, pcm_sample_size); + while(1) { - drflac_int16 *sample = malloc(pcm_sample_count * (pFlac->bitsPerSample / 8)); - if (sample == NULL) { - elog_error(TAG, "%d bytes memory allocation failed", pcm_sample_count * (pFlac->bitsPerSample / 8)); + /* 如果当前是最后一个frame 则frame_count可能小于maxBlockSizeInPCMFrames 因此需要将pcm_sample初始化为全0 将空白区域静音 */ + drflac_int16 *pcm_sample = malloc(pcm_sample_count * pcm_sample_size); //申请内存 存储1个PCM块 + if (pcm_sample == NULL) { + elog_error(TAG, "memory allocation failed, size=%d bytes", pcm_sample_count * pcm_sample_size); break; } - /* 解码新一帧FLAC数据 */ - uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, pFlac->maxBlockSizeInPCMFrames, sample); + memset(pcm_sample, 0, pcm_sample_count * pcm_sample_size); + + /* 此处的framesToRead指的是PCM块中采样的数量(可以理解为时间层面的采样数) 不考虑声道数量与每个采样的字节数 */ + uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, pFlac->maxBlockSizeInPCMFrames, pcm_sample); //解码一帧FLAC数据 - /* 将解码后的PCM数据写入SAI */ if (frame_count != 0) { - elog_verbose(TAG, "writing %d bytes of pcm data", frame_count * sizeof(drflac_int16)); - audio_hal_write(sample, pcm_sample_count * pFlac->channels); + /* 即使frame_count小于maxBlockSizeInPCMFrames也写入完整的一块 缓冲区后面空缺的部分在前面已经清0 */ + audio_hal_write(pcm_sample, pcm_sample_count * pcm_sample_size); //将解码后的PCM数据写入SAI } else { //文件已经读取完毕 - free(sample); + free(pcm_sample); elog_info(TAG, "play done"); break; //结束播放 } - } - /* 关闭文件 */ - f_close(file); - free(file); + 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; + } + } exit: - audio_hal_stop(); + audio_hal_stop(); //停止SAI播放 - if (pFlac) { + f_close(file); //关闭文件 + free(file); + + 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_hal.c b/User/audio/audio_hal.c index 07e92d9..0b5c5c7 100644 --- a/User/audio/audio_hal.c +++ b/User/audio/audio_hal.c @@ -16,6 +16,7 @@ typedef struct { static QueueHandle_t audio_queue = NULL; static uint8_t *audio_buffer = NULL; static uint32_t audio_buffer_length = 0; +static uint8_t audio_buffer_underrun_warn_flag = 0; void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) { @@ -63,6 +64,7 @@ void audio_hal_start(uint32_t sample_count, uint8_t sample_size) vQueueDelete(audio_queue); } audio_queue = xQueueCreate(AUDIO_HAL_SAMPLE_QUEUE_SIZE, sizeof(audio_sample_t)); + audio_buffer_underrun_warn_flag = 0; HAL_SAI_Transmit_DMA(&hsai_BlockB1, audio_buffer, sample_count * 2); //开始DMA循环发送 } @@ -71,6 +73,12 @@ void audio_hal_stop(void) { HAL_SAI_DMAStop(&hsai_BlockB1); + audio_sample_t sample; + while (xQueueReceive(audio_queue, &sample, 0) == pdTRUE) { + free(sample.buffer_ptr); + elog_debug(TAG, "audio_hal_stop: freeing unused buffer"); + } + vQueueDelete(audio_queue); audio_queue = NULL; @@ -89,9 +97,10 @@ void audio_hal_write(void *buffer_ptr, uint32_t buffer_size) .buffer_size = buffer_size }; - if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE) { - elog_warn(TAG, "audio_hal_write: queue is empty before xQueueSend"); + if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE && audio_buffer_underrun_warn_flag != 0) { + elog_warn(TAG, "audio_hal_write: audio sample queue is empty before xQueueSend"); } xQueueSend(audio_queue, &sample, portMAX_DELAY); //发送缓冲区到队列中 + audio_buffer_underrun_warn_flag = 1; //屏蔽首次报错 } diff --git a/User/tasks/task_main.c b/User/tasks/task_main.c index 317567d..1cc8f8f 100644 --- a/User/tasks/task_main.c +++ b/User/tasks/task_main.c @@ -152,11 +152,11 @@ void task_main_entry(void *param) util_i2c_scan(&hi2c1); while (1) { + music_flac_play("HOYO-MiX - Village Surrounded by Green 葳蕤林野间.flac"); music_flac_play("四季音色 - 斑光.flac"); music_flac_play("唐九夏 - 一克拉月光.flac"); - music_mp3_play("夏川椎菜 - No.1.mp3"); music_mp3_play("HoneyWorks,早見沙織 - 可愛くてごめん.mp3"); - music_mp3_play("堀江由衣 - silky heart.mp3"); + music_mp3_play("倉木麻衣 - Time after time〜花舞う街で〜.mp3"); music_mp3_play("Candy_Wind - Go For The Next !.mp3"); music_mp3_play("July - Somewhere.mp3"); music_mp3_play("Wiz Khalifa; Charlie Puth - See You Again.mp3");