stm32h743_player/User/audio/audio_flac.c

165 lines
4.7 KiB
C

#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_NO_STDIO
#define DR_FLAC_NO_OGG
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_BUFFER_SIZE 16384
#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 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);
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));
break;
}
/* 解码新一帧FLAC数据 */
uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, pFlac->maxBlockSizeInPCMFrames, 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, pcm_sample_count * pFlac->channels);
} else { //文件已经读取完毕
free(sample);
elog_info(TAG, "play done");
break; //结束播放
}
}
/* 关闭文件 */
f_close(file);
free(file);
exit:
audio_hal_stop();
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);
}