[ESP32] I2S播放wav文件

 //代码:循环播放4首内置的wav音乐,I2S连接d类功放用NS4168芯片

//文件取样格式:Wave PCM 签字的 16bit, 采样频率:16KHz ,比特率705kbps

//demo工程打包下载:https://download.csdn.net/download/wabil/89515015

#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "esp_system.h"
#include "esp_check.h"
#include "esp_log.h"

/* Example configurations */
#define EXAMPLE_SAMPLE_RATE (16000) // 16KHZ
#define EXAMPLE_MCLK_MULTIPLE (384) // If not using 24-bit data width, 256 should be enough
#define EXAMPLE_MCLK_FREQ_HZ (EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE)
#define EXAMPLE_VOICE_VOLUME CONFIG_EXAMPLE_VOICE_VOLUME

/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (GPIO_NUM_1)   //[No used]
#define I2S_BCK_IO (GPIO_NUM_36) // SerialCK
#define I2S_WS_IO (GPIO_NUM_35)  // LRCK
#define I2S_DO_IO (GPIO_NUM_37)  // SDATA out
#define I2S_DI_IO (GPIO_NUM_19)  // SDATA in for micphone [No used]

static const char *TAG = "i2s_ns4168";
static const char err_reason[][30] = {"input param is invalid", "operation timeout"};
static i2s_chan_handle_t tx_handle = NULL;
static i2s_chan_handle_t rx_handle = NULL;

/* Import music file as buffer */

#define DECLARE_WAV_START(SND) extern const uint8_t SND##_wav_start[] asm("_binary_" #SND "_wav_start")
#define DECALARE_WAV_END(SND) extern const uint8_t SND##_wav_end[] asm("_binary_" #SND "_wav_end")

DECLARE_WAV_START(Snd01);
DECALARE_WAV_END(Snd01);

DECLARE_WAV_START(Snd02);
DECALARE_WAV_END(Snd02);

DECLARE_WAV_START(Snd03);
DECALARE_WAV_END(Snd03);

DECLARE_WAV_START(Snd_Hotel); // california_hotel
DECALARE_WAV_END(Snd_Hotel);

const uint8_t *music_group[][2] = {
    {&Snd01_wav_start, &Snd01_wav_end},
    {&Snd02_wav_start, &Snd02_wav_end},
    {&Snd03_wav_start, &Snd03_wav_end},
    {&Snd_Hotel_wav_start, &Snd_Hotel_wav_end},

};

esp_err_t play_snd_id(uint8_t snd_id, uint32_t timeout_ms)
{
    uint8_t *data_ptr_start = (uint8_t *)music_group[snd_id][0];
    uint8_t *data_ptr_end = (uint8_t *)music_group[snd_id][1];
    size_t data_len = data_ptr_end - data_ptr_start;
    uint32_t bytes_write = 0;

   // ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    vTaskDelay(150 / portTICK_PERIOD_MS);
    uint32_t tick1 = esp_log_timestamp();
    printf("[%ld] read to play:%d ,length:%d bytes.\n", tick1, snd_id, data_len);
    esp_err_t ret = i2s_channel_write(tx_handle, data_ptr_start, data_len, &bytes_write, timeout_ms);
    uint32_t tick2 = esp_log_timestamp();
    printf("[%ld] end play,written:%ld,take:%ld ms\n", tick2,bytes_write, tick2 - tick1);
    vTaskDelay(150 / portTICK_PERIOD_MS);
  //  ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));

    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "[music] i2s write failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);
        abort();
    }
    if (bytes_write <= 0)
    {
        ESP_LOGE(TAG, "[music] i2s music play failed.");
        abort();
    }

    return ret;
}

static esp_err_t i2s_driver_init(void)
{
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);
    chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
        .gpio_cfg = {
            .mclk = I2S_MCK_IO,
            .bclk = I2S_BCK_IO,
            .ws = I2S_WS_IO,
            .dout = I2S_DO_IO,
            .din = I2S_DI_IO,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };
    std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE;

    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));

    return ESP_OK;
}

