c语言谱减法实现wav音频降噪
时间: 2023-09-03 14:09:22 浏览: 57
谱减法是一种常用的音频降噪方法,可以有效地降低噪声,提升音频质量。在 C 语言中,通过 FFT 算法将时域信号转换为频域信号,然后对每个频率分量的振幅进行计算,并相应地减去一定的阈值,从而实现音频的降噪。
下面是一个简单的 C 语言程序,用于实现基于谱减法的音频降噪:
```
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define SAMPLERATE 44100
#define FRAME_SIZE 2048
#define HOP_SIZE 1024
#define THR_FACTOR 1.5
typedef struct {
float re;
float im;
} complex;
float get_threshold(float *power_spectrum, int length, float factor) {
float sum = 0.0;
for (int i = 0; i < length; i++) {
sum += power_spectrum[i];
}
float mean = sum / length;
return mean * factor;
}
void apply_spectrogram_threshold(float *re, float *im, int length, float threshold) {
for (int i = 0; i < length; i++) {
if (sqrt(re[i] * re[i] + im[i] * im[i]) <= threshold) {
re[i] = 0;
im[i] = 0;
}
}
}
void apply_ifft(float *re, float *im, int length, float *output) {
complex *in = (complex *) malloc(length * sizeof(complex));
complex *out = (complex *) malloc(length * sizeof(complex));
for (int i = 0; i < length; i++) {
in[i].re = re[i];
in[i].im = im[i];
}
for (int i = 0; i < length; i++) {
out[i].re = 0;
out[i].im = 0;
for (int j = 0; j < length; j++) {
float angle = 2.0 * M_PI * i * j / length;
out[i].re += in[j].re * cos(angle) - in[j].im * sin(angle);
out[i].im += in[j].re * sin(angle) + in[j].im * cos(angle);
}
out[i].re /= length;
out[i].im /= length;
}
for (int i = 0; i < length; i++) {
output[i] = out[i].re;
}
}
int main(int argc, char **argv) {
if (argc != 3) {
printf("Usage: %s input.wav output.wav\n", argv[0]);
return 1;
}
char *input_file = argv[1];
char *output_file = argv[2];
FILE *input = fopen(input_file, "rb");
if (!input) {
printf("Error: Failed to open %s\n", input_file);
return 1;
}
FILE *output = fopen(output_file, "wb");
if (!output) {
printf("Error: Failed to open %s\n", output_file);
fclose(input);
return 1;
}
fseek(input, 0, SEEK_END);
int length = ftell(input);
fseek(input, 0, SEEK_SET);
float *buffer = (float *) malloc(length);
fread(buffer, sizeof(float), length, input);
fclose(input);
// Spectrogram
float *window = (float *) malloc(FRAME_SIZE * sizeof(float));
for (int i = 0; i < FRAME_SIZE; i++) {
window[i] = 0.5 - 0.5 * cos(2.0 * M_PI * i / FRAME_SIZE);
}
int num_frames = (length - FRAME_SIZE) / HOP_SIZE + 1;
float *spectrum = (float *) malloc(FRAME_SIZE * sizeof(float));
float *power_spectrum = (float *) malloc(FRAME_SIZE / 2 * sizeof(float));
float *output_buffer = (float *) malloc(length);
memset(output_buffer, 0, length);
for (int i = 0; i < num_frames; i++) {
memset(spectrum, 0, FRAME_SIZE * sizeof(float));
memcpy(spectrum, &buffer[i * HOP_SIZE], FRAME_SIZE * sizeof(float));
for (int j = 0; j < FRAME_SIZE; j++) {
spectrum[j] *= window[j];
}
apply_ifft(spectrum, &spectrum[FRAME_SIZE / 2], FRAME_SIZE, output_buffer);
for (int j = 0; j < FRAME_SIZE / 2; j++) {
power_spectrum[j] = output_buffer[j] * output_buffer[j] + output_buffer[FRAME_SIZE / 2 + j] * output_buffer[FRAME_SIZE / 2 + j];
}
float threshold = get_threshold(power_spectrum, FRAME_SIZE / 2, THR_FACTOR);
apply_spectrogram_threshold(spectrum, &spectrum[FRAME_SIZE / 2], FRAME_SIZE / 2, threshold);
apply_ifft(spectrum, &spectrum[FRAME_SIZE / 2], FRAME_SIZE, output_buffer);
for (int j = 0; j < FRAME_SIZE; j++) {
output_buffer[j] *= window[j];
output_buffer[j] *= 1.0 / HOP_SIZE;
output_buffer[j] += buffer[i * HOP_SIZE + j];
}
memcpy(&output_buffer[i * HOP_SIZE], output_buffer, FRAME_SIZE * sizeof(float));
}
fwrite(output_buffer, sizeof(float), length, output);
fclose(output);
free(buffer);
free(window);
free(spectrum);
free(power_spectrum);
free(output_buffer);
return 0;
}
```
该程序实现了对 WAV 格式的音频文件进行谱减法降噪,并将降噪后的结果保存到另一个 WAV 文件中。首先,程序读取输入文件,并将其中的浮点采样点存储在一个缓冲区中。然后,程序对缓冲区中的采样点进行谱减法处理,将每个帧的功率谱计算出来,并根据平均值和阈值系数计算出一个阈值,然后将小于阈值的功率谱设置为零,从而实现噪声的去除。最后,程序将降噪后的采样点存储到输出文件中。