写入 WAV 文件 C++
Posted
技术标签:
【中文标题】写入 WAV 文件 C++【英文标题】:Writing to WAV file C++ 【发布时间】:2021-09-06 22:26:26 【问题描述】:我有一个关于数字信号处理课程的 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);
【问题讨论】:
如果您在没有应用任何过滤器的情况下读取并写入文件,您是否可以读取(和收听)新文件? WAV 文件需要在前面加上标题,请参阅:docs.fileformat.com/audio/wav 行write_wav("test.wav", out, csample * ssample + WAV_HEADER_LENGTH);
使用了一个不存在的变量out
- 这显然不是您正在运行的实际代码,因为它不会编译。
为什么不使用库来处理 WAV 文件格式?如github.com/mhroth/tinywav
@mmc055 所以你必须通过编辑问题来修复错误。我们无法回答有关我们看不到的代码或我们可以看到的代码的问题,但不是您要询问的代码!具体来说,我们看不到您在在写什么。
【参考方案1】:
这对我有用:
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
,作为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]
和N
在编译时未知是一个C++ 扩展:请在您的最终代码中使用std::vector
。
下次请提供任何输入文件的链接。对于我的测试,我使用了 https://freewavesamples.com/alesis-fusion-clean-guitar-c3 ,但是所有这些小事情,比如查找输入文件(WAV 格式有几种风格,我可能会错过正确的一种),猜测过滤器参数等。时间 和努力。
您的条件if ((i - j) >= 0)
可以写成更容易理解的方式;最好通过更改内部循环“标题”。
【讨论】:
我知道“temp”可以正常工作,因为程序读取 wav 并返回“temp”。您将“temp”设置为参数,那么为什么我们有“output”?我应该将“输出”设置为参数以查看输入和输出之间的差异。 当然不是!输出只是对 temp 的参考。是同一个内存缓冲区! 您应该为输出分配一个单独的缓冲区。我建议它应该包含标准 WAV 标头的额外 44 个字节。memcopy
这些字节来自temp
或手动设置它们。然后根据您的过滤器设置“声音”字节。目前你使用“输出”作为输入和输出缓冲区,这本质上是错误的。
data
、output
和 temp
指的是相同的内存(只是初始偏移量略有不同)。从算法上讲,这看起来并不“犹太”,但据我所知,您问为什么您的输出文件根本没有播放。这是一个不同的问题。根据我们的对话,我推断您可能忘记在输出文件中添加 WAV 标头。
@mmc055 因为那样你只会编写没有元数据标头的示例数据。那么它就不是一个有效的 WAV。由于您不厌其烦地阅读和显示标题数据,因此不清楚为什么这不明显,而且问题中的代码既不写临时也不写输出(直到您按要求编辑)不清楚您的问题是,除了你的暴露评论。以上是关于写入 WAV 文件 C++的主要内容,如果未能解决你的问题,请参考以下文章