| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- #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
|