// will play many audio file formats, mp3,aac,flac etc.
// See github page : https://github.com/schreibfaul1/ESP32-audioI2S
#include "Arduino.h"
#include "Audio.h"
#include "SD.h"
#include "FS.h"
// Digital I/O used
#define SD_CS 5
#define SPI_MOSI 23 // SD Card
#define SPI_MISO 19
#define SPI_SCK 18
#define I2S_DOUT 25
#define I2S_BCLK 27 // I2S
#define I2S_LRC 26
#define REC_BUTTON 21
#define PLAY_BUTTON 4
#define MIC_PIN 32
#define SAMPLE_RATE 8000
size_t byteCounter = 0;
uint32_t fileSize;
uint16_t sampleNum = 0, samplesWritten = 0, samplesArray16[128], sampleRead16;
uint8_t samplesArray8[256];
uint8_t samplesRead8[2];
bool isRecording = true, isPlaying = false, alternator = false;
char fileName[] = "/0004.wav";
Audio audio1, audio2;
File audioFile, bufferFile;
void setup() {
pinMode(REC_BUTTON, INPUT_PULLUP);
pinMode(PLAY_BUTTON, INPUT_PULLUP);
//pinMode(SD_CS, OUTPUT);
//digitalWrite(SD_CS, HIGH);
//SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
Serial.begin(9600);
delay(1000);
if (!SD.begin(SD_CS)) {
Serial.println("SD card initialization failed.");
return;
}
Serial.println("SD card initialized.");
audioFile = SD.open("/0006.wav", FILE_WRITE);
if (!audioFile) {
Serial.println("Failed to open WAV file for writing.");
return;
}
Serial.println("WAV file opened successfuly.");
bufferFile = SD.open("/0007.txt");
if (!bufferFile) {
Serial.println("Failed to open Text buffer file for writing.");
return;
}
Serial.println("TEXT file opened successfuly.");
writeWavHeader(audioFile);
audioFile.close();
audio1.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
audio1.setVolume(21);
}
void loop() {
if (isRecording) {
uint16_t micValue = analogRead(MIC_PIN);
samplesArray16[sampleNum] = micValue;
sampleNum++;
if (sampleNum == 128) {
for (int i = 0; i < 128; i++) {
samplesArray8[i * 2] = (uint8_t)((samplesArray16[i] & 0xFF00) >> 8);
samplesArray8[i * 2 + 1] = (uint8_t)(samplesArray16[i] & 0x00FF);
}
bufferFile.write(samplesArray8, 256);
memset(samplesArray16, 0, sizeof(samplesArray16));
sampleNum = 0;
}
samplesWritten++;
}
if (digitalRead(REC_BUTTON) == LOW && isRecording) {
delay(50);
if (digitalRead(REC_BUTTON) == LOW) {
Serial.println("Recording stopped!");
isRecording = false;
audioFile = SD.open("/0006.wav", FILE_WRITE);
for(int i = 0; i < samplesWritten; i++) {
bufferFile.read(samplesRead8, 2);
sampleRead16 = ((uint16_t)samplesRead8[1] << 8) | samplesRead8[0];
writeSample(audioFile, sampleRead16);
}
bufferFile.close();
headerSizeFiller();
audioFile.close();
fileSizePrinter();
Serial.println("Bytes written: " + String(byteCounter));
}
}
if (digitalRead(PLAY_BUTTON) == LOW && !isPlaying) {
delay(50);
if (digitalRead(PLAY_BUTTON == LOW)) {
isPlaying = true;
Serial.println("Button pressed. Playing audio...");
playAudio();
}
}
}
void playAudio() {
audio1.connecttoFS(SD, "/0006.wav");
while(true) {
audio1.processLocalFile(30000000, 2);
if (digitalRead(PLAY_BUTTON) == LOW && isPlaying) {
delay(1000);
if (digitalRead(PLAY_BUTTON == LOW)) {
isPlaying = true;
Serial.println("Button pressed. Playing audio...");
playAudio();
}
}
}
/*uint8_t buf[4];
int16_t buf16[2];
size_t bytes_read;
while(true) {
bytes_read = audioFile.read(buf, 4);
//convertArray(buf, buf16, 2);
buf16[0] = (buf[1] << 8) | buf[0];
buf16[1] = (buf[3] << 8) | buf[2];
audio1.playSample(buf16);
buf16[0] = ((buf16[0] & 0xff) - 128) << 8;
buf16[1] = ((buf16[1] & 0xff) - 128) << 8;
}*/
}
void writeSample(File &file, uint16_t sample) {
// Ensure sample is within the range of a 12-bit signed integer
sample = constrain(sample, -2048, 2047);
// Convert 12-bit sample to 16-bit format for WAV file (left-justified)
uint16_t sample16 = sample & 0xFFF; // Use lower 12 bits
// Write a 16-bit sample to the WAV file
uint8_t bytes[2];
bytes[0] = sample16 & 0xFF; // Least significant byte
bytes[1] = (sample16 >> 8) & 0xFF; // Most significant byte
file.write(bytes, 2); // Return the number of bytes written
byteCounter += 2;
}
void fileSizePrinter() {
audioFile = SD.open("/0006.wav", FILE_READ);
fileSize = audioFile.size();
Serial.println("File size: " + String(fileSize));
audioFile.close();
}
void headerSizeFiller() {
audioFile.seek(4);
audioFile.write((uint8_t*)&fileSize, 4); // File size placeholder
audioFile.seek(40);
audioFile.write((uint8_t*)&byteCounter, 4); // File size placeholder
void writeWavHeader(File &file) {
// Write WAV file header
const char fileSizeH[] = "----";
const char dataSize[] = "----";
const char riffHeader[] = "RIFF";
file.write((const uint8_t*)riffHeader, 4); // RIFF header
file.write((uint8_t*)&fileSizeH, 4); // File size placeholder
const char waveHeader[] = "WAVE";
file.write((const uint8_t*)waveHeader, 4); // WAV format
const char fmtHeader[] = "fmt ";
file.write((const uint8_t*)fmtHeader, 4); // Format chunk
uint32_t fmtSize = 16;
file.write((uint8_t*)&fmtSize, 4); // Format chunk size
uint16_t audioFormat = 1; // PCM format
file.write((uint8_t*)&audioFormat, 2); // Audio format
uint16_t numChannels = 1; // Mono
file.write((uint8_t*)&numChannels, 2); // Number of channels
uint32_t sampleRate = SAMPLE_RATE; // Sample rate
file.write((uint8_t*)&sampleRate, 4); // Sample rate
uint32_t byteRate = sampleRate * numChannels * (16 / 8); // Byte rate
file.write((uint8_t*)&byteRate, 4); // Byte rate
uint16_t blockAlign = numChannels * (16 / 8); // Block align
file.write((uint8_t*)&blockAlign, 2); // Block align
uint16_t bitsPerSample = 16; // Bits per sample
file.write((uint8_t*)&bitsPerSample, 2); // Bits per sample
const char dataHeader[] = "data";
file.write((const uint8_t*)dataHeader, 4); // Data chunk
file.write((uint8_t*)&dataSize, 4); // Data size placeholder
}