加工用C音频WAV文件 [英] processing an audio wav file with C

查看:227
本文介绍了加工用C音频WAV文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理WAV文件的振幅和一些小数因素进行缩放。我想换我围绕如何读取和存储高效的方式重新写入文件,同时试图解决语言(我是新的C)的细微差别头。该文件可以是在任一个8位或16位的格式。我想这样做的方式是通过先读头数据的成一些pre定义的结构,然后处理在一个循环中的实际数据,我会读一大块数据到缓冲区中,做任何需要它,然后把它写入到输出。

I'm working on processing the amplitude of a wav file and scaling it by some decimal factor. I'm trying to wrap my head around how to read and re-write the file in a memory-efficient way while also trying to tackle the nuances of the language (I'm new to C). The file can be in either an 8- or 16-bit format. The way I thought of doing this is by first reading the header data into some pre-defined struct, and then processing the actual data in a loop where I'll read a chunk of data into a buffer, do whatever is needed to it, and then write it to the output.

#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;
}

我得到在年底不同的文件大小(以1K左右,对于一个40MB的文件),我怀疑这是由于这样的事实,我正在写一个完整的缓冲输出,即使该文件填充整个缓冲区大小之前可能已终止。此外,输出文件搞砸了 - 不能播放或打开 - 所以我可能做整个事情是错误的。在那里我搞砸任何提示将是巨大的。谢谢!

I'm getting differing file sizes at the end (by 1k or so, for a 40Mb file), and I suspect this is due to the fact that I'm writing an entire buffer to the output, even though the file may have terminated before filling the entire buffer size. Also, the output file is messed up - won't play or open - so I'm probably doing the whole thing wrong. Any tips on where I'm messing up will be great. Thanks!

推荐答案

1 您正在阅读字节而不是16位采样在这个else分支:

1 You're reading bytes instead of 16-bit samples in this else branch:

while (!feof(infile))
    {
        if (is_8bit)
        {
            fread(inbuff8, 1, BUFSIZE, infile);   
        } else {
            fread(inbuff16, 1, BUFSIZE, infile); // <-- should be BUFSIZE*2     
        }

2 缩放,当你不饱和值,例如原来的16位样本= 32000和因子= 1.5将环绕整数值,而不是它的夹紧到最大32767的

2 You don't saturate the values when scaling, e.g. original 16-bit sample = 32000 and factor = 1.5 will wrap around the integer value instead of clamping it to the maximum of 32767.

3 您不看的RIFF和其他头都没有。在WAV文件,它是可能的音频数据随后通过附加标头pceded一些信息页脚或$ P $。或者换句话说:你的结构过于静态的。你也应该从文件中读取WAV格式而不是一个参数,说这是8位的样品。

3 You don't look at the RIFF and other headers at all. In WAV files, it is possible that the audio data is followed by some informational footers or preceded by additional headers. Or in other words: Your header struct is too static. You should also read the WAV format from the file instead of having a parameter saying it's 8 bit samples.

4 这是不会发生的:

                outbuff16[i] = factor * inbuff16[i];
                if ((int)outbuff16[i] > MAX_16BIT_AMP)

8位/ 16位的值永远不会大于三万二千七百六十八分之二百五十五除非你的电脑中插入一些魔法位到内存时的整数溢出:P

8-bit/16-bit values will never be greater than 255/32768 except if your computer inserts some magic bits into the memory when integers overflows :P

和音频样本签名,这样的范围是-128; 1​​27 -32768; 32767。溢出检查必须发生在繁殖前pression。你还对浮点到整数的舍入模式,这是可配置的,应考虑作出假设。类似如果(roundf(因子* inbuff16 [I])GT; 32767 || roundf(因子* inbuff16 [I])LT; -32768)。,也许

And audio samples are signed, so the ranges are -128;127 and -32768;32767. Overflow checking must occur in the multiplication expression. You're also making assumptions on the floating-point-to-integer rounding mode, which is configurable and should be considered. Something like if(roundf(factor * inbuff16[i]) > 32767 || roundf(factor * inbuff16[i]) < -32768), maybe.

5 您不存储 FREAD 的结果,所以你写太多的样本输出文件。

5 You don't store the result of fread, so you will write too many samples to the output file.

6 并作为最后一点,你重新发明轮子。只要这是学习,这没关系。否则,你应该使用现有的库。

6 And as a last point, you're reinventing the wheel. As long as this is for learning, it's okay. Else you should use existing libraries.

这篇关于加工用C音频WAV文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