#include "test_demo.h" #include "ff_stdio.h" #include "board.h" #include "audio/audio.h" #include "romfile.h" #ifdef AUDIO_REPLAY #if REPLAY_TEST #define ROMFILE_ADUIO #define BUFSZ 4096 struct RIFF_HEADER_DEF { char riff_id[4]; // 'R','I','F','F' uint32_t riff_size; char riff_format[4]; // 'W','A','V','E' }; struct WAVE_FORMAT_DEF { uint16_t FormatTag; uint16_t Channels; uint32_t SamplesPerSec; uint32_t AvgBytesPerSec; uint16_t BlockAlign; uint16_t BitsPerSample; }; struct FMT_BLOCK_DEF { char fmt_id[4]; // 'f','m','t',' ' uint32_t fmt_size; struct WAVE_FORMAT_DEF wav_format; }; struct DATA_BLOCK_DEF { char data_id[4]; // 'R','I','F','F' uint32_t data_size; }; struct wav_info { struct RIFF_HEADER_DEF header; struct FMT_BLOCK_DEF fmt_block; struct DATA_BLOCK_DEF data_block; }; /* Parse wav file header info */ static int wavplay_parse_header(void *file, struct wav_info *info) { int max_sub_chunk = 8; #ifdef ROMFILE_ADUIO if (RomFileRead((RomFile *)file, &(info->header), sizeof(struct RIFF_HEADER_DEF)) <= 0) goto __exit; /* seek to fmt sub-chunk(Drop other sub-chunk in front of fmt chunk) */ while(1) { if (RomFileRead((RomFile *)file, &(info->fmt_block), sizeof(struct FMT_BLOCK_DEF)) <= 0) goto __exit; if(memcmp(info->fmt_block.fmt_id, "fmt ", 4) == 0) break; /* "fmt " sub-chunk fond */ /* sub-chunk "fmt " not fond, seek to the next sub-chunk */ RomFileSeek((RomFile *)file, info->fmt_block.fmt_size - sizeof(struct WAVE_FORMAT_DEF), SEEK_CUR); /* timeout */ if(max_sub_chunk-- <= 0) goto __exit; }; if (info->fmt_block.fmt_size > sizeof(struct WAVE_FORMAT_DEF)) RomFileSeek((RomFile *)file, info->fmt_block.fmt_size - sizeof(struct WAVE_FORMAT_DEF), SEEK_CUR); max_sub_chunk = 8; while(1) { if (RomFileRead((RomFile *)file, &(info->data_block), sizeof(struct DATA_BLOCK_DEF)) <= 0) goto __exit; if(memcmp(info->data_block.data_id, "data", 4) == 0) break; /* "data" sub-chunk fond */ /* sub-chunk "data" not fond, seek to the next sub-chunk */ RomFileSeek((RomFile *)file, info->data_block.data_size, SEEK_CUR); /* timeout */ if(max_sub_chunk-- <= 0) goto __exit; }; #else if (ff_fread(&(info->header), sizeof(struct RIFF_HEADER_DEF), 1, (FF_FILE *)file) <= 0) goto __exit; /* seek to fmt sub-chunk(Drop other sub-chunk in front of fmt chunk) */ while(1) { if (ff_fread(&(info->fmt_block), sizeof(struct FMT_BLOCK_DEF), 1, (FF_FILE *)file) <= 0) goto __exit; if(memcmp(info->fmt_block.fmt_id, "fmt ", 4) == 0) break; // "fmt " sub-chunk fond. /* sub-chunk "fmt " not fond, seek to the next sub-chunk */ ff_fseek((FF_FILE *)file, info->fmt_block.fmt_size - sizeof(struct WAVE_FORMAT_DEF), FF_SEEK_CUR); /* timeout */ if(max_sub_chunk-- <= 0) goto __exit; }; if (info->fmt_block.fmt_size > sizeof(struct WAVE_FORMAT_DEF)) ff_fseek((FF_FILE *)file, info->fmt_block.fmt_size - sizeof(struct WAVE_FORMAT_DEF), FF_SEEK_CUR); max_sub_chunk = 8; while(1) { if (ff_fread(&(info->data_block), sizeof(struct DATA_BLOCK_DEF), 1, (FF_FILE *)file) <= 0) goto __exit; if(memcmp(info->data_block.data_id, "data", 4) == 0) break; // "data" sub-chunk fond. /* sub-chunk "fmt " not fond, seek to the next sub-chunk */ ff_fseek((FF_FILE *)file, info->data_block.data_size, FF_SEEK_CUR); /* timeout */ if(max_sub_chunk-- <= 0) goto __exit; }; #endif return 0; __exit: printf("%s fail.\n", __func__); return -1; } static void wavplay_thread(void *para) { #ifdef ROMFILE_ADUIO RomFile *file = NULL; #else FF_FILE *file = NULL; #endif uint8_t *buffer = NULL; struct wav_info *info = NULL; struct audio_caps caps = {0}; struct audio_device *audio; int data_size; #ifdef ROMFILE_ADUIO file = RomFileOpen("audio/sin1K.wav"); #else file = ff_fopen("/sd/sin1K.wav", "rb"); #endif if (!file) { printf("open file failed!\n"); goto __exit; } buffer = pvPortMalloc(BUFSZ); if (buffer == NULL) goto __exit; info = (struct wav_info *) pvPortMalloc(sizeof(*info)); if (info == NULL) goto __exit; if(wavplay_parse_header((void *)file, info) < 0) goto __exit; printf("wav information:\n"); printf("samplerate %d\n", info->fmt_block.wav_format.SamplesPerSec); printf("channel %d\n", info->fmt_block.wav_format.Channels); audio = audio_dev_open(AUDIO_REPLAY_I2S, AUDIO_FLAG_REPLAY); if (!audio) { printf("Open audio device fail.\n"); goto __exit; } caps.main_type = AUDIO_TYPE_OUTPUT; /* 输出类型(播放设备 )*/ caps.sub_type = AUDIO_DSP_PARAM; /* 设置所有音频参数信息 */ caps.udata.config.samplerate = info->fmt_block.wav_format.SamplesPerSec; /* 采样率 */ caps.udata.config.channels = info->fmt_block.wav_format.Channels; /* 采样通道 */ caps.udata.config.samplebits = 16; /* 采样位数 */ audio_dev_configure(audio, &caps); data_size = info->data_block.data_size; while (data_size > 0) { int length; /* 从文件系统读取 wav 文件的音频数据 */ #ifdef ROMFILE_ADUIO length = RomFileRead(file, buffer, BUFSZ); #else length = ff_fread(buffer, 1, BUFSZ, file); #endif if(length > data_size) length = data_size; if (length <= 0) break; audio_dev_write(audio, buffer, length); data_size -= length; } audio_dev_close(audio, AUDIO_FLAG_REPLAY); __exit: if(file) #ifdef ROMFILE_ADUIO RomFileClose(file); #else ff_fclose(file); #endif if(buffer) vPortFree(buffer); if (info) vPortFree(info); while(1) vTaskDelay(portMAX_DELAY); } void wavplay_demo(void) { if (xTaskCreate(wavplay_thread, "wavplay", configMINIMAL_STACK_SIZE*10, NULL, configMAX_PRIORITIES - 3, NULL) != pdPASS) { printf("create wavplay task fail.\n"); } } #endif #endif #ifdef AUDIO_RECORD #if RECORD_TEST #define RECORD_BUF_SIZE 1024*1024 #define RECORD_REQ_SIZE 1024 static uint8_t *wavrecord_buffer = NULL; static uint8_t *waverecord_get_a_new_buffer(int size) { static int waverecord_index = 0; uint8_t *buffer = NULL; if(!wavrecord_buffer) { wavrecord_buffer = pvPortMalloc(RECORD_BUF_SIZE); if(!wavrecord_buffer) return NULL; waverecord_index = 0; } if(waverecord_index + size < RECORD_BUF_SIZE) { buffer = wavrecord_buffer + waverecord_index; waverecord_index += size; } else { printf("record done, start_addr:0x%x, size:0x%x\n", (uint32_t)wavrecord_buffer, RECORD_BUF_SIZE); //CP15_clean_dcache_for_dma((uint32_t)wavrecord_buffer, (uint32_t)wavrecord_buffer + RECORD_BUF_SIZE); buffer = wavrecord_buffer; waverecord_index = 0; } return buffer; } static int wavrecord_callback(struct audio_device *audio) { int ret = -1; /* save record data */ if(audio && audio->record) { int size = audio->record->buf_info.total_size; if(size == RECORD_REQ_SIZE) { uint8_t *buffer = waverecord_get_a_new_buffer(size); if(buffer) { /* clear buffer */ //memset(buffer, 0, size); #if 1 /* method 1: use dynamic buffer to receive record data(without copy data). [Recommend this method] */ audio_dev_record_set_param(audio, buffer, size); //Set a new buffer to receive the next frame. #else /* method 2: use one buffer to receive record data(should copy data) */ if(audio->record->buf_info.buffer) memcpy(buffer, audio->record->buf_info.buffer, size); //Copy the record data to a destnation buffer. #endif ret = 0; } } else { printf("%s() Invalid size:%d\n", __func__, size); } } return ret; } static void wavrecord_thread(void *para) { uint8_t *buffer = NULL; struct audio_device *audio; int ret; audio = audio_dev_open(AUDIO_RECORD_I2S, AUDIO_FLAG_RECORD); if(audio) { /* set record sample information */ struct audio_caps caps = {0}; caps.main_type = AUDIO_TYPE_INPUT; /* 输入类型(录音设备 )*/ caps.sub_type = AUDIO_DSP_PARAM; /* 设置所有音频参数信息 */ caps.udata.config.samplerate = 16000; /* 采样率 */ caps.udata.config.channels = 2; /* 采样通道 */ caps.udata.config.samplebits = 16; /* 采样位数 */ audio_dev_configure(audio, &caps); /* register record complete callback */ audio_dev_register_record_callback(audio, wavrecord_callback); /* set record buffer and size */ buffer = waverecord_get_a_new_buffer(RECORD_REQ_SIZE); ret = audio_dev_record_set_param(audio, buffer, RECORD_REQ_SIZE); if(ret) { printf("%s() audio_dev_record_set_param failed \n", __func__); goto exit; } /* start recording */ audio_dev_record_start(audio); printf("wav record information:\n"); printf("samplerate %d\n", caps.udata.config.samplerate); printf("channel %d\n", caps.udata.config.channels); printf("samplebits %d\n", caps.udata.config.samplebits); } while(1) vTaskDelay(portMAX_DELAY); exit: if(audio) { /* stop record */ audio_dev_record_stop(audio); /* 关闭 Audio 设备 */ audio_dev_close(audio, AUDIO_FLAG_REPLAY); } if (wavrecord_buffer) vPortFree(wavrecord_buffer); } void wavrecord_demo(void) { if (xTaskCreate(wavrecord_thread, "wavrecord", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 3, NULL) != pdPASS) { printf("create waverecord task fail.\n"); } } #endif #endif