如何创建PCM签名的16位wav文件

时间:2014-02-06 15:04:27

标签: c++ wav

我有一个原始音频流的二进制二进制文件。我想创建一个wav文件,其属性PCM签名为16位单声道小端,采样率为22050hz。

目前正在使用以下代码:

template <typename T>
void write(std::ofstream& stream, const T& t) {
    stream.write((const char*)&t, sizeof(T));
}

template <typename SampleType>
void writeWAVData(const char* outFile, SampleType* buf, size_t bufSize,
                  int sampleRate, short channels)
{
    std::ofstream stream(outFile, std::ios::binary);
    stream.write("RIFF", 4);
    write<int>(stream, 36 + bufSize);
    stream.write("WAVE", 4);
    stream.write("fmt ", 4);
    write<int>(stream, 16);
    write<short>(stream, 1);                                        // Format (1 = PCM)
    write<short>(stream, channels);                                 // Channels //mono/sterio
    write<int>(stream, sampleRate); 

    write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
    write<short>(stream, channels * sizeof(SampleType));            // Frame size
    write<short>(stream, 16 * sizeof(SampleType));                   // Bits per sample
    stream.write("data", 4);
    stream.write((const char*)&bufSize, 4);
    stream.write((const char*)buf, bufSize);
}


int wmain(int argc,wchar_t **argv)
{
    std::ifstream is("c:\\stream", std::ios_base::binary);
    if (is) {
        // get length of file:
        is.seekg (0, is.end);
        int length = is.tellg();
        is.seekg (0, is.beg);
        char * buffer = new char [length];
        is.read (buffer,length);
        writeWAVData("c:\\audio.wav", buffer, length, 22050, 1);
    }
}

有人可以帮我解决这里的错误吗?

3 个答案:

答案 0 :(得分:1)

通过将char*指针作为buf参数传递,样本类型推导为char。如果样本实际上是16位,那么取决于sizeof(SampleType)的值将是错误的。

你可以施展到short*;但最好删除templatiness并将样本大小作为另一个运行时参数传递。在任何一种情况下,您应该乘以8(或CHAR_BIT),而不是16,以获得位数。

答案 1 :(得分:1)

我看到的几个问题是:

  1. buffer必须为short*int16_t*才能使SampleType为16位。

  2. 每个样本写入位时,
  3. write<short>(stream, 16 * sizeof(SampleType));应为write<short>(stream, 8 * sizeof(SampleType));

  4. 如果stream.write((const char*)&bufSize, 4);不是4个字节(在64位系统上通常是8个字节),
  5. size_t做得不对,因为你基本上切断了{的前4个字节{1}}并写下它们。您需要首先将static_cast转换为32位整数:

    bufSize
  6. 可能还有其他问题,但这些问题对我来说很明显。

答案 2 :(得分:1)

谢谢你们,你们是对的。这是我最后的工作代码

template <typename T>
void write(std::ofstream& stream, const T& t) {
    stream.write((const char*)&t, sizeof(T));
}

template <typename SampleType>
void writeWAVData(const char* outFile, SampleType* buf, size_t bufSize,
                  int sampleRate, short channels)
{
    std::ofstream stream(outFile, std::ios::binary);
    stream.write("RIFF", 4);
    write<int>(stream, 36 + bufSize);
    stream.write("WAVE", 4);
    stream.write("fmt ", 4);
    write<int>(stream, 16);
    write<short>(stream, 1);                                        // Format (1 = PCM)
    write<short>(stream, channels);                                 // Channels //mono/sterio
    write<int>(stream, sampleRate); 

    write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
    write<short>(stream, channels * sizeof(SampleType));            // Frame size
    write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample
    stream.write("data", 4);
    uint32_t sz = bufSize;
    stream.write((const char*)&sz, 4);
    stream.write((const char*)buf, bufSize);
}


int wmain(int argc,wchar_t **argv)
{
    FILE *fhandle=fopen("c:\\stream","rb");
    seek(fhandle, 0, SEEK_END); // seek to end of file
    int length ; = ftell(fhandle); // get current file pointer
    fseek(fhandle, 0, SEEK_SET); // seek back to beginning of file
    length = length * 16;
    short* Data=new short [length]; // Create an element for every sample
fread(Data,16/8,length/(16/8),fhandle);//read data
    writeWAVData("c:\\audio.wav", buffer, length, 22050, 1);
  }
}