IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【esp32-s3】7.2 I2S——播放wav文件 -> 正文阅读

[嵌入式]【esp32-s3】7.2 I2S——播放wav文件

1 前言

本章实现了播放和录制功能。

2 硬件

在这里插入图片描述

3 代码

/* I2S Digital Microphone Recording Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "sdkconfig.h"

#include <dirent.h>     // dir struct
#include "esp_vfs.h" 
#define DIR_NUM_MAX 10 

static const char* TAG = "pdm_rec_example";

#define SPI_DMA_CHAN        SPI_DMA_CH_AUTO
#define SD_MOUNT_POINT      "/sdcard"

#define I2S_REC_CHANNEL        (1) // For mono recording only!
#define I2S_REC_BIT (16)
#define I2S_REC_SAMPLE_RATE (36000)
#define I2S_SAMPLE_SIZE         (I2S_REC_BIT * 1024)
#define I2S_BYTE_RATE           (I2S_REC_SAMPLE_RATE * (I2S_REC_BIT / 8)) * I2S_REC_CHANNEL

#define I2S_NUM 0

#define I2S_REC_TIME 5  //set record time seconds

#define I2S_PIN_BCK_GPIO 41
#define I2S_PIN_WS_GPIO 40
#define I2S_PIN_DATA_RECORD 42
#define I2S_PIN_DATA_PLAYBACK 45

// When testing SD and SPI modes, keep in mind that once the card has been
// initialized in SPI mode, it can not be reinitialized in SD mode without
// toggling power to the card.
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t* card;

#define SPI_MOSI_GPIO 35
#define SPI_MISO_GPIO 37
#define SPI_SCLK_GPIO 36
#define SPI_CS_GPIO 34

static int16_t i2s_readraw_buff[I2S_SAMPLE_SIZE];
size_t bytes_read;
const int WAVE_HEADER_SIZE = 44;

// char wav_list[10];
struct wavinfo
{
    char *name;       // wav file path
    bool status;      // playing is 1, stop is 0
    int current_time;    // last stop time

    int bit;          // bit
    int channel;        
    int sample_rate;
    int while_time;   // sample num
    int format;
    struct wavinfo * next;
};
#define WAV_LIST_MAX 10
struct wavinfo *wav_list = NULL;
struct wavinfo list[WAV_LIST_MAX];
int current_list_num = 0;
struct wavinfo current_wav_msg;
struct wavinfo temp_wavinfo;

#define DIR_NAM_LEN_MAX 50
char dir_temp[DIR_NAM_LEN_MAX];

struct wavinfo get_wav_msg(char * wav_name)
{
    for(int i=0;i<current_list_num;i++)
    {
        if(strstr(list[i].name,wav_name))
        {
            printf("has searched wav\n");
            printf("name: %s\n",list[i].name);
            return list[i];
        }
    }
    printf("not find wav %s\n",wav_name);
    return list[0];
}

char* char_change_A2a(char *raw_char)
{
    char *temp = raw_char ;
    int len = strlen(raw_char);
    // printf("str = %s, len = %d\n",raw_char,len);
    for(int a = 0; a<len; a++)
    {
        // printf("str: %c\t",temp[a]);
        if('A'<=temp[a]&&temp[a]<='Z')
            temp[a]=temp[a]+32;
    }
    // printf("temp = %s\n",temp);
    // printf("raw_char = %s\n",raw_char);
    return temp;
}

void dir_list(char *path)
{
    char *dir_name;
    if(path != NULL)
        dir_name = path;
    else
        dir_name = SD_MOUNT_POINT;//"/t1";
        
    ESP_LOGI(TAG, "Opening dir %s", dir_name);

    DIR *dir_t1 = opendir(dir_name);

    int count = 0;
    char* names[DIR_NUM_MAX];

    printf("DIR: %s\n",dir_name);
    while(1) {
        struct dirent* de = readdir(dir_t1);
        if (!de) {
            break;
        }
        
        names[count] = char_change_A2a(de->d_name);

        printf("\t%s\n", de->d_name);
        // printf("\t%s type = %d\n", de->d_name, de->d_type);

        // dir
        if(de->d_type == 2)
        {
            strcpy(dir_temp,dir_name);
            strcat(dir_temp,"/");
            strcat(dir_temp,de->d_name);
            printf("this is dir:%s\n",dir_temp);

            char * temp_cpr;
            temp_cpr = "system~1";
            // printf("%s,%s",de->d_name , temp_cpr);
            if(strcmp(de->d_name,temp_cpr)==0)
                printf("ignore this dir\n");
            else
            {
                // strcpy(dir_temp,"");
                dir_list(dir_temp);
            }
        }


        // search wav file 
        char* search_key = ".wav";
        // printf("search wav = %s\n",strstr(de->d_name,search_key));
        if(strstr(de->d_name,search_key) != NULL)
        {
            // printf("this is wav file: %s\n",de->d_name);
            int file_name_len = strlen(dir_name)+strlen(de->d_name);
            // printf("file name len = %d\n",file_name_len);
            char *temp_path = (char *)malloc(sizeof(char) * (file_name_len+2));
            strcpy(temp_path,dir_name);
            strcat(temp_path,"/");
            strcat(temp_path,de->d_name);
            printf("file path = %s\n",temp_path);

            struct wavinfo *p1 ;
            // // p1 = (struct wavinfo*)malloc(sizeof(struct wavinfo));
            // printf("1\n");
            p1 = &list[current_list_num];
            current_list_num++;
            
            // printf("1\n");
            p1->name = temp_path;

            // printf("1\n");
            printf("p1->name = %s\n",p1->name);
            // printf("1\n");


            // struct wavinfo * p1 ;
            // p1 = (struct wavinfo*)malloc(sizeof(struct wavinfo));
            // printf("1\n");
            // p1->name = temp_path;
            // printf("1\n");
            // list[current_list_num]=*p1;
            // printf("1\n");
            // current_list_num++;
            // printf("1\n");
            // printf("p1->name = %s\n",p1->name);
            // printf("1\n");
        }

        ++count;
    }

    closedir(dir_t1);
}

void print_wav_list()
{
    printf("--------- wav list --------%d\n",current_list_num);

    for(int i=0;i<current_list_num;i++)
    {
        printf("\twav%d: %s\n",i,list[i].name);
    }
}

void test_sd_list()
{
    char *temp_path = SD_MOUNT_POINT;
    dir_list(temp_path);
    // temp_path = SD_MOUNT_POINT"/t1";
    // dir_list(temp_path);
    print_wav_list();

    // printf("wav1: %s \nwav2: %s\n",list[0].name,list[1].name);
}

void mount_sdcard(void)
{
    esp_err_t ret;
    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = 8 * 1024
    };
    ESP_LOGI(TAG, "Initializing SD card");

    spi_bus_config_t bus_cfg = {
        .mosi_io_num = SPI_MOSI_GPIO,
        .miso_io_num = SPI_MISO_GPIO,
        .sclk_io_num = SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4000,
    };
    ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize bus.");
        return;
    }

    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    slot_config.gpio_cs = SPI_CS_GPIO;
    slot_config.host_id = host.slot;

    ret = esp_vfs_fat_sdspi_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount filesystem.");
        } else {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
        }
        return;
    }

    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);
}

void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate){

    // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
    uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8;
    uint32_t byte_rate = I2S_BYTE_RATE;

    const char set_wav_header[] = {
        'R','I','F','F', // ChunkID
        file_size, file_size >> 8, file_size >> 16, file_size >> 24, // ChunkSize
        'W','A','V','E', // Format
        'f','m','t',' ', // Subchunk1ID
        0x10, 0x00, 0x00, 0x00, // Subchunk1Size (16 for PCM)
        0x01, 0x00, // AudioFormat (1 for PCM)
        0x01, 0x00, // NumChannels (1 channel)
        sample_rate, sample_rate >> 8, sample_rate >> 16, sample_rate >> 24, // SampleRate
        byte_rate, byte_rate >> 8, byte_rate >> 16, byte_rate >> 24, // ByteRate
        0x02, 0x00, // BlockAlign
        0x10, 0x00, // BitsPerSample (16 bits)
        'd','a','t','a', // Subchunk2ID
        wav_size, wav_size >> 8, wav_size >> 16, wav_size >> 24, // Subchunk2Size
    };

    memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
}

void playback_wav(char *wav_name)
{
    printf("wav name is %s\n",wav_name);
    FILE* f_wav_play = fopen(wav_name, "r");
    if (f_wav_play == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }

    char wav_header_fmt_play[WAVE_HEADER_SIZE];

    fread(wav_header_fmt_play, 1, WAVE_HEADER_SIZE, f_wav_play);

    // printf("wav play head: %2x\n",wav_header_fmt_play[0]);

    char temp_cpr[8];
    strncpy(temp_cpr,wav_header_fmt_play,4);
    if(strstr(temp_cpr , "RIFF"))
    {
        // printf("this is wav file\n");
        strncpy(temp_cpr,wav_header_fmt_play+8,8);
        if(strstr(temp_cpr , "WAVEfmt "))
        {
            printf("this is wav file \n");

            current_wav_msg = get_wav_msg(wav_name);

            // wav size
            printf("wav size = %02x, %02x, %02x, %02x\n",wav_header_fmt_play[40],wav_header_fmt_play[41],wav_header_fmt_play[42],wav_header_fmt_play[43]);

            current_wav_msg.while_time = wav_header_fmt_play[40] + wav_header_fmt_play[41]* (1<<8) + wav_header_fmt_play[42]* (1<<16) + wav_header_fmt_play[43] * (1<<24);
            printf("while_time = %d\n",current_wav_msg.while_time);

            // wav sample rate
            current_wav_msg.sample_rate = wav_header_fmt_play[24] + wav_header_fmt_play[25]* (1<<8) + wav_header_fmt_play[26]* (1<<16) + wav_header_fmt_play[27] * (1<<24);
            printf("sample_rate = %d\n",current_wav_msg.sample_rate);

            int temp_current_time = 0;
            bytes_read = 0;

            // Start playback
            while (temp_current_time < current_wav_msg.while_time) {
                // Read the RAW samples from the microphone (char *)

                fread(i2s_readraw_buff, 1, bytes_read, f_wav_play);

                i2s_write(I2S_NUM, i2s_readraw_buff, I2S_SAMPLE_SIZE, &bytes_read, 100);

                temp_current_time += bytes_read;
                // Write the samples to the WAV file
                // printf("%ls\n",i2s_readraw_buff);
                printf("temp_current_time = %d\n",temp_current_time);
            }
        }
    }

    // ESP_LOGI(TAG, "Recording done!");
    fclose(f_wav_play);
    ESP_LOGI(TAG, "File read from SDCard");

}

void record_wav(uint32_t rec_time)
{
    // Use POSIX and C standard library functions to work with files.
    int flash_wr_size = 0;
    ESP_LOGI(TAG, "Opening file");

    char wav_header_fmt[WAVE_HEADER_SIZE];

    uint32_t flash_rec_time = I2S_BYTE_RATE * rec_time;
    generate_wav_header(wav_header_fmt, flash_rec_time, I2S_REC_SAMPLE_RATE);

    // First check if file exists before creating a new file.
    struct stat st;
    if (stat(SD_MOUNT_POINT"/record.wav", &st) == 0) {
        // Delete it if it exists
        unlink(SD_MOUNT_POINT"/record.wav");
    }

    // Create new WAV file
    FILE* f = fopen(SD_MOUNT_POINT"/record.wav", "a");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }

    // Write the header to the WAV file
    fwrite(wav_header_fmt, 1, WAVE_HEADER_SIZE, f);

    // Start recording
    while (flash_wr_size < flash_rec_time) {
        // Read the RAW samples from the microphone (char *)
        i2s_read(I2S_NUM, i2s_readraw_buff, I2S_SAMPLE_SIZE, &bytes_read, 100);
        // Write the samples to the WAV file
        // printf("%ls\n",i2s_readraw_buff);
        fwrite(i2s_readraw_buff, 1, bytes_read, f);
        flash_wr_size += bytes_read;

        printf("flash_wr_size = %d\n",flash_wr_size);
    }

    ESP_LOGI(TAG, "Recording done!");
    fclose(f);
    ESP_LOGI(TAG, "File written on SDCard");
}

void init_i2s(void)
{
    // Set the I2S configuration as PDM and 16bits per sample
    i2s_config_t i2s_config = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX  | I2S_MODE_TX , // | I2S_MODE_PDM,
        .sample_rate = I2S_REC_SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
        .dma_buf_count = 8,
        .dma_buf_len = 1024,
        .use_apll = 0,
    };

    // Set the pinout configuration (set using menuconfig)
    i2s_pin_config_t pin_config = {
        .mck_io_num = I2S_PIN_NO_CHANGE,
        .bck_io_num = I2S_PIN_BCK_GPIO,
        .ws_io_num = I2S_PIN_WS_GPIO,
        .data_out_num = I2S_PIN_DATA_PLAYBACK,
        .data_in_num = I2S_PIN_DATA_RECORD,
    };

    // Call driver installation function before any I2S R/W operation.
    ESP_ERROR_CHECK( i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL) );
    ESP_ERROR_CHECK( i2s_set_pin(I2S_NUM, &pin_config) );
    ESP_ERROR_CHECK( i2s_set_clk(I2S_NUM, I2S_REC_SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO) );
}

void app_main(void)
{
    ESP_LOGI(TAG, "PDM microphone recording Example start");
    // Mount the SDCard for recording the audio file
    mount_sdcard();

    test_sd_list();

    // Init the PDM digital microphone
    init_i2s();
    ESP_LOGI(TAG, "Starting recording for %d seconds!", I2S_REC_TIME);
    // Start Recording
    // record_wav(I2S_REC_TIME);

    char * wav_play = "/sdcard/music60.wav";
    // playback_wav(wav_play);
    // wav_play = "/sdcard/music70.wav";
    // playback_wav(wav_play);
    wav_play = "/sdcard/music120.wav";
    playback_wav(wav_play);

    // All done, unmount partition and disable SPI peripheral
    esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, card);
    ESP_LOGI(TAG, "Card unmounted");
    // Deinitialize the bus after all devices are removed
    spi_bus_free(host.slot);

    // Stop I2S driver and destroy
    ESP_ERROR_CHECK( i2s_driver_uninstall(I2S_NUM) );
}

4 结果

在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:20:04  更:2022-05-07 11:20:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:27:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码