C ++ - 读取16位.wav文件

时间:2014-01-25 02:06:54

标签: python c++ audio

我正在尝试读取.wav文件,我认为它给了我正确的结果,但是,当我在Matlab或Python中绘制相同的音频文件时,结果是不同的。

这是我得到的结果:

enter image description here

这是Python(用matplotlib绘制)给出的结果:

enter image description here

结果似乎没有什么不同,但是,当涉及到分析时,这会弄乱我的结果。

以下是转换代码:

for (int i = 0; i < size; i += 2)
{
    int c = (data[i + 1] << 8) | data[i];
    double t = c/32768.0;
                //cout << t << endl;
    rawSignal.push_back(t);
}

我哪里错了?因为,这种转换似乎很好,并且确实产生了类似的结果。

谢谢

编辑:

读取标题/数据的代码:

voidreadHeader(ifstream& file) {



 s_riff_hdr riff_hdr;
    s_chunk_hdr chunk_hdr;

    long padded_size; // Size of extra bits

    vector<uint8_t> fmt_data; // Vector to store the FMT data.

    s_wavefmt *fmt = NULL;

    file.read(reinterpret_cast<char*>(&riff_hdr), sizeof(riff_hdr));
    if (!file) return false;

    if (memcmp(riff_hdr.id, "RIFF", 4) != 0) return false;

    //cout << "size=" << riff_hdr.size << endl;
    //cout << "type=" << string(riff_hdr.type, 4) << endl;

    if (memcmp(riff_hdr.type, "WAVE", 4) != 0) return false;
    {
         do
         {
            file.read(reinterpret_cast<char*>(&chunk_hdr), sizeof(chunk_hdr));
            if (!file) return false;
            padded_size = ((chunk_hdr.size + 1) & ~1);

            if (memcmp(chunk_hdr.id, "fmt ", 4) == 0) 
            {
                if (chunk_hdr.size < sizeof(s_wavefmt)) return false;

                fmt_data.resize(padded_size);
                file.read(reinterpret_cast<char*>(&fmt_data[0]), padded_size);
                if (!file) return false;

                fmt = reinterpret_cast<s_wavefmt*>(&fmt_data[0]);

                sample_rate2 = fmt->sample_rate;

                if (fmt->format_tag == 1) // PCM
                {
                    if (chunk_hdr.size < sizeof(s_pcmwavefmt)) return false;

                    s_pcmwavefmt *pcm_fmt = reinterpret_cast<s_pcmwavefmt*>(fmt);


                    bits_per_sample = pcm_fmt->bits_per_sample;
                }
                else
                {
                    if (chunk_hdr.size < sizeof(s_wavefmtex)) return false;

                    s_wavefmtex *fmt_ex = reinterpret_cast<s_wavefmtex*>(fmt);


                    if (fmt_ex->extra_size != 0)
                    {
                        if (chunk_hdr.size < (sizeof(s_wavefmtex) + fmt_ex->extra_size)) return false;

                        uint8_t *extra_data = reinterpret_cast<uint8_t*>(fmt_ex + 1);
                        // use extra_data, up to extra_size bytes, as needed...
                    }

                }
                //cout << "extra_size=" << fmt_ex->extra_size << endl;
            }

            else if (memcmp(chunk_hdr.id, "data", 4) == 0)
            {
                // process chunk data, according to fmt, as needed...
                size = padded_size;

                if(bits_per_sample == 16)
                {
                    //size = padded_size / 2;
                }

                data = new unsigned char[size];

                file.read(data,     size);

                file.ignore(padded_size);
                if (!file) return false;
            }
            {
                // process other chunks as needed...

                file.ignore(padded_size);
                if (!file) return false;
            }

        }while (!file.eof());
         return true;
     }

 }

这是“转换为双倍”的地方:

if(bits_per_sample == 8)
        {
            uint8_t c;  
            //cout << size;
            for(unsigned i=0; (i < size); i++)
            {
                c = (unsigned)(unsigned char)(data[i]);
                double t = (c-128)/128.0;
                rawSignal.push_back(t);
            }
        }
        else if(bits_per_sample == 16)
        {

            for (int i = 0; i < size; i += 2)
            {
                int c;
                c = (unsigned) (unsigned char) (data[i + 2] << 8) | data[i];
                double t = c/32768.0;
                rawSignal.push_back(t);
        }

请注意“8位”文件如何正常工作?

1 个答案:

答案 0 :(得分:3)

我怀疑您的问题可能是data是一组已签名的 char值。所以,当你这样做时:

int c = (data[i + 1] << 8) | data[i];

......它实际上并没有做你想要的。我们来看一些简单的例子。

如果data[i+1] == 64data[i] == 64,那将是0x4000 |一切都好的0x40或0x4040。

如果data[i+1] == -64data[i] == -64,那将是0xffffc000 | 0xffffffc0或0xffffffc0,这显然是错误的。

如果您使用的是unsigned char值,那么这将起作用,因为这些数字不是-64而是192,而您最终会得到0xc000 | 0xc0或0xc0c0,就像你想要的那样。 (但是你的/32768.0会给你0.0到2.0范围内的数字,当你想要-1.0到1.0时。)

如果不知道你究竟想要做什么,建议“修复”很困难。显然,您希望将某种16位小端整数格式转换为某种浮点格式,但很多都依赖于这些格式的确切细节,并且您没有提供任何此类细节。默认的.wav格式是16位无符号小端整数,因此只需使用unsigned char *即可修复该等式的那部分。但我不知道任何使用从0.0到2.0的64位浮点数的音频格式,我不知道你实际上的目标是什么音频格式,所以我不能说那是{{1实际应该是,只是它可能是错误的。