sa1*_*125 8 c wav audio-processing
我正在处理wav文件的幅度并按一些小数因子进行缩放.我试图以有效记忆的方式阅读和重写文件,同时也试图解决语言的细微差别(我是C的新手).该文件可以是8位或16位格式.我想这样做的方法是首先将头数据读入一些预定义的结构,然后在循环中处理实际数据,我将把一大块数据读入缓冲区,做任何需要它,然后将其写入输出.
#include <stdio.h>
#include <stdlib.h>
typedef struct header
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
short int extra_param_size;
char subchunk2_id[4];
int subchunk2_size;
} header;
typedef struct header* header_p;
void scale_wav_file(char * input, float factor, int is_8bit)
{
FILE * infile = fopen(input, "rb");
FILE * outfile = fopen("outfile.wav", "wb");
int BUFSIZE = 4000, i, MAX_8BIT_AMP = 255, MAX_16BIT_AMP = 32678;
// used for processing 8-bit file
unsigned char inbuff8[BUFSIZE], outbuff8[BUFSIZE];
// used for processing 16-bit file
short int inbuff16[BUFSIZE], outbuff16[BUFSIZE];
// header_p points to a header struct that contains the file's metadata fields
header_p meta = (header_p)malloc(sizeof(header));
if (infile)
{
// read and write header data
fread(meta, 1, sizeof(header), infile);
fwrite(meta, 1, sizeof(meta), outfile);
while (!feof(infile))
{
if (is_8bit)
{
fread(inbuff8, 1, BUFSIZE, infile);
} else {
fread(inbuff16, 1, BUFSIZE, infile);
}
// scale amplitude for 8/16 bits
for (i=0; i < BUFSIZE; ++i)
{
if (is_8bit)
{
outbuff8[i] = factor * inbuff8[i];
if ((int)outbuff8[i] > MAX_8BIT_AMP)
{
outbuff8[i] = MAX_8BIT_AMP;
}
} else {
outbuff16[i] = factor * inbuff16[i];
if ((int)outbuff16[i] > MAX_16BIT_AMP)
{
outbuff16[i] = MAX_16BIT_AMP;
} else if ((int)outbuff16[i] < -MAX_16BIT_AMP) {
outbuff16[i] = -MAX_16BIT_AMP;
}
}
}
// write to output file for 8/16 bit
if (is_8bit)
{
fwrite(outbuff8, 1, BUFSIZE, outfile);
} else {
fwrite(outbuff16, 1, BUFSIZE, outfile);
}
}
}
// cleanup
if (infile) { fclose(infile); }
if (outfile) { fclose(outfile); }
if (meta) { free(meta); }
}
int main (int argc, char const *argv[])
{
char infile[] = "file.wav";
float factor = 0.5;
scale_wav_file(infile, factor, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我最后得到的文件大小不同(大约1k左右,40Mb文件),我怀疑这是因为我正在写一个完整的缓冲区到输出,即使文件可能已经终止在填充整个缓冲区大小之前.此外,输出文件搞砸了 - 不会播放或打开 - 所以我可能做错了.关于我搞砸的地方的任何提示都会很棒.谢谢!
1您正在读取其他分支中的字节而不是16位样本:
while (!feof(infile))
{
if (is_8bit)
{
fread(inbuff8, 1, BUFSIZE, infile);
} else {
fread(inbuff16, 1, BUFSIZE, infile); // <-- should be BUFSIZE*2
}
Run Code Online (Sandbox Code Playgroud)
2缩放时不会使值饱和,例如原始16位采样= 32000且因子= 1.5将环绕整数值而不是将其钳位到最大值32767.
3你根本不看RIFF和其他标题.在WAV文件中,音频数据可能后跟一些信息页脚或前面有其他标题.换句话说:你的header结构太静态了.您还应该从文件中读取WAV格式,而不是让参数说明它是8位样本.
4这不会发生:
outbuff16[i] = factor * inbuff16[i];
if ((int)outbuff16[i] > MAX_16BIT_AMP)
Run Code Online (Sandbox Code Playgroud)
8位/ 16位值永远不会大于255/32768,除非您的计算机在整数溢出时将一些魔术位插入内存:P
音频样本已签名,因此范围为-128; 127和-32768; 32767.溢出检查必须在乘法表达式中进行.您还可以对浮点到整数舍入模式进行假设,这种模式是可配置的,应予以考虑.if(roundf(factor * inbuff16[i]) > 32767 || roundf(factor * inbuff16[i]) < -32768)也许是这样的.
5您不存储结果fread,因此您将向输出文件中写入太多样本.
6作为最后一点,你正在重新发明轮子.只要这是为了学习,没关系.否则你应该使用现有的库.