使用 c 中的低通滤波器过滤 .wav 文件

Posted

技术标签:

【中文标题】使用 c 中的低通滤波器过滤 .wav 文件【英文标题】:Filter a .wav file using a low-pass filter in c 【发布时间】:2021-08-31 15:17:51 【问题描述】:

我有一个任务是创建一个打开 .wav 文件的 C 程序,使用低通或高通滤波器过滤音频文件并将结果保存在另一个文件中。现在我刚刚打开 .wav 文件并显示文件头中的所有信息。有人可以帮我为文件创建过滤器吗?

这是我的代码:

wave.c

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "wave.h"

 int main()
 
    FILE *fp = NULL;
    FILE *outfile = fopen("filtered.wav", "wb");
    
     Wav wav;
     RIFF_t riff;
     FMT_t fmt;
     Data_t data;
 
     fp = fopen("sample.wav", "rb");

     if (!fp) 
         printf("can't open audio file\n");
         exit(1);
     
 
     fread(&wav, 1, sizeof(wav), fp);
     
     riff = wav.riff;
     fmt = wav.fmt;
     data = wav.data;
 
     printf("ChunkID \t%c%c%c%c\n", riff.ChunkID[0], riff.ChunkID[1], riff.ChunkID[2], riff.ChunkID[3]);
     printf("ChunkSize \t%d\n", riff.ChunkSize);
     printf("Format \t\t%c%c%c%c\n", riff.Format[0], riff.Format[1], riff.Format[2], riff.Format[3]);
     
     printf("\n");
     
     printf("Subchunk1ID \t%c%c%c%c\n", fmt.Subchunk1ID[0], fmt.Subchunk1ID[1], fmt.Subchunk1ID[2], fmt.Subchunk1ID[3]);
     printf("Subchunk1Size \t%d\n", fmt.Subchunk1Size);
     printf("AudioFormat \t%d\n", fmt.AudioFormat);
     printf("NumChannels \t%d\n", fmt.NumChannels);
     printf("SampleRate \t%d\n", fmt.SampleRate);
     printf("ByteRate \t%d\n", fmt.ByteRate);
     printf("BlockAlign \t%d\n", fmt.BlockAlign);
     printf("BitsPerSample \t%d\n", fmt.BitsPerSample);
     
     printf("\n");
 
     printf("blockID \t%c%c%c%c\n", data.Subchunk2ID[0], data.Subchunk2ID[1], data.Subchunk2ID[2], data.Subchunk2ID[3]);
     printf("blockSize \t%d\n", data.Subchunk2Size);
     
     printf("\n");
    
     printf("duration \t%d\n", data.Subchunk2Size / fmt.ByteRate);
 

wave.h

typedef struct WAV_RIFF 
    /* chunk "riff" */
    char ChunkID[4];   /* "RIFF" */
    /* sub-chunk-size */
    uint32_t ChunkSize; /* 36 + Subchunk2Size */
    /* sub-chunk-data */
    char Format[4];    /* "WAVE" */
 RIFF_t;

typedef struct WAV_FMT 
    /* sub-chunk "fmt" */
    char Subchunk1ID[4];   /* "fmt " */
    /* sub-chunk-size */
    uint32_t Subchunk1Size; /* 16 for PCM */
    /* sub-chunk-data */
    uint16_t AudioFormat;   /* PCM = 1*/
    uint16_t NumChannels;   /* Mono = 1, Stereo = 2, etc. */
    uint32_t SampleRate;    /* 8000, 44100, etc. */
    uint32_t ByteRate;  /* = SampleRate * NumChannels * BitsPerSample/8 */
    uint16_t BlockAlign;    /* = NumChannels * BitsPerSample/8 */
    uint16_t BitsPerSample; /* 8bits, 16bits, etc. */
 FMT_t;

typedef struct WAV_data 
    /* sub-chunk "data" */
    char Subchunk2ID[4];   /* "data" */
    /* sub-chunk-size */
    uint32_t Subchunk2Size; /* data size */
    /* sub-chunk-data */
    /* Data_block_t block; */
 Data_t;

/* typedef struct WAV_data_block 
 Data_block_t; */

typedef struct WAV_fotmat 
   RIFF_t riff;
   FMT_t fmt;
   Data_t data;
 Wav;

所以我尝试打开文件,将其存储在缓冲区中,并使用最简单的低通滤波器的公式对其进行过滤,然后存储在另一个缓冲区中。如何在输出文件中写入输出缓冲区?

int nb;
    int buffIn[1024];
    int buffOut[1024];
    fread( buffIn, sizeof(char), 100, fp);

    //I read all data in a buffer, copy the first 44 bytes(header) and filtered the rest of it
    int i;
    for (i = 0; i < sizeof(buffIn); ++i)
    
        if(i < 44)
            buffOut[i] = buffIn[i];
        else
            buffOut[i] = buffIn[i] + buffIn[i-1];
            printf("0x%02x",buffOut[x]);
            printf("\t");
        ;
    

