使用 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 文件的主要内容,如果未能解决你的问题,请参考以下文章
模拟模拟伪随机 LFO 信号(Javascript 中的低通滤波)