Gabriel Lavoura
Gabriel Lavoura

Reputation: 41

How can I store the 50ms before and after an audio event in a circular buffer?

I am processing a dataset of 17 hours of audio .wav (16-bit PCM, 192khz), to simulate a "real-time" processing that will be embedded in an ESP32, Arduino DUE or in a RASP, depending on the results.

How am I handling with that now?

First I cut the 17 hours file in a 1 minute samples, after I created a program in C that turns this file into a .CSV (jumping the entire head of .wav and taking only the date field).

PS: I chose CSV to have the data in a better disposition in order to perform tests in Scilab to validate the algorithms.

With this generated .CSV file I run it in a second program, that opens this file and fills a circular buffer with 130ms (24900 values), when the buffer is full, the code begins to calculate the RMS (Root Mean Square) in moving window with 10ms overlap, window size is 30ms . When I get a value greater than 1000 it is considered an event.

Below you can see an illustration of the problem:

Delimiters of an Event, Inicio = Start, Fim = End

Here is shown the Window with 50 ms before and after an event which I mean:

Window os 200ms, 50ms before and after and event of 100ms

PS: Inicio, Fim and Janela means respectively, Start, End, Window.

My question is:

How should I save these 50ms before and after the event, since the event can occur anywhere in the buffer? And what should I do if the event lasts for more than one window?

Some data to help the understanding:

130ms = 24900 values ​​from my .csv file
50ms = 9600   values
30ms = 5700   values
10ms = 1920   values

I've searched for several sources, but most of the DSP bibliographies and Data Structures treat these topics superficially, just illustrating what a circular buffer is and not how to deal with it in a useful way.

Here is my code sketch, which seems to be taking a wrong approach to the problem, but I really have no idea how to proceed, in this case I created a data-set from 1 to 100 to ease of the debug:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>

    // Define the size of window 50ms
    #define window_size 3 // 30ms
    #define buffer_size 13 // 130ms = 50ms + 30ms + 50ms

    int main()
    {
        //define variables.
        int buffer[buffer_size]={0}; // create the buffer with 150ms;
        int write = 0;
        int i = 0, j = 0;
        int read = 0;
        int read1 =0;
        int write1 = 0;
        int counter_elements = 0;
        int number_lines = 0;
        int save_line = 0;
        char c;
        char str[1024];     // array to hold characters in a conversion of char to int.
        int inicio = 0, fim = 0;
        //RMS
        int soma_quadrado = 0;
        int rms = 0;
        int pre_amostragem[5] = {0};

        //Define variaveis referentes a leitura do arquivo e manipulacoes do mesmo.
        FILE * fp;
        FILE * LOG;
        FILE * log_rms_final;

        // Open the file and verify is NULL.
        if((fp = fopen("generator.txt","r")) == NULL)
        { // Define o nome do csv para abrir
            printf("Error! Can't open the file.\n");
            exit(1);
        }
        // store rms values
         LOG = fopen("RMSValues.csv", "a");
        // store the 50ms after and before a event.
        log_rms_final = fopen("Log_RMS.csv","a");

        int lines = 0;
        while(!feof(fp))
        {
            fgets(str,1024,fp); //reads 1024 characters and store in str.
            buffer[write] = atoi(str);
            write = (write + 1) % buffer_size; // circular
            counter_elements++; // sum 

        c = fgetc(fp);
        if(c == '\n')
        {
            lines++;
        }
        printf("%d\n", lines);
            //if buffer is full
            if(counter_elements == buffer_size)
            {
                // window
                read1 = read; 
                for(i = 0; i < window_size; i++)
                {
                    //square and sum.
                    soma_quadrado += buffer[read1]*buffer[read1];
                    read1 = (read1 + 1) % buffer_size;
                }

                // RMS 
                rms = sqrt(soma_quadrado/window_size);

                fprintf(LOG, "\n %d", rms); // store

                if(rms > 1000)
                {
                    printf("rms: %d\n",rms);

                    // store the 50ms befor a event and the window.
                    write1 = write;
                    for(j = 0 ; j < 5; j++)
                    {

                        write1 = (write1 + (buffer_size - 1)) % buffer_size;
                        pre_amostragem[j] = buffer[write1];
                    }

                    fprintf(log_rms_final,"%s","\n");

                    for(j = 4; j >= 0; j--)
                    {
                        fprintf(log_rms_final,"%d - pre \n",pre_amostragem[j]);
                    }

                    fprintf(log_rms_final,"%s","\n");
    /*
                    for(j = 0; j < window_size; j++)
                    {

                        fprintf(log_rms_final,"%d - janela\n",buffer[read1]);
                        read1 = (read1 + 1) % buffer_size;
                    }
    */
                    fprintf(log_rms_final,"%s","\n");

                    //store the 50ms after a event.

                    /*
                    fseek(log_rms_final,save_line - 3,save_line);

                    for(j = 0; j < 5; j++){

                        fgets(str,1024,fp);
                        fprintf(log_rms_final,"%d - pós \n",atoi(str));

                    }
                    */
                }

                soma_quadrado = 0;
                rms = 0;


                read = (read + 1) % buffer_size;
                counter_elements = counter_elements - 2;

            }
            soma_quadrado = 0;
            rms = 0;

        }

    fclose(fp);
    fclose(LOG);
    fclose(log_rms_final);
    return 0;
    }

some comments are in Portuguese but they aren't relevant for the understanding of the problem.

Upvotes: 2

Views: 293

Answers (1)

Rishikesh Raje
Rishikesh Raje

Reputation: 8614

I am giving you an algorithm for the solution here.

  1. Always record 50ms (or even 60ms) data in a circular buffer.
  2. If you detect a start event,
    • Copy previous 50 ms from circular buffer to final buffer
    • Continue writing received data into final buffer at 50ms location.
  3. If you detect an end event.
    • Continue writing into final buffer for 50 ms more.
    • Start writing into circular buffer again.
  4. If you have multiple events, you need to have multiple final buffers and can repeat the process.

As mentioned below in the comments, this solution will work for a window size > 50 ms also. You need to select the size of the final buffer accordingly.

Upvotes: 2

Related Questions