I2S_ADC_Mic_SD_WAV_Speaker
unknown
c_cpp
2 years ago
7.8 kB
189
Indexable
// Libraries
#include <driver/i2s.h>
#include <SPI.h> // Using SPI interface for the SD card
#include <SD.h> // A dedicated library for the SD card
#include "FS.h"
// Defenitions
#define I2S_SAMPLE_RATE 16000 // 16KHz
#define ADC_INPUT ADC1_CHANNEL_5 //pin 33
#define I2S_SAMPLE_BITS I2S_BITS_PER_SAMPLE_16BIT // 16 Bits
#define NUM_OF_CHANNELS 1 // 1 Channel
#define RECORD_TIME 10 // 10 Seconds of recording
#define BUTTON_MIC 32 // Mic's Button pin number
#define BUTTON_SPEAK 35 // Speaker's Button pin number
// Global variables
const int chipSelect = 5;
uint32_t wavSize = NUM_OF_CHANNELS * I2S_SAMPLE_RATE * (I2S_SAMPLE_BITS / 8) * RECORD_TIME;
String file_name = "/test.wav";
void setup() {
// Serial monitor
Serial.begin(115200);
delay(1000);
Serial.println("wavSize = " + String(wavSize));
// Button
pinMode(BUTTON_MIC, INPUT);
pinMode(BUTTON_SPEAK, INPUT);
// Initialize the I2S peripheral
i2sInit();
// SD card:
// see if the card is present and can be initialized:
while (!SD.begin(chipSelect)) // If there was a faliure
{
Serial.println("Card failed, or not present");
delay(1000);
}
Serial.println("card initialized.\nReady to record!");
delay(1000);
}
void loop() {
if (digitalRead(BUTTON_MIC)) // Record button pushed = Start recording
{
save_audio();
}
if (digitalRead(BUTTON_SPEAK)) // Playback button pushed = Start playing
{
play_audio();
}
}
// Mic functions:
void i2sInit()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX |I2S_MODE_ADC_BUILT_IN | I2S_MODE_TX), // Both TX (Speaker) and RX (Mic)
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
//.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Only one channel
//.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
//.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.intr_alloc_flags = 0,
.dma_buf_count = 4,
.dma_buf_len = 128,
.use_apll = 1,
};
static const i2s_pin_config_t pin_config = { // For the Speaker
.bck_io_num = 27, // The bit clock connectiom, goes to pin 27 of ESP32
.ws_io_num = 26, // Word select, also known as word select or left right clock
.data_out_num = 25, // Data out from the ESP32, connect to DIN on 38357A
.data_in_num = I2S_PIN_NO_CHANGE // we are not interested in I2S data into the ESP32
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_sample_rates(I2S_NUM_0, I2S_SAMPLE_RATE); //set sample rate
i2s_set_pin(I2S_NUM_0,&pin_config);
i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
i2s_adc_enable(I2S_NUM_0);
}
void save_audio() { // Recording audio with the MAX9814, and saving to an SD card
//Serial.println("Opening the file");
File dataFile = SD.open(file_name, FILE_APPEND);
//Serial.println("File opened");
// The 4 high bits are the channel, and the data is inverted
uint16_t offset = (int)ADC_INPUT * 0x1000 + 0xFFF;
uint32_t rec_len = 0;
size_t bytes_read;
//int buff_len = 2;
int buff_len = 32;
uint16_t buffer[buff_len] = {0};
byte wav_head[44];
int min_val = 5000, max_val = 0;
wavHeader(wav_head, wavSize);
for (int i = 0; i < 44; i++)
{
dataFile.write( wav_head[i] );
}
Serial.println("Rec starting!");
int rec_time = millis();
while (rec_len < wavSize)
{
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, portMAX_DELAY);
rec_len += bytes_read;
for (int i = 0; i < buff_len; i++)
{
// Explanation: I want to save 16 bits of information from
// every reading.Therfore, I take the uint16_t value, and
// compare it (AND gate) first to an 8 bit 1 (0xff = 0000000011111111)
// Then, I move the 16 bit values to the right by 8 bits
// (taking the leftmost values) and compares them to 0xff
dataFile.write(byte( (offset - buffer[i]) & 0xff));
dataFile.write(byte( ((offset - buffer[i])>>8) & 0xff));
}
}
rec_time = millis() - rec_time;
// Read from file and find the maximum value
dataFile.close();
Serial.println("Rec finished!");
Serial.println("record length: " + String(rec_len));
Serial.println("wavSize: " + String(wavSize));
Serial.println("Expected rec time = " + String(RECORD_TIME));
Serial.println("Actuall rec time = " + String(rec_time / 1000.0));
}
void play_audio() { // Playing audio from a SD card with the MAX98357
//Serial.println("Opening the file");
//File dataFile = SD.open(file_name, FILE_READ);
File dataFile = SD.open(file_name);
int buff_len = 1024;
uint8_t buffer[buff_len] = {0}; // Reading 1 byte each time, so uint8_t
size_t BytesWritten;
dataFile.seek(44); // The first 44 bytes are wav header, after that there is real audio data
Serial.println("Start playing!");
int rec_time = millis();
while(dataFile.available())
{
dataFile.read(buffer,buff_len);
i2s_write(I2S_NUM_0,buffer,sizeof(buffer),&BytesWritten,portMAX_DELAY);
}
rec_time = millis() - rec_time;
Serial.println("Finished playing!");
Serial.println("Played for " + String(rec_time/1000.0) + " seconds");
dataFile.seek(44); // The first 44 bytes are wav header, after that there is real audio data
dataFile.close();
}
// WAV
const int headerSize = 44;
void wavHeader(byte* header, int wavSize) {
// First 4 are for the name RIFF
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
// Next is the file size, which can be calculated by the formula below:
// (I2S_NUM_OF_CHANNELS * I2S_SAMPLE_RATE * (I2S_SAMPLE_BITS / 8) * RECORD_TIME)
// I multiply by
unsigned int fileSize = wavSize + headerSize - 8;
header[4] = (byte)(fileSize & 0xFF);
header[5] = (byte)((fileSize >> 8) & 0xFF);
header[6] = (byte)((fileSize >> 16) & 0xFF);
header[7] = (byte)((fileSize >> 24) & 0xFF);
// More strings
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
// fmt, including null
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
// Size of format section (Not inverted)
header[16] = 0x10;
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
// Format (1 = PCM)
header[20] = 0x01;
header[21] = 0x00;
// Channels (1=mono, 2=stereo)
//header[22] = 0x01;
header[22] = 0x01;
header[23] = 0x00;
// Sample rate (make sure it matches I2S_SAMPLE_RATE), currently 16KHz
header[24] = 0x80;
header[25] = 0x3E;
header[26] = 0x00;
header[27] = 0x00;
// Byte rate (Sample rate * channels * bits per sample / 8), currently (16,000*1*16/8) = 32,000
header[28] = 0x00;
header[29] = 0x7D;
header[30] = 0x00;
header[31] = 0x00;
// Block allign : channels * bits per sample / 8
header[32] = 0x02;
header[33] = 0x00;
// Bits per sample (according to I2S_SAMPLE_BITS)
header[34] = 0x10;
header[35] = 0x00;
// Data name
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
// Size of data
header[40] = (byte)(wavSize & 0xFF);
header[41] = (byte)((wavSize >> 8) & 0xFF);
header[42] = (byte)((wavSize >> 16) & 0xFF);
header[43] = (byte)((wavSize >> 24) & 0xFF);
}
Editor is loading...
Leave a Comment