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