ESP32語音交互之三-----------ESP32-LyraTv4.3開發板運行SD卡播放音樂

學習ADF框架,不能錯過音樂播放,本篇博客記錄如何通過SD卡播放音樂:

上代碼前先看這兩張圖:

這兩圖基本就是ADF框架播放mp3的流程:首先將MP3解碼器和I2S流兩個元素添加進管道,解碼器的輸入是MP3文件數據流,I2S流將解碼後的音頻數據輸出到片外,各應用程序之間通過事件接口通信。

上代碼:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "board.h"
#include "audio_pipeline.h"
#include "fatfs_stream.h"
#include "i2s_stream.h"
#include "raw_stream.h"
#include "esp_audio.h"

#include "mp3_decoder.h"
#include "filter_resample.h"
#include "rec_eng_helper.h"

static const char *TAG = "SDCARD_MP3_EXAMPLE";

static esp_audio_handle_t setup_player()                           //播放器
{
    esp_audio_handle_t player = NULL;
    esp_audio_cfg_t cfg = DEFAULT_ESP_AUDIO_CONFIG();
    audio_board_handle_t board_handle = audio_board_init();
    cfg.vol_handle = board_handle->audio_hal;  //音量
    cfg.prefer_type = ESP_AUDIO_PREFER_MEM;
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
    cfg.resample_rate = 16000;//設置重採樣率
#else
    cfg.resample_rate = 48000;
#endif
    player = esp_audio_create(&cfg);
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);//音量
    fatfs_stream_cfg_t fs_reader = FATFS_STREAM_CFG_DEFAULT();
    fs_reader.type = AUDIO_STREAM_READER;
    raw_stream_cfg_t raw_reader = RAW_STREAM_CFG_DEFAULT();
    raw_reader.type = AUDIO_STREAM_READER;
    esp_audio_input_stream_add(player, raw_stream_init(&raw_reader));//
    esp_audio_input_stream_add(player, fatfs_stream_init(&fs_reader));//
    mp3_decoder_cfg_t  mp3_dec_cfg  = DEFAULT_MP3_DECODER_CONFIG();
    esp_audio_codec_lib_add(player, AUDIO_CODEC_TYPE_DECODER, mp3_decoder_init(&mp3_dec_cfg));//初始化mp3 decoder
    i2s_stream_cfg_t i2s_writer = I2S_STREAM_CFG_DEFAULT();

#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
    i2s_writer.i2s_config.sample_rate = 16000;
#else
    i2s_writer.i2s_config.sample_rate = 48000;
#endif

    i2s_writer.type = AUDIO_STREAM_WRITER;
    audio_element_handle_t i2s_stream_writer = i2s_stream_init(&i2s_writer);//初始化i2s stream
    esp_audio_output_stream_add(player, i2s_stream_writer);
    esp_audio_vol_set(player, 100);//設置音量
        
    ESP_LOGI(TAG, "esp_audio instance is:%p\r\n", player);
    return player;
}

void app_main()
{

#if defined CONFIG_ESP_LYRAT_V4_3_BOARD
    gpio_config_t gpio_conf = {
        .pin_bit_mask = 1UL << get_green_led_gpio(),//LED燈設置
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 0,
        .pull_down_en = 0,
        .intr_type = 0
    };
    gpio_config(&gpio_conf);
#endif

    esp_log_level_set("*", ESP_LOG_WARN);
    esp_log_level_set(TAG, ESP_LOG_INFO);

    audio_pipeline_handle_t pipeline;                                //管道
    audio_element_handle_t i2s_stream_reader, filter, raw_read;      //音頻元素
    esp_audio_handle_t player;


    ESP_LOGI(TAG, "[ 1 ] Start codec chip");//初始化codec 芯片
    esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
    audio_board_sdcard_init(esp_periph_set_init(&periph_cfg));

    ESP_LOGI(TAG, "[ 2.0 ] Create audio pipeline for recording");//創建音頻管道給recording
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[ 2.1 ] Create i2s stream to read audio data from codec chip");//爲讀音頻數據創建i2s stream
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.i2s_config.sample_rate = 48000;
    i2s_cfg.type = AUDIO_STREAM_READER;

#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
    i2s_cfg.i2s_config.sample_rate = 16000;
    i2s_cfg.i2s_port = 1;
    i2s_cfg.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
    i2s_stream_reader = i2s_stream_init(&i2s_cfg);//初始化i2s
#else
    i2s_stream_reader = i2s_stream_init(&i2s_cfg);
    ESP_LOGI(TAG, "[ 2.2 ] Create filter to resample audio data");//爲重採樣音頻數據創建filter
    rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
    rsp_cfg.src_rate = 48000;
    rsp_cfg.src_ch = 2;
    rsp_cfg.dest_rate = 16000;
    rsp_cfg.dest_ch = 1;
    filter = rsp_filter_init(&rsp_cfg);
#endif

    ESP_LOGI(TAG, "[ 2.3 ] Create raw to receive data");//爲接收數據創建raw
    raw_stream_cfg_t raw_cfg = {
        .out_rb_size = 8 * 1024,
        .type = AUDIO_STREAM_READER,
    };
    raw_read = raw_stream_init(&raw_cfg);

    ESP_LOGI(TAG, "[ 3 ] Register all elements to audio pipeline");//註冊所有元素到管道
    audio_pipeline_register(pipeline, i2s_stream_reader, "i2s");
    audio_pipeline_register(pipeline, raw_read, "raw");

#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
    ESP_LOGI(TAG, "[ 4 ] Link elements together [codec_chip]-->i2s_stream-->raw-->[SR]");
    audio_pipeline_link(pipeline, (const char *[]) {"i2s",  "raw"}, 2);
#else
    audio_pipeline_register(pipeline, filter, "filter");
    ESP_LOGI(TAG, "[ 4 ] Link elements together [codec_chip]-->i2s_stream-->filter-->raw-->[SR]");
    audio_pipeline_link(pipeline, (const char *[]) {"i2s", "filter", "raw"}, 3);
#endif

    player = setup_player();

    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");//開始音頻管道
    audio_pipeline_run(pipeline);
    esp_audio_sync_play(player, "file://sdcard/test.mp3", 0);//SD卡里文件名爲test的mp3文件


    ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");//停止音頻管道
  
    audio_pipeline_terminate(pipeline);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_remove_listener(pipeline);

    audio_pipeline_unregister(pipeline, raw_read);
    audio_pipeline_unregister(pipeline, i2s_stream_reader);
    audio_pipeline_unregister(pipeline, filter);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(raw_read);
    audio_element_deinit(i2s_stream_reader);
    audio_element_deinit(filter);

    ESP_LOGI(TAG, "[ 7 ] Destroy model");

}

此程序是根據ADF例程中\examples\speech_recognition\asr例程修改而來,和player文件裏的例程有所不同!這個修改後的例程將播放器模塊化,方便後面的程序調用,一句:esp_audio_sync_play();即可調用播放!後面將根據這個模塊,結合語音喚醒和命令詞做進一步修改!用語言控制播放!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章