播放本地音频的代码

首先要在芯片存储区建立存储区域,这个加到partitions.csvz最后

spiffs,   data, spiffs,  0xD00000,  1M

下来就是在CMakeLists.txt中增加自动烧录配置

# 配置 SPIFFS 自动烧录(关键代码)
spiffs_create_partition_image(spiffs data FLASH_IN_PROJECT)

音频文件放在data文件夹下面

这个文件夹是我置顶的烧录到映像区域的文件

下面这个是头文件和配置硬件,我用的是ns416

8

// *************************************************************/

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_vfs.h"
#include "esp_spiffs.h"  // 添加SPIFFS支持

// -------------------------- 配置参数(根据硬件修改) --------------------------
#define I2S_BCLK        GPIO_NUM_15  // I2S时钟线引脚
#define I2S_WS          GPIO_NUM_16  // I2S声道选择线(LRCK)引脚
#define I2S_DOUT        GPIO_NUM_7   // I2S数据输出引脚
#define PLAY_BUFFER_SIZE 2048        // 播放缓冲区大小(2KB,可按需调整)
#define WAV_SAMPLE_RATE 16000        // 目标WAV采样率(16kHz,需与播放文件匹配)
#define WAV_BIT_DEPTH   16           // 目标WAV位深(16bit,需与播放文件匹配)

/***************************************************************/

下面是播放和测试分区文件的代码

头文件


    /*******************************************************/
    void list_spiffs_files();
    int init_ok = 0;
    esp_err_t spiffs_init();
    // 新增:WAV播放相关配置(需与你的WAV文件匹配)
    static const int WAV_BUFFER_SIZE = 2048;  // 播放缓冲区大小(2KB,可调整)
    static const int WAV_HEADER_SIZE = 44;    // 标准WAV文件头大小(固定44字节)
    // 新增:核心函数声明(读取WAV并播放)
    bool read_wav_and_play(const char* wav_path);  // 读取WAV文件并调用Write播放
    /*******************************************************/

类文件

void AudioCodec::OutputData(std::vector<int16_t>& data) {
    //Write(data.data(), data.size());

    ESP_LOGE(TAG, "++++++++++++OutputData+++++++++++++");
    // 确保先初始化(只在首次调用时执行)
    if (this->spiffs_init() != ESP_OK) {
        return;  // 初始化失败则退出
    }

    // 2. 调用核心函数:读取WAV并播放(路径替换为你的WAV文件名)
    const char* wav_path = "/spiffs/hi_idf_audio.wav";  // SPIFFS中的WAV路径
    this->read_wav_and_play(wav_path);
}
/****************************************************************************/
// -------------------------- SPIFFS初始化 --------------------------
esp_err_t AudioCodec::spiffs_init(void) {
    if (this->init_ok) return ESP_OK;  // 已初始化直接返回

    // SPIFFS配置(指定spiffs分区)
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = "spiffs",
        .max_files = 5,
        .format_if_mount_failed = true
    };

    // 执行初始化
    esp_err_t ret = esp_vfs_spiffs_register(&conf);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPIFFS初始化失败: %s", esp_err_to_name(ret));
        return ret;
    }

    this->init_ok = 1;  // 标记为已初始化
    ESP_LOGI(TAG, "SPIFFS初始化成功");

    // 每次调用都打印文件清单
    DIR *dir = opendir("/spiffs");
    if (!dir) {
        ESP_LOGE(TAG, "无法打开SPIFFS目录");
        return ret;
    }

    struct dirent *entry;
    int count = 0;
    ESP_LOGI(TAG, "=== 文件清单 ===");
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.') continue;  // 跳过.和..
        ESP_LOGI(TAG, "文件: %s", entry->d_name);
        count++;
    }
    closedir(dir);
    ESP_LOGI(TAG, "共%d个文件 ====", count);
    return ESP_OK;
}


// 核心函数:读取SPIFFS中的WAV文件,调用Write播放
bool AudioCodec::read_wav_and_play(const char* wav_path) {
    // 1. 打开WAV文件(SPIFFS路径,只读模式)
    FILE* wav_fp = fopen(wav_path, "rb");
    if (wav_fp == NULL) {
        ESP_LOGE(TAG, "打开WAV失败: %s", wav_path);
        return false;
    }

    // 2. 跳过WAV文件头(前44字节是格式信息,不是PCM数据)
    if (fseek(wav_fp, WAV_HEADER_SIZE, SEEK_SET) != 0) {
        ESP_LOGE(TAG, "跳过WAV头失败");
        fclose(wav_fp);
        return false;
    }

    // 3. 分配缓冲区(栈外分配,避免栈溢出)
    int16_t* wav_buffer = (int16_t*)malloc(WAV_BUFFER_SIZE);
    if (wav_buffer == NULL) {
        ESP_LOGE(TAG, "分配WAV缓冲区失败");
        fclose(wav_fp);
        return false;
    }

    // 4. 循环读取WAV数据并播放(核心逻辑)
    size_t read_samples = 0;  // 每次读取的PCM样本数(16bit=1个样本)
    bool play_success = true;
    while (1) {
        // 读取数据:fread返回字节数,转成样本数(1样本=2字节)
        read_samples = fread(wav_buffer, sizeof(int16_t), WAV_BUFFER_SIZE / sizeof(int16_t), wav_fp);
        if (read_samples == 0) {
            // 读取到文件末尾,播放完成
            ESP_LOGI(TAG, "WAV播放完成");
            break;
        }

        // 调用Write函数,将PCM数据写入I2S(播放)
        int written_samples = Write(wav_buffer, read_samples);
        if (written_samples != read_samples) {
            ESP_LOGE(TAG, "播放数据丢失:读取%d样本,写入%d样本", read_samples, written_samples);
            play_success = false;
            break;
        }

        // (可选)打印播放进度(调试用)
        ESP_LOGD(TAG, "播放进度:已读%d样本", read_samples);
    }

    // 5. 释放资源
    free(wav_buffer);
    fclose(wav_fp);
    return play_success;
}

/****************************************************************************/

大体就是这样,因为嵌入别的代码的一部分,不能直接使用,可以借鉴。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CDialog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值