Closed fssqawj closed 2 months ago
Please try wav.
#define WAVE_HEADER_SIZE 44
#define EXAMPLE_SAMPLE_RATE (32000)
inline void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate, uint8_t channels, uint32_t byte_rate){
// See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8;
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)
channels, 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));
}
uint32_t bytesread = 0;
uint8_t mic_buffer[2048];
int32_t wrote_cycle = 300;
generate_wav_header((char*)mic_buffer, 2048 * wrote_cycle, EXAMPLE_SAMPLE_RATE*2, 1, EXAMPLE_SAMPLE_RATE*2);
File file = SD.open("/test.wav", FILE_WRITE);
file.write(mic_buffer, WAVE_HEADER_SIZE);
while (wrote_cycle--)
{
esp_err_t err = i2s_read(I2S_NUM, mic_buffer, sizeof(mic_buffer), &bytesread, 1000);
file.write(mic_buffer, bytesread);
}
Please reopen this issue if you still need it.
Please try wav.
#define WAVE_HEADER_SIZE 44 #define EXAMPLE_SAMPLE_RATE (32000) inline void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate, uint8_t channels, uint32_t byte_rate){ // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/ uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8; 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) channels, 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)); } uint32_t bytesread = 0; uint8_t mic_buffer[2048]; int32_t wrote_cycle = 300; generate_wav_header((char*)mic_buffer, 2048 * wrote_cycle, EXAMPLE_SAMPLE_RATE*2, 1, EXAMPLE_SAMPLE_RATE*2); File file = SD.open("/test.wav", FILE_WRITE); file.write(mic_buffer, WAVE_HEADER_SIZE); while (wrote_cycle--) { esp_err_t err = i2s_read(I2S_NUM, mic_buffer, sizeof(mic_buffer), &bytesread, 1000); file.write(mic_buffer, bytesread); }
尝试加了 wav header,仍然有问题 audio_0605.zip
InitI2SSpeakOrMic(MODE_MIC);
int cnt = 50;
generate_wav_header((char*)microphonedata0, cnt * RECORD_BUFFER_SIZE, 8000, 1, 8000);
audioDataFile.write(microphonedata0, WAVE_HEADER_SIZE);
while (cnt --) {
Serial.println(cnt);
i2s_read(Speak_I2S_NUMBER,
microphonedata0, RECORD_BUFFER_SIZE,
&byte_read, (100 / portTICK_RATE_MS));
audioDataFile.write(microphonedata0, RECORD_BUFFER_SIZE);
}
I2S 设置:
bool InitI2SSpeakOrMic(int mode) { // Init I2S. 初始化I2S
esp_err_t err = ESP_OK;
i2s_driver_uninstall(
Speak_I2S_NUMBER); // Uninstall the I2S driver. 卸载I2S驱动
i2s_comm_format_t comm_fmt;
comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode.
// 设置I2S工作模式
.sample_rate = 8000, // Set the I2S sampling rate. 设置I2S采样率
.bits_per_sample =
I2S_BITS_PER_SAMPLE_16BIT,
.channel_format =
I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式
.communication_format = comm_fmt,
.intr_alloc_flags =
ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志
.dma_buf_count = 8, // DMA buffer count. DMA缓冲区计数
.dma_buf_len = 128, // DMA buffer length. DMA缓冲区长度
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = -1,
.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
};
if (mode == MODE_MIC) {
i2s_config.mode =
(i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
} else {
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
i2s_config.use_apll = false; // I2S clock setup. I2S时钟设置
i2s_config.tx_desc_auto_clear =
true; // Enables auto-cleanup descriptors for understreams.
// 开启欠流自动清除描述符
}
// Install and drive I2S. 安装并驱动I2S
err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL);
i2s_pin_config_t tx_pin_config;
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0))
tx_pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
#endif
tx_pin_config.bck_io_num =
CONFIG_I2S_BCK_PIN; // Link the BCK to the CONFIG_I2S_BCK_PIN pin.
// 将BCK链接至CONFIG_I2S_BCK_PIN引脚
tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN; // ...
tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN; // ...
tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; // ...
err +=
i2s_set_pin(Speak_I2S_NUMBER,
&tx_pin_config); // Set the I2S pin number. 设置I2S引脚编号
err += i2s_set_clk(
Speak_I2S_NUMBER, 8000, I2S_BITS_PER_SAMPLE_16BIT,
I2S_CHANNEL_MONO); // Set the clock and bitwidth used by I2S Rx and Tx.
// 设置I2S RX、Tx使用的时钟和位宽
return true;
}
I can't reopen this issue.
#include <M5Unified.h>
#include <Arduino.h>
#include <driver/gpio.h>
#include "driver/i2s.h"
#include <math.h>
#include <SPI.h>
#include <SD.h>
#define TAG "Main"
#define UTILS_WAVE_HEADER_SIZE 44
static uint8_t audio_buffer[2048];
void utils_generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate, uint8_t channels, uint32_t byte_rate){
// See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
uint32_t file_size = wav_size + UTILS_WAVE_HEADER_SIZE - 8;
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)
channels, 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));
}
static void mic_test()
{
int n = 100;
auto file = SD.open("/test.wav", FILE_WRITE);
if (!file) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
utils_generate_wav_header((char*)audio_buffer, n * sizeof(audio_buffer), 16000, 1, 16000 * 2);
file.write(audio_buffer, UTILS_WAVE_HEADER_SIZE);
while (n--)
{
size_t bytes_read;
esp_err_t err = i2s_read(I2S_NUM_0, audio_buffer, sizeof(audio_buffer), &bytes_read, 1000);
file.write(audio_buffer, bytes_read);
if (err != ESP_OK) {
ESP_LOGE(TAG, "I2S Read failed, errno = %d", err);
break;
}
}
file.close();
i2s_stop(I2S_NUM_0);
i2s_zero_dma_buffer(I2S_NUM_0);
i2s_driver_uninstall(I2S_NUM_0);
printf("Done\n");
}
static esp_err_t _pdm_mic_init(uint32_t sample_rate, int8_t pin_ws, int8_t pin_data)
{
esp_err_t err = ESP_OK;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = sample_rate,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
.dma_buf_count = 4,
.dma_buf_len = 256,
.use_apll = 0,
};
i2s_pin_config_t i2s_mic_pins = {
.bck_io_num = I2S_PIN_NO_CHANGE,
.ws_io_num = pin_ws,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = pin_data,
};
err = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); // PDM mode only supported in I2S_NUM_0
if (err != ESP_OK) {
return err;
}
err = i2s_set_pin(I2S_NUM_0, &i2s_mic_pins);
if (err != ESP_OK) {
return err;
}
err = i2s_start(I2S_NUM_0);
if (err != ESP_OK) {
return err;
}
return err;
}
extern "C" void app_main()
{
auto config = M5.config();
config.internal_spk = false;
config.internal_mic = false;
config.internal_imu = false;
config.internal_rtc = false;
M5.begin(config);
M5.Power.Axp192.setGPIO2(1);
M5.Lcd.fillScreen(GREEN);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(2);
SPI.begin(18, 38, 23);
SD.begin(4, SPI, 20000000);
printf("SD Card Size: %llu\n", SD.cardSize() / 1024 / 1024);
_pdm_mic_init(16000, 0, 34);
mic_test();
while (1)
{
delay(10);
}
}
Tryout this complete arduino code, this is working fine with builtin M5StackCore2 microphone (which on the base board). If issue still present, try another mic.
Please try wav.
#define WAVE_HEADER_SIZE 44 #define EXAMPLE_SAMPLE_RATE (32000) inline void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate, uint8_t channels, uint32_t byte_rate){ // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/ uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8; 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) channels, 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)); } uint32_t bytesread = 0; uint8_t mic_buffer[2048]; int32_t wrote_cycle = 300; generate_wav_header((char*)mic_buffer, 2048 * wrote_cycle, EXAMPLE_SAMPLE_RATE*2, 1, EXAMPLE_SAMPLE_RATE*2); File file = SD.open("/test.wav", FILE_WRITE); file.write(mic_buffer, WAVE_HEADER_SIZE); while (wrote_cycle--) { esp_err_t err = i2s_read(I2S_NUM, mic_buffer, sizeof(mic_buffer), &bytesread, 1000); file.write(mic_buffer, bytesread); }
尝试加了 wav header,仍然有问题 audio_0605.zip
InitI2SSpeakOrMic(MODE_MIC); int cnt = 50; generate_wav_header((char*)microphonedata0, cnt * RECORD_BUFFER_SIZE, 8000, 1, 8000); audioDataFile.write(microphonedata0, WAVE_HEADER_SIZE); while (cnt --) { Serial.println(cnt); i2s_read(Speak_I2S_NUMBER, microphonedata0, RECORD_BUFFER_SIZE, &byte_read, (100 / portTICK_RATE_MS)); audioDataFile.write(microphonedata0, RECORD_BUFFER_SIZE); }
I2S 设置:
bool InitI2SSpeakOrMic(int mode) { // Init I2S. 初始化I2S esp_err_t err = ESP_OK; i2s_driver_uninstall( Speak_I2S_NUMBER); // Uninstall the I2S driver. 卸载I2S驱动 i2s_comm_format_t comm_fmt; comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S); i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode. // 设置I2S工作模式 .sample_rate = 8000, // Set the I2S sampling rate. 设置I2S采样率 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式 .communication_format = comm_fmt, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志 .dma_buf_count = 8, // DMA buffer count. DMA缓冲区计数 .dma_buf_len = 128, // DMA buffer length. DMA缓冲区长度 .use_apll = false, .tx_desc_auto_clear = true, .fixed_mclk = -1, .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT, }; if (mode == MODE_MIC) { i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM); } else { i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); i2s_config.use_apll = false; // I2S clock setup. I2S时钟设置 i2s_config.tx_desc_auto_clear = true; // Enables auto-cleanup descriptors for understreams. // 开启欠流自动清除描述符 } // Install and drive I2S. 安装并驱动I2S err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL); i2s_pin_config_t tx_pin_config; #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0)) tx_pin_config.mck_io_num = I2S_PIN_NO_CHANGE; #endif tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN; // Link the BCK to the CONFIG_I2S_BCK_PIN pin. // 将BCK链接至CONFIG_I2S_BCK_PIN引脚 tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN; // ... tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN; // ... tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; // ... err += i2s_set_pin(Speak_I2S_NUMBER, &tx_pin_config); // Set the I2S pin number. 设置I2S引脚编号 err += i2s_set_clk( Speak_I2S_NUMBER, 8000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); // Set the clock and bitwidth used by I2S Rx and Tx. // 设置I2S RX、Tx使用的时钟和位宽 return true; }
The byterate shoulde be sample rate * 2, since one sample contains two byte :)
#include <M5Unified.h> #include <Arduino.h> #include <driver/gpio.h> #include "driver/i2s.h" #include <math.h> #include <SPI.h> #include <SD.h> #define TAG "Main" #define UTILS_WAVE_HEADER_SIZE 44 static uint8_t audio_buffer[2048]; void utils_generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate, uint8_t channels, uint32_t byte_rate){ // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/ uint32_t file_size = wav_size + UTILS_WAVE_HEADER_SIZE - 8; 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) channels, 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)); } static void mic_test() { int n = 100; auto file = SD.open("/test.wav", FILE_WRITE); if (!file) { ESP_LOGE(TAG, "Failed to open file for writing"); return; } utils_generate_wav_header((char*)audio_buffer, n * sizeof(audio_buffer), 16000, 1, 16000 * 2); file.write(audio_buffer, UTILS_WAVE_HEADER_SIZE); while (n--) { size_t bytes_read; esp_err_t err = i2s_read(I2S_NUM_0, audio_buffer, sizeof(audio_buffer), &bytes_read, 1000); file.write(audio_buffer, bytes_read); if (err != ESP_OK) { ESP_LOGE(TAG, "I2S Read failed, errno = %d", err); break; } } file.close(); i2s_stop(I2S_NUM_0); i2s_zero_dma_buffer(I2S_NUM_0); i2s_driver_uninstall(I2S_NUM_0); printf("Done\n"); } static esp_err_t _pdm_mic_init(uint32_t sample_rate, int8_t pin_ws, int8_t pin_data) { esp_err_t err = ESP_OK; i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM), .sample_rate = sample_rate, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2, .dma_buf_count = 4, .dma_buf_len = 256, .use_apll = 0, }; i2s_pin_config_t i2s_mic_pins = { .bck_io_num = I2S_PIN_NO_CHANGE, .ws_io_num = pin_ws, .data_out_num = I2S_PIN_NO_CHANGE, .data_in_num = pin_data, }; err = i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); // PDM mode only supported in I2S_NUM_0 if (err != ESP_OK) { return err; } err = i2s_set_pin(I2S_NUM_0, &i2s_mic_pins); if (err != ESP_OK) { return err; } err = i2s_start(I2S_NUM_0); if (err != ESP_OK) { return err; } return err; } extern "C" void app_main() { auto config = M5.config(); config.internal_spk = false; config.internal_mic = false; config.internal_imu = false; config.internal_rtc = false; M5.begin(config); M5.Power.Axp192.setGPIO2(1); M5.Lcd.fillScreen(GREEN); M5.Lcd.setTextColor(WHITE); M5.Lcd.setTextSize(2); SPI.begin(18, 38, 23); SD.begin(4, SPI, 20000000); printf("SD Card Size: %llu\n", SD.cardSize() / 1024 / 1024); _pdm_mic_init(16000, 0, 34); mic_test(); while (1) { delay(10); } }
Tryout this complete arduino code, this is working fine with builtin M5StackCore2 microphone (which on the base board). If issue still present, try another mic.
Thanks for your code~
I have find the problem, i'm using a lib named ESP8266_multipart for uploading the local sd wav file to the server. The problem is that the transmitted data is incorrect(I thought there was not much difference between esp32 and esp8266), I'm trying to fix this...
Sorry again for misleading you.
问题描述: 使用 M5Core2 录音存储 pcm 文件,然后从 pcm 文件读数据,使用 I2S 可以播放(音量较低,听着也有杂音,但是能正常听清内容)。但是从电脑打开该 pcm 文件,不能正常播放(进而导致 ASR 服务不能正常进行识别)。 怀疑过电脑打开 pcm 设置不对,所以尝试了电脑能正常播放的 WAV(PCM+header),M5Core2 也能正常播放该 WAV 文件。也尝试了电脑换不同的参数打开(虽然很确定录音参数,以防万一^-^!),包括各种采样率,位宽,大小端,声道数 等,也不能正常播放。同时,换了各种采样率/I2S参数进行录音,并不奏效。基本断定是获取的 pcm 文件本身就有问题。 使用该 repo 提供的录音样例 https://github.com/m5stack/M5Core2/blob/master/examples/Basics/record/record.ino ,存储为pcm文件,也有该问题。 所以感觉是 M5Core2 录音存储的 PCM 文件格式问题 或者是 pdm 麦克风的问题。请了解的同学提供下解决问题的思路~
相关文件:
官方提供的录音样例,把 read 数据存储到 pcm 文件
录音语句:“你好,请问你叫什么名字” test_example.zip
打开方式:
波形文件:
可以看到不是正常的波形
录音部分代码:
M5Core2 SPK 录音/播放 I2S 设置:
https://github.com/m5stack/M5Core2/blob/master/src/Speaker.cpp