/** * @file wav_play_form_sd_card.c * @brief * * Copyright (c) 2021 Bouffalolab team * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * */ #include "bsp_es8388.h" #include "hal_i2s.h" #include "hal_dma.h" #include "data_protocol.h" #include "wav_play_from_isp.h" extern isp_obj_t isp_obj_uart; static int wav_data_parser(uint8_t *buff, uint16_t max_size, wav_information_t *wav_information); static uint32_t pcm_24bit_to_32bit(uint8_t *buff, uint32_t data_size); static int isp_wav_play_init(struct audio_dev *audio_dev, uint8_t mode, uint8_t *buff); static int isp_wav_play_control(struct audio_dev *audio_dev, AUDIO_CMD_t cmd, void *args); static int isp_wav_play_callback(audio_dev_t *audio_dev); uint8_t audio_buff[2][4 * 1024] __attribute__((section(".system_ram"), aligned(4))); static ES8388_Cfg_Type ES8388Cfg = { .work_mode = ES8388_CODEC_MDOE, /*!< ES8388 work mode */ .role = ES8388_SLAVE, /*!< ES8388 role */ .mic_input_mode = ES8388_DIFF_ENDED_MIC, /*!< ES8388 mic input mode */ .mic_pga = ES8388_MIC_PGA_9DB, /*!< ES8388 mic PGA */ .i2s_frame = ES8388_LEFT_JUSTIFY_FRAME, /*!< ES8388 I2S frame */ .data_width = ES8388_DATA_LEN_16, /*!< ES8388 I2S dataWitdh */ }; static wav_information_t Wav_Information; static record_config_t record_config; static audio_dev_t *p_Audio_Dev = NULL; static void dma_ch2_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state) { if (p_Audio_Dev && p_Audio_Dev->audio_callback) { p_Audio_Dev->audio_callback(p_Audio_Dev); } } static void dma_ch3_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state) { if (p_Audio_Dev && p_Audio_Dev->audio_callback) { p_Audio_Dev->audio_callback(p_Audio_Dev); } } /* get File pointer from top of file*/ static int wav_data_parser(uint8_t *buff, uint16_t max_size, wav_information_t *wav_information) { uint32_t offset = 0; uint32_t chunk_id; if (buff == NULL) return 1; /* RIFF WAVE Chunk */ chunk_id = ((chunk_riff_t *)&buff[offset])->chunk_id; if (chunk_id == 0x46464952) { wav_information->chunk_riff_offset = offset; wav_information->chunk_riff = *((chunk_riff_t *)&buff[offset]); offset += sizeof(chunk_riff_t); } else { wav_information->chunk_riff_offset = -1; return 1; } /* Format Chunk */ chunk_id = ((chunk_format_t *)&buff[offset])->chunk_id; if (chunk_id == 0x20746D66 && offset < max_size) /* fmt */ { wav_information->chunk_format_offset = offset; wav_information->chunk_format = *((chunk_format_t *)&buff[offset]); offset += ((chunk_format_t *)&buff[offset])->chunk_size + 8; } else { wav_information->chunk_format_offset = -1; return 1; } /* Fact/list Chunk */ chunk_id = ((chunk_fact_t *)&buff[offset])->chunk_id; if ((chunk_id == 0X74636166 || chunk_id == 0X5453494C) && offset < max_size) /*fact or list*/ { wav_information->chunk_fact_offset = offset; wav_information->chunk_fact = *((chunk_fact_t *)&buff[offset]); offset += ((chunk_fact_t *)&buff[offset])->chunk_size + 8; } else { wav_information->chunk_fact_offset = -1; } /* Data Chunk */ chunk_id = ((chunk_data_t *)&buff[offset])->chunk_id; if (chunk_id == 0X61746164 && offset < max_size) { wav_information->chunk_data_offset = offset; wav_information->chunk_data = *((chunk_data_t *)&buff[offset]); } else { wav_information->chunk_data_offset = -1; return 1; } return 0; } static uint32_t pcm_24bit_to_32bit(uint8_t *buff, uint32_t data_size) { /* buff大小应该在data_size的三分之四倍以上 */ for (uint16_t i = data_size / 3; i > 0; i--) { buff[i * 4 - 1] = buff[i * 3 - 1]; buff[i * 4 - 2] = buff[i * 3 - 2]; buff[i * 4 - 3] = buff[i * 3 - 3]; buff[i * 4 - 4] = 0; } return data_size / 3 * 4; } static int isp_wav_play_init(struct audio_dev *audio_dev, uint8_t mode, uint8_t *buff) { int res; struct device *dma_ch2 = device_find("i2s_ch2"); struct device *dma_ch3 = device_find("i2s_ch3"); audio_dev->device = device_find("I2S"); if (audio_dev->device) { device_close(audio_dev->device); } else { i2s_register(I2S0_INDEX, "I2S"); audio_dev->device = device_find("I2S"); } if (mode == 1) { goto record_conf; } /* play config */ if (dma_ch2) { device_close(dma_ch2); } else { dma_register(DMA0_CH2_INDEX, "i2s_ch2"); dma_ch2 = device_find("i2s_ch2"); } /* Parse the WAV file */ res = wav_data_parser(buff, 1000, &Wav_Information); if (!res) { audio_dev->wav_information = &Wav_Information; } else { /* MSG("wav file parse error\r\n"); */ return 1; } if ((audio_dev->device) && dma_ch2) { /* I2S Config */ I2S_DEV(audio_dev->device)->interface_mode = I2S_MODE_LEFT; I2S_DEV(audio_dev->device)->sampl_freq_hz = audio_dev->wav_information->chunk_format.sample_rate; I2S_DEV(audio_dev->device)->channel_num = audio_dev->wav_information->chunk_format.num_of_channels; uint8_t pcm_w = audio_dev->wav_information->chunk_format.bits_per_sample / 8; if (pcm_w <= 2) { I2S_DEV(audio_dev->device)->frame_size = I2S_FRAME_LEN_16; } else { I2S_DEV(audio_dev->device)->frame_size = I2S_FRAME_LEN_32; } I2S_DEV(audio_dev->device)->data_size = I2S_DEV(audio_dev->device)->frame_size; I2S_DEV(audio_dev->device)->fifo_threshold = 3; res = device_open((audio_dev->device), DEVICE_OFLAG_DMA_TX); /* ES8388 Config */ switch (I2S_DEV(audio_dev->device)->data_size) { case I2S_FRAME_LEN_16: ES8388Cfg.data_width = ES8388_DATA_LEN_16; break; case I2S_FRAME_LEN_24: ES8388Cfg.data_width = ES8388_DATA_LEN_24; break; case I2S_FRAME_LEN_32: ES8388Cfg.data_width = ES8388_DATA_LEN_32; break; default: return 1; break; } ES8388_Init(&ES8388Cfg); ES8388_Set_Voice_Volume(50); /* DMA Config */ DMA_DEV(dma_ch2)->direction = DMA_MEMORY_TO_PERIPH; DMA_DEV(dma_ch2)->transfer_mode = DMA_LLI_ONCE_MODE; DMA_DEV(dma_ch2)->src_req = DMA_REQUEST_NONE; DMA_DEV(dma_ch2)->dst_req = DMA_REQUEST_I2S_TX; DMA_DEV(dma_ch2)->src_addr_inc = DMA_ADDR_INCREMENT_ENABLE; DMA_DEV(dma_ch2)->dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE; DMA_DEV(dma_ch2)->src_burst_size = DMA_BURST_4BYTE; DMA_DEV(dma_ch2)->dst_burst_size = DMA_BURST_4BYTE; DMA_DEV(dma_ch2)->src_width = DMA_TRANSFER_WIDTH_8BIT; DMA_DEV(dma_ch2)->dst_width = DMA_TRANSFER_WIDTH_8BIT; switch (I2S_DEV(audio_dev->device)->data_size * I2S_DEV(audio_dev->device)->channel_num) { case 1: DMA_DEV(dma_ch2)->src_width = DMA_TRANSFER_WIDTH_8BIT; DMA_DEV(dma_ch2)->dst_width = DMA_TRANSFER_WIDTH_8BIT; break; case 2: DMA_DEV(dma_ch2)->src_width = DMA_TRANSFER_WIDTH_16BIT; DMA_DEV(dma_ch2)->dst_width = DMA_TRANSFER_WIDTH_16BIT; break; default: DMA_DEV(dma_ch2)->src_width = DMA_TRANSFER_WIDTH_32BIT; DMA_DEV(dma_ch2)->dst_width = DMA_TRANSFER_WIDTH_32BIT; break; } device_open(dma_ch2, 0); device_set_callback(dma_ch2, dma_ch2_irq_callback); device_control(dma_ch2, DEVICE_CTRL_SET_INT, NULL); device_control((audio_dev->device), DEVICE_CTRL_ATTACH_TX_DMA, (void *)dma_ch2); /* Delete the information data*/ uint32_t data_size = audio_dev->buff_data_size[!audio_dev->buff_using]; data_size = data_size - audio_dev->wav_information->chunk_data_offset; audio_dev->buff_data_size[!audio_dev->buff_using] = data_size; uint8_t *p_dst = audio_dev->buff[!audio_dev->buff_using]; uint8_t *p_src = &(audio_dev->buff[!audio_dev->buff_using][audio_dev->wav_information->chunk_data_offset]); memcpy(p_dst, p_src, data_size); if (audio_dev->wav_information->chunk_format.bits_per_sample / 8 == 3) { audio_dev->buff_data_size[!audio_dev->buff_using] = pcm_24bit_to_32bit(audio_dev->buff[!audio_dev->buff_using], data_size); } else { } } else { return 1; } return 0; /* record config */ record_conf: if (dma_ch3) { device_close(dma_ch3); } else { dma_register(DMA0_CH3_INDEX, "i2s_ch3"); dma_ch3 = device_find("i2s_ch3"); } if ((audio_dev->device) && dma_ch3) { I2S_DEV(audio_dev->device)->iis_mode = I2S_MODE_MASTER; I2S_DEV(audio_dev->device)->interface_mode = I2S_MODE_LEFT; I2S_DEV(audio_dev->device)->channel_num = audio_dev->record_config->channel_num; I2S_DEV(audio_dev->device)->data_size = audio_dev->record_config->data_size; if (I2S_DEV(audio_dev->device)->data_size <= 2) { I2S_DEV(audio_dev->device)->frame_size = I2S_FRAME_LEN_16; } else { I2S_DEV(audio_dev->device)->frame_size = I2S_FRAME_LEN_32; } I2S_DEV(audio_dev->device)->fifo_threshold = 4; switch (audio_dev->record_config->sampl_freq) { case SAMPL_FREQ_8000: I2S_DEV(audio_dev->device)->sampl_freq_hz = 8000; break; case SAMPL_FREQ_16000: I2S_DEV(audio_dev->device)->sampl_freq_hz = 16000; break; // case SAMPL_FREQ_32000: // I2S_DEV(audio_dev->device)->sampl_freq_hz = 32000; // break; case SAMPL_FREQ_44100: I2S_DEV(audio_dev->device)->sampl_freq_hz = 44100; break; case SAMPL_FREQ_48000: I2S_DEV(audio_dev->device)->sampl_freq_hz = 48000; break; default: break; } device_open(audio_dev->device, DEVICE_OFLAG_DMA_RX); /* ES8388 Config */ switch (I2S_DEV(audio_dev->device)->data_size) { case I2S_FRAME_LEN_16: ES8388Cfg.data_width = ES8388_DATA_LEN_16; break; case I2S_FRAME_LEN_24: ES8388Cfg.data_width = ES8388_DATA_LEN_24; break; case I2S_FRAME_LEN_32: ES8388Cfg.data_width = ES8388_DATA_LEN_32; break; default: return 1; break; } ES8388_Init(&ES8388Cfg); /* DMA Config */ DMA_DEV(dma_ch3)->direction = DMA_PERIPH_TO_MEMORY; DMA_DEV(dma_ch3)->transfer_mode = DMA_LLI_ONCE_MODE; DMA_DEV(dma_ch3)->src_req = DMA_REQUEST_I2S_RX; DMA_DEV(dma_ch3)->dst_req = DMA_REQUEST_NONE; DMA_DEV(dma_ch3)->src_addr_inc = DMA_ADDR_INCREMENT_DISABLE; DMA_DEV(dma_ch3)->dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE; DMA_DEV(dma_ch3)->src_burst_size = DMA_BURST_4BYTE; DMA_DEV(dma_ch3)->dst_burst_size = DMA_BURST_4BYTE; DMA_DEV(dma_ch3)->src_width = DMA_TRANSFER_WIDTH_8BIT; DMA_DEV(dma_ch3)->dst_width = DMA_TRANSFER_WIDTH_8BIT; switch (I2S_DEV(audio_dev->device)->data_size * I2S_DEV(audio_dev->device)->channel_num) { case 1: DMA_DEV(dma_ch3)->src_width = DMA_TRANSFER_WIDTH_8BIT; DMA_DEV(dma_ch3)->dst_width = DMA_TRANSFER_WIDTH_8BIT; break; case 2: DMA_DEV(dma_ch3)->src_width = DMA_TRANSFER_WIDTH_16BIT; DMA_DEV(dma_ch3)->dst_width = DMA_TRANSFER_WIDTH_16BIT; break; default: DMA_DEV(dma_ch3)->src_width = DMA_TRANSFER_WIDTH_32BIT; DMA_DEV(dma_ch3)->dst_width = DMA_TRANSFER_WIDTH_32BIT; break; } device_open(dma_ch3, 0); device_set_callback(dma_ch3, dma_ch3_irq_callback); device_control(dma_ch3, DEVICE_CTRL_SET_INT, NULL); device_control((audio_dev->device), DEVICE_CTRL_ATTACH_RX_DMA, (void *)dma_ch3); } return 0; } static int isp_wav_play_control(struct audio_dev *audio_dev, AUDIO_CMD_t cmd, void *args) { static uint32_t volume = 50; int res = -1; switch (cmd) { case AUDIO_CMD_PLAY_START: if (audio_dev->audio_state) { audio_dev->buff_using = !audio_dev->buff_using; res = device_write(audio_dev->device, 0, audio_dev->buff[audio_dev->buff_using], audio_dev->buff_data_size[audio_dev->buff_using]); audio_dev->audio_state = 4; res = 0; } break; case AUDIO_CMD_PLAY_STOP: if (audio_dev->audio_state) { audio_dev->audio_state = 1; res = 0; } break; case AUDIO_CMD_RECORD_START: if (audio_dev->audio_state >= 10) { audio_dev->buff_using = !audio_dev->buff_using; res = device_read(audio_dev->device, 0, audio_dev->buff[audio_dev->buff_using], audio_dev->buff_size_max); audio_dev->audio_state = 12; } break; case AUDIO_CMD_RECORD_STOP: if (audio_dev->audio_state > 10) { audio_dev->audio_state = 10; res = 0; } break; case AUDIO_CMD_SET_VOLUME: if (audio_dev->audio_state) { res = ES8388_Set_Voice_Volume((uint32_t)args); res = 0; volume = (uint32_t)args; } break; case AUDIO_CMD_GET_VOLUME: if (audio_dev->audio_state) { // res = ES8388_Set_Voice_Volume((uint32_t)args); res = (int)volume; } break; default: break; } return res; } static int isp_wav_play_callback(audio_dev_t *audio_dev) { if (audio_dev->audio_state < 10) { /* play*/ if (audio_dev->buff_data_size[!audio_dev->buff_using] > 0 && isp_obj_uart.status.isp_state_mode == RECEIVE_WAIT_ACK) { /* data ready, switch buff */ audio_dev->buff_using = !audio_dev->buff_using; device_write(audio_dev->device, 0, audio_dev->buff[audio_dev->buff_using], audio_dev->buff_data_size[audio_dev->buff_using]); audio_dev->buff_data_size[audio_dev->buff_using] = 0; audio_dev->buff_data_size[!audio_dev->buff_using] = isp_obj_uart.length; isp_obj_uart.file_data = audio_dev->buff[!audio_dev->buff_using]; isp_obj_uart.status.isp_state_mode = NO_TASK; isp_uart_send_ack(&isp_obj_uart, REPLY_SUCCES); } else { /* Data not ready, wait data receive*/ audio_dev->audio_state = 3; } } else { /* record */ audio_dev->buff_data_size[audio_dev->buff_using] = audio_dev->buff_size_max; if (audio_dev->audio_state == 12) { if (isp_obj_uart.status.isp_state_mode == NO_TASK) { /* Continue to the recording */ audio_dev->buff_using = !audio_dev->buff_using; device_read(audio_dev->device, 0, audio_dev->buff[audio_dev->buff_using], audio_dev->buff_size_max); /* send data to PC */ isp_obj_uart.file_data = audio_dev->buff[!audio_dev->buff_using]; isp_obj_uart.length = audio_dev->buff_data_size[!audio_dev->buff_using]; isp_obj_uart.cmd_id = FILE_DATA; isp_obj_uart.file_type = 0x58; isp_uart_send_data(&isp_obj_uart); audio_dev->buff_data_size[!audio_dev->buff_using] = 0; } else { /* Data not ready, wait data transmit*/ audio_dev->audio_state = 11; } } } return 0; } int isp_wav_play_register(audio_dev_t *audio_dev) { p_Audio_Dev = audio_dev; audio_dev->audio_init = isp_wav_play_init, audio_dev->audio_control = isp_wav_play_control, audio_dev->audio_callback = isp_wav_play_callback, audio_dev->buff[0] = audio_buff[0]; audio_dev->buff[1] = audio_buff[1]; audio_dev->buff_data_size[0] = 0; audio_dev->buff_data_size[1] = 0; audio_dev->audio_state = 0; audio_dev->buff_size_max = sizeof(audio_buff) / 2; record_config.data_size = 2; record_config.channel_num = 1; record_config.sampl_freq = SAMPL_FREQ_16000; audio_dev->record_config = &record_config; return 0; }