c++ - 写入 WAV 文件 C++
问题描述
我有一个关于数字信号处理类的 WAV 文件和 FIR 滤波器的作业。
我的程序必须读取 WAV 文件,对数据应用过滤器并将输出数据再次写入另一个 WAV 文件。
我已完成阅读和应用过滤器,但我无法编写 WAV 文件。程序在编译时不会出错,但 WAV 文件无法播放。
如果我将“temp”写入 WAV,它会正常运行。但如果我写“数据”,它不会。
如何正确编写 WAV 文件?
#define _CRT_SECURE_NO_WARNINGS
#define PI 3.14f
#define WAV_HEADER_LENGTH 44
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
char* read_wav(const char* filename, short*, short*, int*);
void write_wav(const char* filename, const char*, int);
using namespace std;
int main()
{
short nchannel, ssample;
int csample;
//Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
cout << "How many coefficients are there in filter ?" << endl;
int N;
cin >> N ;
float filter[N];
cout << "Type coefficients in filter." << endl;
for(int i=0; i<N;i++){
cin >> filter[i];
}
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for(int i=0; i < csample; i++){
double sum = 0;
for(int j=0; j < N; j++){
if((i - j) >= 0)
sum += filter[j] * data[i-j];
}
output[i] = (short) sum;
}
write_wav("test.wav", out, csample * ssample + WAV_HEADER_LENGTH);
}
char* read_wav(const char* filename, short* nchannel, short* ssample, int* csample) {
//Reading the file.
FILE* fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("The file \"%s\" has %d bytes\n\n", filename, file_size);
char* buffer = (char*)malloc(sizeof(char) * file_size);
fread(buffer, file_size, 1, fp);
// Dump the buffer info.
*nchannel = *(short*)&buffer[22];
*ssample = *(short*)&buffer[34] / 8;
*csample = *(int*)&buffer[40] / *ssample;
printf("ChunkSize :\t %u\n", *(int*)&buffer[4]);
printf("Format :\t %u\n", *(short*)&buffer[20]);
printf("NumChannels :\t %u\n", *(short*)&buffer[22]);
printf("SampleRate :\t %u\n", *(int*)&buffer[24]); // number of samples per second
printf("ByteRate :\t %u\n", *(int*)&buffer[28]); // number of bytes per second
printf("BitsPerSample :\t %u\n", *(short*)&buffer[34]);
printf("Subchunk2ID :\t \"%c%c%c%c\"\n", buffer[36], buffer[37], buffer[38], buffer[39]); // marks beginning of the data section
printf("Subchunk2Size :\t %u\n", *(int*)&buffer[40]); // size of data (byte)
printf("Duration :\t %fs\n\n", (float)(*(int*)&buffer[40]) / *(int*)&buffer[28]);
fclose(fp);
return buffer;
}
void write_wav(const char* filename, const char* data, int len) {
FILE* fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Couldn't open the file \"%s\"\n", filename);
exit(0);
}
fwrite(data, len, 1, fp);
fclose(fp);
}
解决方案
这对我有用:
int main()
{
short nchannel, ssample;
int csample;
// Reading WAV file and returning the data.
char* temp = read_wav("sum.wav", &nchannel, &ssample, &csample);
short* data = (short*)&temp[WAV_HEADER_LENGTH];
// cout << "How many coefficients are there in filter ?" << endl;
const int N = 2;
// cin >> N;
float filter[N] = {0.5, 0.75};
// cout << "Type coefficients in filter." << endl;
// for (int i = 0; i < N; i++)
// {
// cin >> filter[i];
// }
short* output = (short*)&temp[WAV_HEADER_LENGTH];
for (int i = 0; i < csample; i++)
{
double sum = 0;
for (int j = 0; j < N; j++)
{
if ((i - j) >= 0) sum += filter[j] * data[i - j];
}
output[i] = (short)sum;
}
write_wav("test.wav", (char*)temp, csample * ssample + WAV_HEADER_LENGTH);
}
我的改变:
- 主要的变化是使用完整的缓冲区,名称极具误导性:
temp
,而不是你的out
that 不编译,作为write_wav
. - 我应用了“我的”滤波器系数(输出文件中的声音真的很失真),
- 我应用了我最喜欢的缩进
如果代码是可移植的,您需要检查字节序并采取相应措施。
我希望输入和输出文件的长度相同,但事实并非如此。请自行检查为什么不是这种情况。例子:
-rw-r--r-- 1 zkoza zkoza 787306 06-23 14:09 sum.wav
-rw-r--r-- 1 zkoza zkoza 787176 06-23 14:16 test.wav
输出文件中似乎缺少 130 个字节。
您的float filter[N]
with N
not known at compile time 是 C++ 扩展:请std::vector
在您的最终代码中使用。
下次请提供任何输入文件的链接。对于我的测试,我使用了https://freewavesamples.com/alesis-fusion-clean-guitar-c3 ,但是所有这些小东西,比如查找输入文件(WAV 格式有多种风格,我可能错过了正确的一种) ,猜测过滤器参数等需要时间和精力。
你的情况if ((i - j) >= 0)
可以用更容易理解的方式写出来;最好通过更改内部循环“标题”。
推荐阅读
- ibm-watson - 请求有效负载的公平配置模式
- php - PHP_xlsxwriter 不在服务器上工作(file_exists 无法检测到)
- java - 将流和收集器与 Maps 的 ArrayList 一起使用时出现不兼容的类型错误
- php - 为什么php不通过break退出循环?
- swift - 自定义 UILabel 类不改变属性?
- android - 在 build.gradle 中设置变量
- c - 奇怪的右位移不一致
- javascript - 当我清除画布时“canvas.clearRect 不是函数”
- vb.net - 将值从两个条形码扫描仪传递到两个特定的 texbox。
- python-3.x - Selenium Web Scraping Id 缺失