Project Developement

Testing

  1. Voice Recognition
  2. As I needed to make the toy as a voice actuated one, our Instructor introduced me Grove- Offline Voice Recognition Module. Which contains a number of pre trained words so that we can assign functions for each or we can add our own trained words also. Upto 150 trained words can be stored in the module.

    Image taken from amazon.

    I followed Seed studio and hackster.io for getting started with the grove module. It uses UART communication protocol.

    Connections

    • Grove RX to Esp TX

    • Grove TX to Esp RX

    • Grove VCC to ESP 5V

    • Grove GND to ESP GND

    I tried to Turn ON and OFF the onboard LED on the ESP32 S3 when I say Cooler and Warmer. The wake up word for the module was "Hey Pudding". My fello batch mates were too irritated while I tested this thing.😁 😁

    With the help of ChatGPT I wrote a code for it.


        
            #include <SoftwareSerial.h>
    
            #define SOFTWARE_RX 44   // RX of Grove Voice Module
            #define SOFTWARE_TX 43   // TX of Grove Voice Module
            #define LED_PIN 21       // User LED pin
    
            SoftwareSerial Grove_Sensor(SOFTWARE_RX, SOFTWARE_TX); // RX, TX
    
            const byte CMD_LENGTH = 5;
            byte buffer[CMD_LENGTH];
            byte index = 0;
    
            void setup() 
            {
            Serial.begin(9600);
            while (!Serial);
    
            Serial.println("USB Serial Port connection Established!");
    
            Grove_Sensor.begin(115200);
    
            pinMode(LED_PIN, OUTPUT);
            digitalWrite(LED_PIN, LOW); // Initially OFF
            }
    
            void loop() 
            {
            while (Grove_Sensor.available()) 
            {
                byte incoming = Grove_Sensor.read();
                Serial.print(incoming, HEX);
                Serial.print(" ");
    
                // Store into buffer
                buffer[index++] = incoming;
    
                // If 5 bytes received
                if (index == CMD_LENGTH)
                {
                // Check for "warmer" command
                if (buffer[0] == 0x5A && buffer[1] == 0x20 && buffer[2] == 0x00 && buffer[3] == 0x00 && buffer[4] == 0x7A)
                {
                    digitalWrite(LED_PIN, HIGH); // Turn LED ON
                    Serial.println(" -> Warmer Command Recognized: LED ON");
                }
    
                // Check for "cooler" command
                else if (buffer[0] == 0x5A && buffer[1] == 0x21 && buffer[2] == 0x00 && buffer[3] == 0x00 && buffer[4] == 0x7B)
                {
                    digitalWrite(LED_PIN, LOW); // Turn LED OFF
                    Serial.println(" -> Cooler Command Recognized: LED OFF");
                }
    
                // Reset buffer index for next command
                index = 0;
                }
            }
    
            delay(10);
            }
        
      

    ChatGPT Promt: I have a groove voice recognition module and an ESP32s3. While i say warmer the user led on esp32s3 needed to be turn on and on cooler it needed to be turned off. led pin is 21


    Then I tried to integrate Servo with this. While the light turn ON the servo needed to turn to 0 and while light turn OFF the servo needed to turn 180.

      
                #include <SoftwareSerial.h>
                #include <ESP32Servo.h>
    
                // Pin Definitions
                #define VOICE_RX 44         // Grove module TX → ESP32 RX
                #define VOICE_TX 43         // Grove module RX → ESP32 TX
                #define LED_PIN 21
                #define SERVO_PIN 2
    
                // Command hex values received from Grove module
                #define CMD_WARMER 0x6AFF
                #define CMD_COOLER 0x6BFF
    
                // Servo pulse range
                #define PULSEMIN 500
                #define PULSEMAX 2500
    
                // Create instances
                SoftwareSerial Grove_Sensor(VOICE_RX, VOICE_TX);
                Servo myServo;
    
                void setup() {
                Serial.begin(115200);
                Grove_Sensor.begin(115200);
    
                pinMode(LED_PIN, OUTPUT);
                digitalWrite(LED_PIN, LOW);  // Start with LED OFF
    
                // Attach servo with defined pulse range
                ESP32PWM::allocateTimer(0);  // Optional but good practice
                if (myServo.attach(SERVO_PIN, PULSEMIN, PULSEMAX)) {
                    myServo.write(0);  // Initial position
                    Serial.println("✅ Servo attached to pin 2.");
                } else {
                    Serial.println("❌ Servo failed to attach!");
                }
    
                Serial.println("🟢 System initialized.");
                }
    
                void loop() {
                static uint8_t buffer[2];
                static uint8_t index = 0;
    
                // Read command bytes from Grove voice module
                while (Grove_Sensor.available()) {
                    buffer[index++] = Grove_Sensor.read();
    
                    if (index >= 2) {
                    // Combine two bytes into one command
                    uint16_t command = (buffer[0] <<< 8) | buffer[1];
                    Serial.print("🎙️ Command Received: 0x");
                    Serial.println(command, HEX);
                    index = 0;
    
                    // Match commands
                    if (command == CMD_WARMER) {
                        digitalWrite(LED_PIN, HIGH);
                        myServo.write(180);
                        Serial.println("✅ Warmer command: LED ON, Servo 180°");
                    } else if (command == CMD_COOLER) {
                        digitalWrite(LED_PIN, LOW);
                        myServo.write(0);
                        Serial.println("✅ Cooler command: LED OFF, Servo 0°");
                    } else {
                        Serial.println("⚠️ Unknown command received.");
                    }
                    }
                }
    
                delay(5);  // Small delay for stability
                }
    
      
    
  3. Playing Mp3 file from Micro SD card.
  4. As playing music from the micro SD card was a basic feature of my toy, I tested it during the initial phase to confirm that it works correctly.

    I took references from the following sites to test it,


    Connections
    Code
                    
                        #include <Arduino.h>
                        #include <SPI.h>
                        #include <SD.h>
                        #include <AudioFileSourceSD.h>
                        #include <AudioGeneratorMP3.h>
                        #include <AudioOutputI2S.h>
    
                        // SD card SPI pins
                        #define SD_CS    14
                        #define MOSI    23
                        #define MISO    19
                        #define SCK     18
    
                        // I2S speaker pins
                        #define I2S_DOUT 25  // DIN to MAX98357A
                        #define I2S_BCLK 32
                        #define I2S_LRC  33  // LRCK or WS
    
                        AudioGeneratorMP3 *mp3;
                        AudioFileSourceSD *file;
                        AudioOutputI2S *out;
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000);
    
                        // Initialize SPI for SD card
                        SPI.begin(SCK, MISO, MOSI);
                        if (!SD.begin(SD_CS)) {
                            Serial.println("SD card init failed!");
                            while (true);
                        }
                        Serial.println("SD card initialized.");
    
                        // Load MP3 file
                        file = new AudioFileSourceSD("/test.mp3");  // Make sure this exists
    
                        // Set up I2S output to speaker
                        out = new AudioOutputI2S();
                        out->SetPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
                        out->SetGain(0.5);  // 0.0 to 1.0 volume
    
                        // Start MP3 decoding
                        mp3 = new AudioGeneratorMP3();
                        mp3->begin(file, out);
                        }
    
                        void loop() {
                        if (mp3->isRunning()) {
                            mp3->loop();
                        } else {
                            Serial.println("Playback finished.");
                            delay(1000);
                        }
                        }
    
                    
                

  5. Talking Tom
  6. The talking tom feature was also sucessfully tested.

    Here I completly relied on ChatGPT for testing.

    Connections
    Code
                    
                        #include <Arduino.h>
                        #include <SD.h>
                        #include <SPI.h>
                        #include <driver/i2s.h>
    
                        // SD card
                        #define SD_CS 5
    
                        // I2S Microphone (INMP441)
                        #define I2S_MIC_WS 15
                        #define I2S_MIC_SD 32
                        #define I2S_MIC_SCK 14
    
                        // I2S DAC (UDA1334A)
                        #define I2S_DAC_WS 25
                        #define I2S_DAC_SD 22
                        #define I2S_DAC_SCK 26
    
                        #define SAMPLE_RATE 16000
                        #define RECORD_TIME_SECONDS 5
                        #define WAV_FILENAME "/record.wav"
    
                        File audioFile;
    
                        void writeWavHeader(File file, uint32_t sampleRate, uint16_t bitsPerSample, uint16_t channels) {
                        uint32_t fileSize = 0;
                        uint32_t byteRate = sampleRate * channels * bitsPerSample / 8;
                        uint16_t blockAlign = channels * bitsPerSample / 8;
    
                        byte header[44] = {
                            'R','I','F','F', 0,0,0,0, 'W','A','V','E','f','m','t',' ',
                            16,0,0,0, 1,0, (byte)channels,0,
                            (byte)(sampleRate & 0xff), (byte)((sampleRate >> 8) & 0xff),
                            (byte)((sampleRate >> 16) & 0xff), (byte)((sampleRate >> 24) & 0xff),
                            (byte)(byteRate & 0xff), (byte)((byteRate >> 8) & 0xff),
                            (byte)((byteRate >> 16) & 0xff), (byte)((byteRate >> 24) & 0xff),
                            blockAlign,0, bitsPerSample,0, 'd','a','t','a',
                            0,0,0,0
                        };
                        file.write(header, 44);
                        }
    
                        void updateWavHeader(File file) {
                        uint32_t fileSize = file.size();
                        file.seek(4);
                        uint32_t chunkSize = fileSize - 8;
                        file.write((uint8_t*)&chunkSize, 4);
                        file.seek(40);
                        uint32_t dataSize = fileSize - 44;
                        file.write((uint8_t*)&dataSize, 4);
                        }
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000);
    
                        // SD card init
                        if (!SD.begin(SD_CS)) {
                            Serial.println("SD Card initialization failed!");
                            while (true);
                        }
                        Serial.println("SD card initialized.");
    
                        // Configure I2S for mic (RX mode)
                        i2s_config_t i2sMicConfig = {
                            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
                            .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_LEVEL1,
                            .dma_buf_count = 8,
                            .dma_buf_len = 1024,
                            .use_apll = false
                        };
    
                        i2s_pin_config_t micPins = {
                            .bck_io_num = I2S_MIC_SCK,
                            .ws_io_num = I2S_MIC_WS,
                            .data_out_num = I2S_PIN_NO_CHANGE,
                            .data_in_num = I2S_MIC_SD
                        };
    
                        i2s_driver_install(I2S_NUM_0, &i2sMicConfig, 0, NULL);
                        i2s_set_pin(I2S_NUM_0, &micPins);
                        i2s_zero_dma_buffer(I2S_NUM_0);
    
                        // Open file and write header
                        audioFile = SD.open(WAV_FILENAME, FILE_WRITE);
                        writeWavHeader(audioFile, SAMPLE_RATE, 16, 1);
                        Serial.println("Recording...");
    
                        // Record audio
                        const int bufferSize = 1024;
                        char buffer[bufferSize];
                        uint32_t startTime = millis();
    
                        while (millis() - startTime < RECORD_TIME_SECONDS * 1000) {
                            size_t bytesRead;
                            i2s_read(I2S_NUM_0, &buffer, bufferSize, &bytesRead, portMAX_DELAY);
                            audioFile.write((const byte*)buffer, bytesRead);
                        }
    
                        // Stop recording
                        audioFile.flush();
                        updateWavHeader(audioFile);
                        audioFile.close();
                        i2s_driver_uninstall(I2S_NUM_0);
                        Serial.println("Recording done.");
    
                        delay(1000);
    
                        // Configure I2S for DAC (TX mode)
                        i2s_config_t i2sDacConfig = {
                            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
                            .sample_rate = SAMPLE_RATE,
                            .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
                            .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
                            .communication_format = I2S_COMM_FORMAT_I2S,
                            .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
                            .dma_buf_count = 8,
                            .dma_buf_len = 1024,
                            .use_apll = false
                        };
    
                        i2s_pin_config_t dacPins = {
                            .bck_io_num = I2S_DAC_SCK,
                            .ws_io_num = I2S_DAC_WS,
                            .data_out_num = I2S_DAC_SD,
                            .data_in_num = I2S_PIN_NO_CHANGE
                        };
    
                        i2s_driver_install(I2S_NUM_0, &i2sDacConfig, 0, NULL);
                        i2s_set_pin(I2S_NUM_0, &dacPins);
                        i2s_zero_dma_buffer(I2S_NUM_0);
    
                        // Open audio file
                        audioFile = SD.open(WAV_FILENAME);
                        if (!audioFile) {
                            Serial.println("Playback file open failed!");
                            return;
                        }
    
                        audioFile.seek(44); // Skip WAV header
                        Serial.println("Playing back...");
    
                        while (audioFile.available()) {
                            int bytesRead = audioFile.readBytes(buffer, bufferSize);
                            size_t bytesWritten;
                            i2s_write(I2S_NUM_0, buffer, bytesRead, &bytesWritten, portMAX_DELAY);
                        }
    
                        Serial.println("Playback done.");
                        audioFile.close();
                        i2s_driver_uninstall(I2S_NUM_0);
                        }
    
                        void loop() {
                        // Do nothing after playback
                        }
    
                    
                
                    ChatGPT Promt: I have an inmp441, sd card module, esp32 , UDA1334A and a speaker. I need to record the audio and play it back like a talking tom
                

  7. Capacitive Touch
  8. Esp32 already have the touch recogniton feature in it. So I tested to impliment it in my project.

    I took reference from the following documentation

    I connected a jumper wire to GPIO 4 of esp32 and flased the code below using arduino IDE.

                    
                        // ESP32 Touch Test
                        // Just test touch pin - Touch0 is T0 which is on GPIO 4.
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000); // give me time to bring up serial monitor
                        Serial.println("ESP32 Touch Test");
                        }
    
                        void loop() {
                        Serial.println(touchRead(4));  // get value of Touch 0 pin = GPIO 4
                        delay(1000);
                        }
                    
                

    Then I try to control a servo with the capacitive reading on the serial monitor. In normal conditon the value was always above 50 and while touching the value suddenly goes below 50 so I wrote a program to control the servo id the value is greater than 50 the servo turn to 0 degree and while the value goes below 50 then the servo turns to 180 degree and it works sucessfully.

    Jumper wire was connected to GPIO4 for capacitive touch and the servo motor was connected to GPIO2.


                    
                        #include  <ESP32Servo.h>
    
                        Servo myServo;
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000); // Allow time to open Serial Monitor
                        Serial.println("ESP32 Touch + Servo Control");
    
                        myServo.attach(2);   // Servo connected to GPIO 2
                        myServo.write(0);    // Initial position
                        }
    
                        void loop() {
                        // === Touch Control ===
                        int touchVal = touchRead(4); // Read Touch0 (GPIO 4)
                        Serial.print("Touch Value: ");
                        Serial.println(touchVal);
    
                        if (touchVal > 50) {
                            myServo.write(0);   // Move to 0°
                        } else {
                            myServo.write(180); // Move to 180°
                        }
    
                        // === Optional: Serial Input for Manual Control ===
                        if (Serial.available()) {
                            int angle = Serial.parseInt();
                            if (angle >= 0 && angle <= 180) {
                            myServo.write(angle);
                            Serial.print("Manual Angle Set: ");
                            Serial.println(angle);
                            }
                        }
    
                        delay(500); // Delay to prevent rapid switching
                        }
    
                    
                


  9. Testing 2 INMP441 toughter.
  10. As my toy turn to the direction of the sound by measuring the input of the microphones. So I connected 2 INMP441 to ESP 32 to test it out.

    I took the wiring reference from the following arduino forum

    Image taken from Forum.Arduino

    The signal pins of the INMP441 can be parallelly connected to ESP's GPIO pins. On one INMP441 the L/R should be grounded and on the other it should be connected to 3.3v.

    Code


                    
                        #include <driver/i2s.h>
    
                        #define I2S_WS      15   // LRCLK (Word Select)
                        #define I2S_SCK     2    // BCLK (Bit Clock)
                        #define I2S_SD      34   // DATA IN (Serial Data)
    
                        #define I2S_PORT    I2S_NUM_0
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000);
                        Serial.println("Voice Direction Detection (Mic 1 = Left, Mic 2 = Right)");
    
                        i2s_config_t i2s_config = {
                            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
                            .sample_rate = 16000,
                            .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
                            .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
                            .communication_format = I2S_COMM_FORMAT_I2S,
                            .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
                            .dma_buf_count = 8,
                            .dma_buf_len = 64,
                            .use_apll = false,
                            .tx_desc_auto_clear = false,
                            .fixed_mclk = 0
                        };
    
                        i2s_pin_config_t pin_config = {
                            .bck_io_num = I2S_SCK,
                            .ws_io_num = I2S_WS,
                            .data_out_num = I2S_PIN_NO_CHANGE,
                            .data_in_num = I2S_SD
                        };
    
                        i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
                        i2s_set_pin(I2S_PORT, &pin_config);
                        }
    
                        void loop() {
                        const int samples = 512; // Number of 32-bit samples to read (256 stereo pairs)
                        int32_t buffer[samples];
                        size_t bytes_read;
    
                        // Read samples from I2S
                        i2s_read(I2S_PORT, &buffer, sizeof(buffer), &bytes_read, portMAX_DELAY);
                        int samples_read = bytes_read / sizeof(int32_t);
    
                        long left_sum = 0;
                        long right_sum = 0;
    
                        // Sum absolute values of left and right channels
                        for (int i = 0; i < samples_read; i += 2) {
                            int32_t left = buffer[i];       // Left channel
                            int32_t right = buffer[i + 1];  // Right channel
    
                            left_sum += abs(left);
                            right_sum += abs(right);
                        }
    
                        // Higher threshold to detect clear dominance
                        if (left_sum > right_sum * 3.0) {
                            Serial.println("1");  // Voice clearly from Mic 1 (Left)
                        } else if (right_sum > left_sum * 3.0) {
                            Serial.println("2");  // Voice clearly from Mic 2 (Right)
                        } else {
                            Serial.println("0");  // No clear dominant mic or silence
                        }
    
                        delay(200); // Delay to slow output for easier reading
                        }
    
                    
                

                    ChatGPT Promt: I have 2 INMP441 mic and is connected to ESP32 30 pin. L/R of mic 1 is connected to 3.3v and mic 2 is grounded. 
    other pins of both mic are common connections. Mic GND to esp gnd, mic vdd to esp 3.3, SD to io34, WS to io15, sck to io2 write a program to
    check the reading of the mic in serial monitor.

  11. Combining Mp3 and Talking Tom
  12. Both were individually tested and worked fine. However, I needed to confirm if they would function properly when combined. So, I attempted to integrate them and check their performance together. I followed the same wiring setup as the Talking Tom connections mentioned earlier.


    Code

                    
                        #include <Arduino.h>
                        #include >SD.h>
                        #include >SPI.h>
                        #include >driver/i2s.h>
                        #include >AudioFileSourceSD.h>
                        #include >AudioGeneratorMP3.h>
                        #include >AudioOutputI2S.h>
    
                        // SD card pin (from first program)
                        #define SD_CS 5
    
                        // I2S Microphone (INMP441) pins (from first program)
                        #define I2S_MIC_WS 15
                        #define I2S_MIC_SD 32
                        #define I2S_MIC_SCK 14
    
                        // I2S DAC (UDA1334A) pins (from first program)
                        #define I2S_DAC_WS 25
                        #define I2S_DAC_SD 22
                        #define I2S_DAC_SCK 26
    
                        #define SAMPLE_RATE 16000
                        #define RECORD_TIME_SECONDS 5
                        #define WAV_FILENAME "/record.wav"
    
                        // For MP3 playback from second program, pins adjusted to first program's DAC pins
                        // Audio library will handle I2S internally, but pin mapping is needed for output
                        #define I2S_BCLK I2S_DAC_SCK
                        #define I2S_LRC  I2S_DAC_WS
                        #define I2S_DOUT I2S_DAC_SD
    
                        File audioFile;
    
                        // For MP3 playback objects
                        AudioGeneratorMP3 *mp3 = nullptr;
                        AudioFileSourceSD *file = nullptr;
                        AudioOutputI2S *out = nullptr;
    
                        void writeWavHeader(File file, uint32_t sampleRate, uint16_t bitsPerSample, uint16_t channels) {
                        uint32_t byteRate = sampleRate * channels * bitsPerSample / 8;
                        uint16_t blockAlign = channels * bitsPerSample / 8;
    
                        byte header[44] = {
                            'R','I','F','F', 0,0,0,0, 'W','A','V','E','f','m','t',' ',
                            16,0,0,0, 1,0, (byte)channels,0,
                            (byte)(sampleRate & 0xff), (byte)((sampleRate >> 8) & 0xff),
                            (byte)((sampleRate >> 16) & 0xff), (byte)((sampleRate >> 24) & 0xff),
                            (byte)(byteRate & 0xff), (byte)((byteRate >> 8) & 0xff),
                            (byte)((byteRate >> 16) & 0xff), (byte)((byteRate >> 24) & 0xff),
                            blockAlign,0, bitsPerSample,0, 'd','a','t','a',
                            0,0,0,0
                        };
                        file.write(header, 44);
                        }
    
                        void updateWavHeader(File file) {
                        uint32_t fileSize = file.size();
                        file.seek(4);
                        uint32_t chunkSize = fileSize - 8;
                        file.write((uint8_t*)&chunkSize, 4);
                        file.seek(40);
                        uint32_t dataSize = fileSize - 44;
                        file.write((uint8_t*)&dataSize, 4);
                        }
    
                        // Recording + Playback function (first program)
                        void recordAndPlayback() {
                        Serial.println("Starting recording...");
    
                        // Configure I2S for mic (RX mode)
                        i2s_config_t i2sMicConfig = {
                            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
                            .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_LEVEL1,
                            .dma_buf_count = 8,
                            .dma_buf_len = 1024,
                            .use_apll = false
                        };
    
                        i2s_pin_config_t micPins = {
                            .bck_io_num = I2S_MIC_SCK,
                            .ws_io_num = I2S_MIC_WS,
                            .data_out_num = I2S_PIN_NO_CHANGE,
                            .data_in_num = I2S_MIC_SD
                        };
    
                        i2s_driver_install(I2S_NUM_0, &i2sMicConfig, 0, NULL);
                        i2s_set_pin(I2S_NUM_0, &micPins);
                        i2s_zero_dma_buffer(I2S_NUM_0);
    
                        // Open file and write WAV header
                        audioFile = SD.open(WAV_FILENAME, FILE_WRITE);
                        if (!audioFile) {
                            Serial.println("Failed to open file for recording!");
                            return;
                        }
                        writeWavHeader(audioFile, SAMPLE_RATE, 16, 1);
    
                        const int bufferSize = 1024;
                        char buffer[bufferSize];
                        uint32_t startTime = millis();
    
                        while (millis() - startTime < RECORD_TIME_SECONDS * 1000) {
                            size_t bytesRead;
                            i2s_read(I2S_NUM_0, &buffer, bufferSize, &bytesRead, portMAX_DELAY);
                            audioFile.write((const byte*)buffer, bytesRead);
                        }
    
                        audioFile.flush();
                        updateWavHeader(audioFile);
                        audioFile.close();
    
                        i2s_driver_uninstall(I2S_NUM_0);
    
                        Serial.println("Recording done.");
    
                        delay(1000);
    
                        // Playback part (I2S TX)
                        Serial.println("Starting playback...");
    
                        i2s_config_t i2sDacConfig = {
                            .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
                            .sample_rate = SAMPLE_RATE,
                            .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
                            .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
                            .communication_format = I2S_COMM_FORMAT_I2S,
                            .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
                            .dma_buf_count = 8,
                            .dma_buf_len = 1024,
                            .use_apll = false
                        };
    
                        i2s_pin_config_t dacPins = {
                            .bck_io_num = I2S_DAC_SCK,
                            .ws_io_num = I2S_DAC_WS,
                            .data_out_num = I2S_DAC_SD,
                            .data_in_num = I2S_PIN_NO_CHANGE
                        };
    
                        i2s_driver_install(I2S_NUM_0, &i2sDacConfig, 0, NULL);
                        i2s_set_pin(I2S_NUM_0, &dacPins);
                        i2s_zero_dma_buffer(I2S_NUM_0);
    
                        audioFile = SD.open(WAV_FILENAME);
                        if (!audioFile) {
                            Serial.println("Playback file open failed!");
                            i2s_driver_uninstall(I2S_NUM_0);
                            return;
                        }
    
                        audioFile.seek(44); // Skip WAV header
    
                        while (audioFile.available()) {
                            int bytesRead = audioFile.readBytes(buffer, bufferSize);
                            size_t bytesWritten;
                            i2s_write(I2S_NUM_0, buffer, bytesRead, &bytesWritten, portMAX_DELAY);
                        }
    
                        audioFile.close();
                        i2s_driver_uninstall(I2S_NUM_0);
    
                        Serial.println("Playback done.");
                        }
    
                        // MP3 playback function (second program)
                        void mp3Playback() {
                        Serial.println("Starting MP3 playback...");
    
                        // Initialize MP3 playback objects
                        if (mp3) {
                            delete mp3;
                            mp3 = nullptr;
                        }
                        if (file) {
                            delete file;
                            file = nullptr;
                        }
                        if (out) {
                            delete out;
                            out = nullptr;
                        }
    
                        file = new AudioFileSourceSD("/test.mp3");
                        out = new AudioOutputI2S();
                        out->SetPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
                        out->SetGain(0.5);
    
                        mp3 = new AudioGeneratorMP3();
                        if (!mp3->begin(file, out)) {
                            Serial.println("Failed to start MP3 playback!");
                            return;
                        }
    
                        // Play until done
                        while (mp3->isRunning()) {
                            mp3->loop();
                        }
    
                        Serial.println("MP3 Playback finished.");
                        }
    
                        void setup() {
                        Serial.begin(115200);
                        delay(1000);
    
                        Serial.println("Initializing SD card...");
                        if (!SD.begin(SD_CS)) {
                            Serial.println("SD Card initialization failed!");
                            while (true);
                        }
                        Serial.println("SD card initialized.");
                        Serial.println("Type '1' for record+playback, '2' for mp3 playback");
                        }
    
                        void loop() {
                        if (Serial.available()) {
                            char cmd = Serial.read();
    
                            if (cmd == '1') {
                            recordAndPlayback();
                            Serial.println("Type '1' for record+playback, '2' for mp3 playback");
                            } 
                            else if (cmd == '2') {
                            mp3Playback();
                            Serial.println("Type '1' for record+playback, '2' for mp3 playback");
                            }
                            else {
                            Serial.println("Unknown command. Type '1' or '2'");
                            }
                        }
                        }
    
                    
                

                ChatGPT Promt: I have an esp32 30 pin microcontroller, INMP441, UDA1334A and an sd card module. I tested it and it play the audio 
    from the sd card and it also act as a talking tom seperately. Can I combine both these so that I can make this as a talking toy and an mp3 player.
    if I need mp3 switch to mp3 mode and if I need talking tom i can switch it to talking toy as well. Currently switching should be done using serial
    monitor if i input 1 mp3 and 2 for ta1king toy. Also provided the individual tested code of both mp3 playback and talk back.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.