【问题讨论】:

我是一名前端开发人员,对 C 或信号处理了解不多。我只是想看看过滤是怎么做的,试着理解一下…… 很酷,但 Stack Overflow 并不是真正的代码编写服务,它是一个精心设计的问题和答案集合,旨在帮助未来的读者。如果您阅读教程(例如来自 google 的任意教程:dsprelated.com/freebooks/filters/Simplest_Lowpass_Filter_I.html),然后在遇到问题时返回特定问题,您可能会有更好的运气并了解更多信息 我看到了如何对一组数据进行低通过滤,但我不明白如何过滤此音频文件 那么您的任务很可能是一个单声道音频文件,因此,鉴于此,您已经读取了所有标题,只需要读取音频数据(数据的字节数由Subchunk2Size 给出,我发现this resource 有助于打开wav 文件(如果看起来有点难看)到一个数组中,这就是您过滤的内容。然后将其写回文件。 所以想一想如何将文件读入数据数组,然后低通滤波,再将数据数组写入文件。您确实阅读了标题。你将如何读取数据?您确实阅读了数据块的标题。之后文件的其余部分是实际数据。 【参考方案1】:

我想出了以下代码,但我不知道我做错了什么:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "wave.h"

 int main()
 
    FILE *fp = NULL;
    FILE *outfile = NULL;
    
     Wav wav;
     RIFF_t riff;
     FMT_t fmt;
     Data_t data;
 
     fp = fopen("3sec.wav", "rb");
     outfile = fopen("filtered.wav", "wb");

     if(!fp) 
         printf("can't open audio file\n");
         exit(1);
     

 
     fread(&wav, 1, sizeof(wav), fp);

     riff = wav.riff;
     fmt = wav.fmt;
     data = wav.data;
 
     printf("ChunkID \t%c%c%c%c\n", riff.ChunkID[0], riff.ChunkID[1], riff.ChunkID[2], riff.ChunkID[3]);
     printf("ChunkSize \t%d\n", riff.ChunkSize);
     printf("Format \t\t%c%c%c%c\n", riff.Format[0], riff.Format[1], riff.Format[2], riff.Format[3]);
     
     printf("\n");
     
     printf("Subchunk1ID \t%c%c%c%c\n", fmt.Subchunk1ID[0], fmt.Subchunk1ID[1], fmt.Subchunk1ID[2], fmt.Subchunk1ID[3]);
     printf("Subchunk1Size \t%d\n", fmt.Subchunk1Size);
     printf("AudioFormat \t%d\n", fmt.AudioFormat);
     printf("NumChannels \t%d\n", fmt.NumChannels);
     printf("SampleRate \t%d\n", fmt.SampleRate);
     printf("ByteRate \t%d\n", fmt.ByteRate);
     printf("BlockAlign \t%d\n", fmt.BlockAlign);
     printf("BitsPerSample \t%d\n", fmt.BitsPerSample);
     
     printf("\n");
 
     printf("blockID \t%c%c%c%c\n", data.Subchunk2ID[0], data.Subchunk2ID[1], data.Subchunk2ID[2], data.Subchunk2ID[3]);
     printf("blockSize \t%d\n", data.Subchunk2Size);
     
     printf("\n");
    
     printf("duration \t%d\n", data.Subchunk2Size / fmt.ByteRate);

    int nb;
    int buffIn[1024];
    int buffOut[1024];
    fread( buffIn, sizeof(char), 1, fp);

    //I read all data in a buffer, copy the first 44 bytes(header) and filtered the rest of it
    int i;
    for (i = 0; i < sizeof(buffIn); ++i)
    
        if(i < 44)
            buffOut[i] = buffIn[i];
        else
            buffOut[i] = buffIn[i] + buffIn[i-1];
            printf("0x%02x",buffOut[i]);
            printf("\t");
        ;
    
    fwrite(buffOut , 1 , sizeof(char) , outfile );

 

【讨论】:

尽量在评论区向作者提出问题或疑问,而不是在回答帖子中提问。 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。

以上是关于使用 c 中的低通滤波器过滤 .wav 文件的主要内容,如果未能解决你的问题,请参考以下文章

我的低通滤波器有啥问题?

如何将 5Hz 的低通滤波器应用于 pandas 数据帧?

matlab用低通滤波器处理wav文件

模拟模拟伪随机 LFO 信号(Javascript 中的低通滤波)

使用 Avaudioengine iOS 的低通滤波器 + 采样率转换

用电阻和电容构造一个低通滤波电路,简述其原理与特征。