static void i2s_music_task(void *args)
{
    esp_err_t ret = ESP_OK;
    size_t bytes_write = 0;
    uint8_t *data_ptr = (uint8_t *)Snd01_wav_start;

    bytes_write = Snd01_wav_end - Snd01_wav_start;
    printf("the music bin data length:%d bytes.start_addr:%p\n", bytes_write, data_ptr);

    /* (Optional) Disable TX channel and preload the data before enabling the TX channel,
     * so that the valid data can be transmitted immediately */

    ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
    ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, Snd01_wav_end - data_ptr, &bytes_write));
    //  data_ptr += bytes_write;  // Move forward the data pointer
    printf("preload data length:%d.EXAMPLE_SAMPLE_RATE=%d\n", bytes_write, EXAMPLE_SAMPLE_RATE);

    /* Enable the TX channel */
    ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
   vTaskDelay(5000 / portTICK_PERIOD_MS);
    uint8_t snd_id = 0;
    while (1)
    {

        play_snd_id(snd_id, portMAX_DELAY);
        snd_id = (snd_id + 1) % 4; // 共4个wav音效
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    // 634240 bytes are written
    printf("I2S_NS4168: BCK=%d,WS=%d,DAT_IO=%d.\n", I2S_BCK_IO, I2S_WS_IO, I2S_DO_IO);

    /* Initialize i2s peripheral */
    if (i2s_driver_init() != ESP_OK)
    {
        ESP_LOGE(TAG, "i2s driver init failed");
        abort();
    }
    else
    {
        ESP_LOGI(TAG, "i2s driver init success");
    }
    xTaskCreate(i2s_music_task, "i2s_music_task", 4096, NULL, 5, NULL);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/771223.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion【基础篇】:降噪强度(denoising strength)

提到降噪强度&#xff08;denoising strength&#xff09;&#xff0c;大家一定不会陌生&#xff0c;这个参数是图生图中最关键的参数之一。今天在Stable Diffusion Art网站看到一篇介绍降噪强度&#xff08;denoising strength&#xff09;的文章&#xff08;地址&#xff1a;…

【postgresql】版本学习

PostgreSQL 17 Beta 2 发布于2024-06-27。 PostgreSQL 17 Beta 2功能和变更功能的完整列表&#xff1a;PostgreSQL: Documentation: 17: E.1. Release 17 ​ 支持的版本&#xff1a; 16 ( 当前版本) / 15 / 14 / 13 / 12 ​ 不支持的版本&#xff1a; 11 / 10 / 9.6 / 9.5 /…

「前端」快速排序算法演示

快速排序算法演示。 布局描述 一个简单的HTML页面,用户可以在其中输入一系列用逗号分隔的数字。 一个CSS样式表,提供了一个美观大方的布局和样式。 一个JavaScript脚本,实现了快速排序算法,并在用户点击按钮时对输入的数字进行排序,并显示结果。 效果演示 核心代码 <…

Django创建项目

虚拟环境创建成功 使用命令行创建项目 创建一个文件夹&#xff0c;用pycharm打开&#xff0c;将之前创建好的虚拟环境选中&#xff08;这一步不在仔细赘述了&#xff0c;比较简单&#xff09; cd进入虚拟环境所在文件目录&#xff0c;打开虚拟环境pipenv shell 创建django项…

身边有填报志愿需求别错过!张雪峰透露今年志愿填报技巧:报专业,别报行业!(文末附稳定高薪专业推荐)

高考填报志愿是每个考生和家长都要面对的重大抉择。在当前就业形势日趋严峻、部分行业发展前景不明朗的大背景下,考生在填报志愿时更需要全面了解各个专业的就业前景,理性权衡自身兴趣特长与社会需求&#xff0c;而不是盲目跟风报考所谓的"热门专业"。 今天跟大家分…

对谈 MoonBit:AI 时代的编程语言应该是什么样子的?丨编码人声

「编码人声」是由「RTE开发者社区」策划的一档播客节目&#xff0c;关注行业发展变革、开发者职涯发展、技术突破以及创业创新&#xff0c;由开发者来分享开发者眼中的工作与生活。 本期节目&#xff0c;我们请到了 MoonBit 的创始人宏波和资深的开发者狼叔作为我们的嘉宾&…

人工智能在日常生活中的十大应用:从医疗到智能家居

人工智能已成为当今人类日常生活的重要组成部分&#xff0c;无论您是否意识到&#xff0c;它几乎在所有场景中都能提供帮助。每次您进行网络搜索、在线预订旅行、接收来自京东等购物平台的产品推荐又或是打开您的新浪、抖音时&#xff0c;都能看到影子&#xff0c;这些只是一些…

Python番外篇之代码编译与字节码

引言 关于字节码&#xff0c;不太想讲&#xff0c;不影响实际使用&#xff0c;对新手不友好…… 但是&#xff0c;涉及到新手经常碰到的问题的解惑&#xff0c;似乎又不得不讲。 最终&#xff0c;还是打算以番外篇的形式&#xff0c;稍微提一下。 不过&#xff0c;关于字节码的…

RabbitMQ入门教程(精细版二带图)

目录 六 RabbitMQ工作模式 6.1Hello World简单模式 6.1.1 什么是简单模式 6.1.2 RabbitMQ管理界面操作 6.1.3 生产者代码 6.1.4 消费者代码 6.2 Work queues工作队列模式 6.2.1 什么是工作队列模式 6.2.2 RabbitMQ管理界面操作 6.2.3 生产者代码 6.2.4 消费者代码 …

RAID详解

一、RAID存储是什么&#xff1f; RAID 存储&#xff08;Redundant Arrays of Independent Disks&#xff0c;独立磁盘冗余阵列&#xff09;是一种通过将多个独立的物理磁盘组合在一起&#xff0c;以实现更高的存储性能、数据可靠性和容错能力的技术。其主要目的是解决单个磁盘…

tapd 与国内外主流的8大项目管理软件大对比

对比Tapd与8大项目管理工具&#xff1a;PingCode、Worktile、Redmine、Teambition、广联达、Jira、禅道、飞书。 Tapd 是腾讯推出的一款敏捷开发管理工具&#xff0c;特别适合那些需要高效协作和快速迭代的敏捷开发团队。它支持多种敏捷方法论&#xff0c;包括Scrum和Kanban&am…

liunx文件系统,日志分析

文章目录 1.inode与block1.1 inode与block概述1.2 inode的内容1.3 文件存储1.4 inode的大小1.5 inode的特殊作用 2.硬链接与软链接2.1链接文件分类 3.恢复误删除的文件3.1 案例:恢复EXT类型的文件3.2 案例:恢复XFS类型的文件3.2.1 xfsdump使用限制 4.分析日志文件4.1日志文件4.…

Android10以上实现获取设备序列号功能

Android10以上实现获取设备唯一标识&#xff0c;目前只支持华为和荣耀设备。实现原理&#xff1a;通过无障碍服务读取序列号界面。 public class DeviceHelper implements Application.ActivityLifecycleCallbacks {static final String TAG "WADQ_DeviceHelper";s…

无人机智能追踪反制系统技术详解

随着无人机技术的飞速发展&#xff0c;无人机在各个领域的应用越来越广泛。然而&#xff0c;无人机的无序飞行和非法使用也带来了一系列安全隐患和威胁。因此&#xff0c;无人机智能追踪反制系统应运而生&#xff0c;成为维护公共安全和防止无人机滥用的重要工具。本文将详细介…

SPI四种模式--极性与相位

SPI的四种模式&#xff1a;相位和极性 极性 定义时钟空闲状态&#xff1a; CPOL0&#xff1a;时钟线在空闲状态为低电平 CPOL1&#xff1a;时钟线在空闲状态为高电平 这个设置决定了设备不进行通信时时钟线的状态。 兼容性&#xff1a; 不同的SPI设备可能需要不同的时钟极性…

Spring Boot 的机场投诉管理平台-计算机毕业设计源码22030

摘要 随着航空运输业的迅速发展&#xff0c;机场的客流量不断增加&#xff0c;旅客对机场服务的质量和效率也提出了更高的要求。为了提高机场的服务质量&#xff0c;及时处理旅客的投诉&#xff0c;建立一个高效、便捷的机场投诉管理平台显得尤为重要。 本项目旨在设计与实现一…

飞利浦的台灯值得入手吗?书客、松下多维度横评大分享!

随着生活品质的持续提升&#xff0c;人们对于健康的追求日益趋向精致与高端化。在这一潮流的推动下&#xff0c;护眼台灯以其卓越的护眼功效与便捷的操作体验&#xff0c;迅速在家电领域崭露头角&#xff0c;更成为了众多家庭书房中不可或缺的视力守护者。这些台灯以其精心设计…

AIGC对设计师积极性的影响

随着科技的迅猛发展&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;工具正逐渐深入设计的每个角落&#xff0c;对设计师的工作方式和思维模式产生了深远的影响。AIGC不仅极大提升了设计师的工作效率&#xff0c;更激发了他们的创新思维&#xff0c;为设计行业带来了翻…

java 基础之 反射技术_java 程序src阶段 class对象阶段 run阶段3个阶段

System.out.println(in); } publicClass[] aa1(String name, int[] password){ returnnew Class[]{String.class} ; } privatestatic void aa1(int num){ System.out.println(num“静态方法”); } public static void main(String[] args){ System.out.println(“main”…

MySQL单表千万级数据查询优化大家怎么说(评论有亮点)

题图来自APOD 上次写了一篇MySQL优化实战的文章“MySQL千万级数据从190秒优化到1秒全过程”。 这篇文章主要还是在实战MySQL优化&#xff0c;所以从造数据到查询SQL优化SQL都没有业务或者其它依赖&#xff0c;优化的技巧也不涉及软件架构就是纯SQL优化。 由于笔者经验有限和…