Taimoor Naeem
Published

Sound frequency Analyzer

Sound frequency detector detects frequency from the sound

IntermediateFull instructions provided12 hours192
Sound frequency Analyzer

Things used in this project

Hardware components

ESP32
Espressif ESP32
×1
inmp 441 microphone
×1
SD card adapter
×1

Software apps and online services

ESP-IDF

Story

Read more

Schematics

Schematic

Wire connections should be established accordingly

Code

app_main.c

C/C++
Use in esp-idf framework
/*
 * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "format_wav.h"
#include "hal/i2s_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_check.h"
#include "sdkconfig.h"
#include "app_fft.h"
#include "freertos/queue.h"

#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
#include "app_ntp.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "app_http.h"

#define LED_PIN 2

// extern char frequency[10];
// extern char description[50];
// extern char status[20];

// extern float *frequency_samples;

float current_frequency_value_A = 0.0;
float current_frequency_value_B = 0.0;
float current_frequency_value_C = 0.0;
float current_frequency_value_D = 0.0;
float current_frequency_value_E = 0.0;

float previous_frequency_value_A = 0.0;
float previous_frequency_value_B = 0.0;
float previous_frequency_value_C = 0.0;
float previous_frequency_value_D = 0.0;
float previous_frequency_value_E = 0.0;
float previous_max_frequency = 0.0;


char description_A[50] = "Calling endpoint A";
char description_B[50] = "Calling endpoint B";
char description_C[50] = "Calling endpoint C";
char description_D[50] = "Calling endpoint D";
char description_E[50] = "Calling endpoint E";

char type_A[20] = "status_01";
char type_B[20] = "status_02";
char type_C[20] = "status_03";
char type_D[20] = "status_04";
char type_E[20] = "status_05";

char status[20] = "Active";

#define BUFF_SIZE 1024
#define BYTE_RATE (CONFIG_SAMPLE_RATE * 4)

size_t bytes_read = 0;
int32_t raw_samples[BUFF_SIZE] = {0};

static const char *TAG = "Voice Recorder";

#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#define SD_MOUNT_POINT "/sdcard"

sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t *card;

static i2s_chan_handle_t rx_chan; // I2S rx channel handler
QueueHandle_t sample_queue, frequency_queue;

void app_connect_wifi(void)
{
    nvs_flash_init();
    esp_netif_init();
    esp_event_loop_create_default();
    example_connect();
}

static void fft_task(void *args)
{
    int32_t fft_samples[BUFF_SIZE] = {0};

    while (1)
    {
        // Receive data from the queue
        if (xQueueReceive(sample_queue, (void *)fft_samples, portMAX_DELAY) == pdTRUE)
        {
            compute_fft(fft_samples);
        }
        vTaskDelay(pdMS_TO_TICKS(80));

        // printf("executing compute fft \n");
    }

    vTaskDelete(NULL);
}

void record_wav(uint32_t rec_time)
{

    // Use POSIX and C standard library functions to work with files.
    int flash_wr_size = 0;

    char file_path[100] = {0};
    create_file_with_timestamp(file_path, sizeof(file_path));
    printf("********** %s ************\n", file_path);

    ESP_LOGI(TAG, "Opening file");

    uint32_t flash_rec_time = BYTE_RATE * rec_time;
    const wav_header_t wav_header =
        WAV_HEADER_PCM_DEFAULT(flash_rec_time, 32, CONFIG_SAMPLE_RATE, 1);

    // First check if file exists before creating a new file.
    struct stat st;
    if (stat(file_path, &st) == 0)
    {
        printf("inside unlink if \n");
        // Delete it if it exists
        unlink(file_path);
    }

    // printf("outside unlink if \n");

    // Create new WAV file
    FILE *f = fopen(file_path, "a");
    if (f == NULL)
    {
        ESP_LOGE(TAG, "Failed to open file for writing");
        return;
    }

    // Write the header to the WAV file
    fwrite(&wav_header, sizeof(wav_header), 1, f);

    i2s_channel_enable(rx_chan);
    gpio_set_level(LED_PIN, 1);

    ESP_LOGI(TAG, "Starting recording for %d seconds!", CONFIG_REC_TIME);

    // Start recording
    while (flash_wr_size < flash_rec_time)
    {
        size_t bytes_read = 0;
        // Read the RAW samples from the microphone
        i2s_channel_read(rx_chan, raw_samples, sizeof(int32_t) * BUFF_SIZE, &bytes_read, portMAX_DELAY);
        int samples_read = bytes_read / 4;
        if (samples_read == BUFF_SIZE)
        {
            // Send data to the queue
            if (xQueueSend(sample_queue, (void *)raw_samples, portMAX_DELAY) != pdTRUE)
            {
                printf("Failed to send data to queue\n");
            }
        }
        fwrite(raw_samples, bytes_read, 1, f);
        flash_wr_size += bytes_read;
    }

    gpio_set_level(LED_PIN, 0);
    ESP_LOGI(TAG, "Recording done!");
    fclose(f);
    ESP_LOGI(TAG, "File written on SDCard");

    // All done, unmount partition and disable SPI peripheral
    // esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, card);
    // ESP_LOGI(TAG, "Card unmounted");
    // Deinitialize the bus after all devices are removed
    // spi_bus_free(host.slot);

    // call_endpoints();

    current_frequency_value_A = 0.0;
    current_frequency_value_B = 0.0;
    current_frequency_value_C = 0.0;
    current_frequency_value_D = 0.0;
    current_frequency_value_E = 0.0;

    previous_frequency_value_A = 0.0;
    previous_frequency_value_B = 0.0;
    previous_frequency_value_C = 0.0;
    previous_frequency_value_D = 0.0;
    previous_frequency_value_E = 0.0;
    previous_max_frequency = 0.0;

}

static void record_wave_task(void *args)
{

    while (1)
    {

        record_wav(CONFIG_REC_TIME);

        ESP_ERROR_CHECK(i2s_channel_disable(rx_chan));

        // ESP_ERROR_CHECK(i2s_del_channel(rx_chan));

        /// vTaskDelete(NULL);

        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

static void freq_task(void *args)
{
    float frequency_rcv_sample;

    while (1)
    {
        if (xQueueReceive(frequency_queue, &frequency_rcv_sample, pdMS_TO_TICKS(1000)) == pdPASS)
        {
            call_endpoints(frequency_rcv_sample);
        }

        vTaskDelay(pdMS_TO_TICKS(80));
    }
}

void mount_sdcard(void)
{
    esp_err_t ret;
    // Options for mounting the filesystem.
    // If format_if_mount_failed is set to true, SD card will be partitioned and
    // formatted in case when mounting fails.
    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = 8 * 1024};
    ESP_LOGI(TAG, "Initializing SD card");
    host.max_freq_khz = 1000;
    spi_bus_config_t bus_cfg = {
        .mosi_io_num = CONFIG_SPI_MOSI_GPIO,
        .miso_io_num = CONFIG_SPI_MISO_GPIO,
        .sclk_io_num = CONFIG_SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4000,
    };
    ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to initialize bus.");
        return;
    }

    // This initializes the slot without card detect (CD) and write protect (WP) signals.
    // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
    sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
    slot_config.gpio_cs = CONFIG_SPI_CS_GPIO;
    slot_config.host_id = host.slot;

    ret = esp_vfs_fat_sdspi_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card);

    if (ret != ESP_OK)
    {
        if (ret == ESP_FAIL)
        {
            ESP_LOGE(TAG, "Failed to mount filesystem.");
        }
        else
        {
            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
                          "Make sure SD card lines have pull-up resistors in place.",
                     esp_err_to_name(ret));
        }
        return;
    }

    // Card has been initialized, print its properties
    sdmmc_card_print_info(stdout, card);
}

static void i2s_init_std_simplex(void)
{
    i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
    ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_chan));

    i2s_std_config_t rx_std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(CONFIG_SAMPLE_RATE),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED, // some codecs may require mclk signal, this example doesn't need it
            .bclk = CONFIG_I2S_BCLK_GPIO,
            .ws = CONFIG_I2S_WS_GPIO,
            .dout = I2S_GPIO_UNUSED,
            .din = CONFIG_I2S_DIN_GPIO,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv = false,
            },
        },
    };

    rx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_RIGHT;
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
}

void app_main(void)
{

    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
    // Mount the SDCard for recording the audio file
    sample_queue = xQueueCreate(10, BUFF_SIZE * sizeof(int32_t));
    frequency_queue = xQueueCreate(2048, sizeof(float));

    if (sample_queue == NULL)
    {
        printf("Failed to create sample queue\n");
        return;
    }

    if (frequency_queue == NULL)
    {
        printf("Failed to create frequency queue\n");
        return;
    }

    app_connect_wifi();
    app_ntp_client_init();
    app_fft_init();

    mount_sdcard();
    // Acquire a I2S philips channel for the IMP441 microphone
    i2s_init_std_simplex();

    xTaskCreate(record_wave_task, "i2s_example_read_task", 32384, NULL, 5, NULL);
    xTaskCreate(fft_task, "fft_task", 8096, NULL, 5, NULL);
    xTaskCreate(freq_task, "frequency task", 32384, NULL, 5, NULL);
}

Credits

Taimoor Naeem
1 project • 0 followers
Aa Embedded Firmware Developer who possesses skills in Embedded IoT and microcontroller firmware (STM32, ESP32, NRF, Arduino).
Contact

Comments

Please log in or sign up to comment.