Closed Kingwulin closed 3 months ago
This example uses i2s_write
to play raw music that store in flash or header file. Raw music means only audio data in it, but a .wav
format music has a protocol header at the beginning, which indicates the sample_rate
, data_bit_width
and so on, these information are used to decode the following music and shouldn't be played. You can try to parse the header of .wav
file and play the music without the header.
Hope it can help~
FYI, you can refer to i2s_audio_recorder_sdcard and check how a .wav
header is generated
This example uses
i2s_write
to play raw music that store in flash or header file. Raw music means only audio data in it, but a.wav
format music has a protocol header at the beginning, which indicates thesample_rate
,data_bit_width
and so on, these information are used to decode the following music and shouldn't be played. You can try to parse the header of.wav
file and play the music without the header.Hope it can help~
think you for your reply below it my code to play a .wav file stora at spiffs, I had read the header of the file ,but the noise still exit and Noise appears at the beginning of playback
typedef struct {
// The "RIFF" chunk descriptor
uint8_t ChunkID[4];
int32_t ChunkSize;
uint8_t Format[4];
// The "fmt" sub-chunk
uint8_t Subchunk1ID[4];
int32_t Subchunk1Size;
int16_t AudioFormat;
int16_t NumChannels;
int32_t SampleRate;
int32_t ByteRate;
int16_t BlockAlign;
int16_t BitsPerSample;
// The "data" sub-chunk
uint8_t Subchunk2ID[4];
int32_t Subchunk2Size;
} wav_header_t;
static esp_err_t play_wav(const char *filepath)
{
FILE *fd = NULL;
fd = fopen(filepath, "r");
if (NULL == fd) {
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
return ESP_FAIL;
}
const size_t chunk_size = 2048;
uint8_t *buffer = malloc(chunk_size);
if (NULL == buffer) {
ESP_LOGE(TAG, "audio data buffer malloc failed");
fclose(fd);
return ESP_FAIL;
}
int len;
/**
* read head of WAV file
*/
wav_header_t wav_head;
len = fread(&wav_head, 1, sizeof(wav_header_t), fd);
if (len <= 0) {
ESP_LOGE(TAG, "Read wav header failed");
fclose(fd);
return ESP_FAIL;
}
if (NULL == strstr((char *)wav_head.Subchunk1ID, "fmt") &&
NULL == strstr((char *)wav_head.Subchunk2ID, "data")) {
ESP_LOGE(TAG, "Header of wav format error");
fclose(fd);
return ESP_FAIL;
}
// ESP_LOGI(TAG, "frame_rate=%d, ch=%d, width=%d", wav_head.SampleRate, wav_head.NumChannels, wav_head.BitsPerSample);
/**
* read wave data of WAV file
*/
size_t write_num = 0;
size_t cnt;
//i2s_start(I2S_NUM_0);
do {
/* Read file in chunks into the scratch buffer */
len = fread(buffer, 1, chunk_size, fd);
if (len <= 0) {
ESP_LOGI(TAG, "break out");
//i2s_stop(I2S_NUM_0);
break;
}
//pwm_audio_write(buffer, len, &cnt, 1000 / portTICK_PERIOD_MS);
i2s_write(I2S_NUM_0, buffer, len, &cnt, 100);
ESP_LOGI(TAG, "%d,%d",cnt,len);
write_num += len;
} while (1);
free(buffer);
fclose(fd);
return ESP_OK;
}
Hello,there is video,There is a "de" sound at the beginning of most tones,and below is my main code
void app_play_num(int index)
{
char file_buf[16];
sprintf(file_buf,"/audio/%d.wav",index);
play_wav(file_buf);
ESP_LOGI(TAG,"going to player %s",file_buf);
}
void speaker_setTemp2_say(void)
{
char file_buf[32];
sprintf(file_buf,"/audio/setTime.wav");
ESP_LOGI(TAG,"going to player %s",file_buf);
play_wav(file_buf);
}
void speaker_du_say(void)
{
char file_buf[16];
sprintf(file_buf,"/audio/min.wav");
ESP_LOGI(TAG,"going to player %s",file_buf);
play_wav(file_buf);
}
void app_voice_play(int num)
{
speaker_setTemp2_say();
if(num/10)
{
app_play_num(num/10); //noise exit at the begin of this code
app_play_num(0); //noise exit at the begin of this code
}
app_play_num(num%10); //noise exit at the begin of this code
speaker_du_say(); //noise exit at the begin of this code
}
void app_main(void)
{
spiffs_driver_init();
hal_i2s_driver_init();
//play_wav(MOUNT_POINT"/sample.wav");
app_voice_play(19);
vTaskDelay(100);
app_voice_play(13);
vTaskDelay(100);
app_voice_play(31);
vTaskDelay(100);
app_voice_play(39);
vTaskDelay(100);
app_voice_play(91);
vTaskDelay(100);
app_voice_play(93);
}
Firstly, for the current I2S driver, due to the driver will start automatically after installation, the uninitialized data may be transported, you can try to stop the i2s after installation and calling i2s_zero_dma_buffer
to clear the DMA buffer before start and write data.
Secondly, just in case the audio itself contains the noise, try to print the beginning data of the sending buffer.
Another notice, the DAC only support 8 bit-width, but most audios are at least 16 bit-width, the audio data need to be right shifted 8 bits
The clipped sound mainly caused by the rapid change of data. I guess the polling time between two i2s_write
may be too long which lead to the audio not consecutive, try to remove other codes in the i2s_write
loop. and also clear the dma buffer every time after finished sending the data.
Firstly, for the current I2S driver, due to the driver will start automatically after installation, the uninitialized data may be transported, you can try to stop the i2s after installation and calling
i2s_zero_dma_buffer
to clear the DMA buffer before start and write data. Secondly, just in case the audio itself contains the noise, try to print the beginning data of the sending buffer.
here is the wav file spiffs_image.zip
how to clear the dma buffer
Call i2s_zero_dma_buffer
Call
i2s_zero_dma_buffer
Thanks for your reply,would you tell me which file the "i2s_zero_dma_buffer" function is. I can't find the call in the git project
It's not a file, it's a function declared in components/driver/include/driver/i2s.h
line 379.
It's not a file, it's a function declared in
components/driver/include/driver/i2s.h
line 379.
Thank you! I found event I write the code like this: to make the num output data consecutly,but the 'de' noise is still exit in num
Is it a problem of wav format, is it better for me to change to pcm format?
#include <stdio.h>
#include "driver/i2s.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "esp_spiffs.h"
#include <string.h>
static const char *TAG = "speaker";
#define I2S_SAMPLE_RATE (16000)
#define SAMPLE_BITS (16)
#define MASTER_BCK_IO 4
#define MASTER_WS_IO 5
#define DATA_OUT_IO 18
#define DATA_IN_IO 21
#define MOUNT_POINT "/audio"
static const char *partition_label = "audio";
typedef struct {
// The "RIFF" chunk descriptor
uint8_t ChunkID[4];
int32_t ChunkSize;
uint8_t Format[4];
// The "fmt" sub-chunk
uint8_t Subchunk1ID[4];
int32_t Subchunk1Size;
int16_t AudioFormat;
int16_t NumChannels;
int32_t SampleRate;
int32_t ByteRate;
int16_t BlockAlign;
int16_t BitsPerSample;
// The "data" sub-chunk
uint8_t Subchunk2ID[4];
int32_t Subchunk2Size;
} wav_header_t;
#define MAX_OP_FILE 10
typedef struct
{
FILE * fds[MAX_OP_FILE];
int num_use;
}file_op_t;
file_op_t file_op;
char file_name_buf[MAX_OP_FILE][16];
static esp_err_t play_wav(const char *filepath)
{
FILE *fd = NULL;
//struct stat file_stat;
// if (stat(filepath, &file_stat) == -1) {
// ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
// return ESP_FAIL;
// }
// ESP_LOGI(TAG, "file stat info: %s (%ld bytes)...", filepath, file_stat.st_size);
fd = fopen(filepath, "r");
if (NULL == fd) {
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
return ESP_FAIL;
}
const size_t chunk_size = 4096;
uint8_t *buffer = malloc(chunk_size);
if (NULL == buffer) {
ESP_LOGE(TAG, "audio data buffer malloc failed");
fclose(fd);
return ESP_FAIL;
}
int len;
/**
* read head of WAV file
*/
wav_header_t wav_head;
len = fread(&wav_head, 1, sizeof(wav_header_t), fd);
if (len <= 0) {
ESP_LOGE(TAG, "Read wav header failed");
fclose(fd);
return ESP_FAIL;
}
if (NULL == strstr((char *)wav_head.Subchunk1ID, "fmt") &&
NULL == strstr((char *)wav_head.Subchunk2ID, "data")) {
ESP_LOGE(TAG, "Header of wav format error");
fclose(fd);
return ESP_FAIL;
}
// ESP_LOGI(TAG, "frame_rate=%d, ch=%d, width=%d", wav_head.SampleRate, wav_head.NumChannels, wav_head.BitsPerSample);
/**
* read wave data of WAV file
*/
size_t write_num = 0;
size_t cnt;
//i2s_start(I2S_NUM_0);
i2s_zero_dma_buffer(I2S_NUM_0);
do {
/* Read file in chunks into the scratch buffer */
len = fread(buffer, 1, chunk_size, fd);
if (len <= 0) {
ESP_LOGI(TAG, "break out");
//i2s_stop(I2S_NUM_0);
break;
}
//pwm_audio_write(buffer, len, &cnt, 1000 / portTICK_PERIOD_MS);
i2s_write(I2S_NUM_0, buffer, len, &cnt, 100);
ESP_LOGI(TAG, "%d,%d",cnt,len);
write_num += len;
} while (1);
free(buffer);
fclose(fd);
return ESP_OK;
}
void spiffs_driver_init(void)
{
ESP_LOGI(TAG, "Initializing SPIFFS");
esp_vfs_spiffs_conf_t conf = {
.base_path = MOUNT_POINT,
.partition_label = partition_label,
.max_files = 5,
.format_if_mount_failed = false
};
// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return;
}
size_t total = 0, used = 0;
ret = esp_spiffs_info(conf.partition_label, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}
}
void hal_i2s_driver_init(void)
{
esp_err_t err;
// master driver installed and send data
i2s_config_t master_i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = SAMPLE_BITS,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.dma_buf_count = 6,
.dma_buf_len = 200,
.use_apll = 0,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
};
i2s_pin_config_t master_pin_config = {
.bck_io_num = MASTER_BCK_IO,
.ws_io_num = MASTER_WS_IO,
.data_out_num = DATA_OUT_IO,
.data_in_num = DATA_IN_IO
};
err = i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL);
ESP_LOGI(TAG,"i2s_driver_install status %d",err);
err = i2s_set_pin(I2S_NUM_0, &master_pin_config);
ESP_LOGI(TAG,"i2s_set_pin status %d",err);
i2s_set_clk(I2S_NUM_0, I2S_SAMPLE_RATE, (i2s_bits_per_sample_t)16, (i2s_channel_t)1);
}
void wav_num_set(int num)
{
file_op.num_use = 0;
if(num/10)
{
//app_play_num(num/10); //noise exit at the begin of this code
sprintf(file_name_buf[file_op.num_use++],"/audio/%d.wav",num/10);
//app_play_num(0); //noise exit at the begin of this code
sprintf(file_name_buf[file_op.num_use++],"/audio/0.wav");
}
//app_play_num(num%10); //noise exit at the begin of this code
sprintf(file_name_buf[file_op.num_use++],"/audio/%d.wav",num%10);
}
static esp_err_t wav_num_player(void)
{
int i,j=0;
wav_header_t wav_head;
int len;
for(i=0;i<file_op.num_use;i++)
{
file_op.fds[i] = NULL;
file_op.fds[i] = fopen(file_name_buf[i], "r");
if (NULL == file_op.fds[i]) {
ESP_LOGE(TAG, "Failed to read existing file : %s", file_name_buf[i]);
return ESP_FAIL;
}
len = fread(&wav_head, 1, sizeof(wav_header_t), file_op.fds[i]);
if (len <= 0) {
ESP_LOGE(TAG, "Read wav header failed");
fclose(file_op.fds[i]);
return ESP_FAIL;
}
if (NULL == strstr((char *)wav_head.Subchunk1ID, "fmt") &&
NULL == strstr((char *)wav_head.Subchunk2ID, "data")) {
ESP_LOGE(TAG, "Header of wav format error");
fclose(file_op.fds[i]);
return ESP_FAIL;
}
ESP_LOGI(TAG, "frame_rate=%d, ch=%d, width=%d", wav_head.SampleRate, wav_head.NumChannels, wav_head.BitsPerSample);
}
const size_t chunk_size = 4096;
uint8_t *buffer = malloc(chunk_size);
size_t write_num = 0;
size_t cnt;
do {
/* Read file in chunks into the scratch buffer */
len = fread(buffer, 1, chunk_size, file_op.fds[j]);
if(j != file_op.num_use-1)
{
if (len < chunk_size) {
j++;
len+=fread(&buffer[len], 1, chunk_size-len, file_op.fds[j]);
}
}
else
{
if (len <= 0) {
ESP_LOGI(TAG, "break out");
break;
}
}
//pwm_audio_write(buffer, len, &cnt, 1000 / portTICK_PERIOD_MS);
i2s_write(I2S_NUM_0, buffer, len, &cnt, 100);
ESP_LOGI(TAG, "%d,%d",cnt,len);
write_num += len;
} while (1);
free(buffer);
for(i=0;i<file_op.num_use;i++)
{
fclose(file_op.fds[i]);
}
return ESP_OK;
}
size_t sounder_speaker(char * p_data,unsigned int data_len)
{
size_t i2s_bytes_write = 0;
i2s_write(I2S_NUM_0, p_data, data_len, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
return i2s_bytes_write;
}
//char *file_arr[5] = {"shi","001","002","ktw","shd"};
void app_play_num(int index)
{
char file_buf[16];
sprintf(file_buf,"/audio/%d.wav",index);
play_wav(file_buf);
ESP_LOGI(TAG,"going to player %s",file_buf);
}
void speaker_setTemp2_say(void)
{
char file_buf[32];
sprintf(file_buf,"/audio/setTime.wav");
ESP_LOGI(TAG,"going to player %s",file_buf);
play_wav(file_buf);
}
void speaker_du_say(void)
{
char file_buf[16];
sprintf(file_buf,"/audio/min.wav");
ESP_LOGI(TAG,"going to player %s",file_buf);
play_wav(file_buf);
}
void app_voice_play(int num)
{
wav_num_set(num);
speaker_setTemp2_say();
wav_num_player();
speaker_du_say(); //noise exit at the begin of this code
}
void app_main(void)
{
spiffs_driver_init();
hal_i2s_driver_init();
//play_wav(MOUNT_POINT"/sample.wav");
app_voice_play(19);
vTaskDelay(100);
app_voice_play(13);
vTaskDelay(100);
app_voice_play(31);
vTaskDelay(100);
app_voice_play(39);
vTaskDelay(100);
app_voice_play(91);
vTaskDelay(100);
app_voice_play(93);
}
You can put your wav
file into a software named audacity
, it can provide the wave shape and also able to play the audio.
Thanks for reporting, feel free to reopen.
Hi,I am using the demo here I modify this demo to make the .wav file output to a speaker over the i2s driver(a hardware max9735a I used) mostly,every time at the starting of the .wav file ,the sound always some noise like "de" How to deal with it ,Thanks