如何将音频事件前后的50毫秒存储在循环缓冲区中?

时间:2019-05-20 16:00:52

标签: c embedded signal-processing audio-processing

我正在处理17个小时的音频.wav(16位PCM,192khz)的数据集,以模拟将嵌入到ESP32,Arduino DUE或RASP中的“实时”处理,具体取决于结果。

我现在该如何处理?

首先,我用C语言创建了一个程序,将17小时的文件剪切为1分钟的样本,该程序将该文件转换为.CSV文件(跳过整个.wav文件的头部,仅使用日期字段)。

PS:我选择CSV来更好地处理数据,以便在Scilab中执行测试以验证算法。

使用生成的.CSV文件在第二个程序中运行它,打开该文件并用130ms(24900个值)填充循环缓冲区,当缓冲区已满时,代码开始计算RMS(均方根) )在重叠10毫秒的移动窗口中,窗口大小为30毫秒。当我获得的值大于1000时,将被视为事件。

在下面您可以看到问题的说明:

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

在此处显示的是事件发生前后50毫秒的窗口:

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

PS:Inicio,Fim和Janela分别表示开始,结束和窗口。

我的问题是:

由于事件可以发生在缓冲区的任何位置,因此我应该如何在事件发生之前和之后保存这50ms?如果活动持续一个以上的窗口,我该怎么办?

一些数据有助于理解:

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

我已经搜索了多个资源,但是大多数DSP参考书目和数据结构都只是表面地论述了这些主题,只是说明了循环缓冲区是什么,而不是如何以有用的方式对其进行处理。

这是我的代码草图,似乎是对问题采取了错误的方法,但是我真的不知道如何进行,在这种情况下,我创建了一个1到100的数据集以简化调试:

    #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;
    }

一些注释是葡萄牙语的,但与理解该问题无关。

1 个答案:

答案 0 :(得分:2)

我在这里为您提供解决方案的算法。

  1. 始终在循环缓冲区中记录50毫秒(甚至60毫秒)的数据。
  2. 如果您检测到开始事件,
    • 将前50毫秒从循环缓冲区复制到最终缓冲区
    • 在50ms的位置继续将接收到的数据写入最终缓冲区。
  3. 如果您检测到结束事件。
    • 继续写入最终缓冲区至少50毫秒。
    • 再次开始写入循环缓冲区。
  4. 如果您有多个事件,则需要有多个最终缓冲区并可以重复该过程。

如下面的注释中所述,此解决方案也适用于> 50 ms的窗口大小。您需要相应地选择最终缓冲区的大小。