写入.WAV - C ++时的两个问题

时间:2014-03-06 14:06:21

标签: c++ templates audio wav fstream

我目前正在使用C ++中的openFrameworks编写程序音乐引擎。我可以生成一首歌并从浮点数的标准化(在-1和1之间)缓冲区中播放它完全没问题,但是当我尝试将相同的浮点缓冲区写入32位时,我遇到了一些问题.WAV文件。

  1. 当我在Finder的预览中回放文件时(我在OSX 10.9.2上),整个歌曲持续时间的播放被极度剪裁和扭曲。它似乎能够很好地读取格式,因为它显示正确的文件持续时间,比特率和采样率http://i.stack.imgur.com/fz2w8.png。奇怪的是,当我将同一个文件拖到Logic Pro X中时,它被读取正确,转换成功并无失真地播放。它还会生成一个波形显示,我可以看到两个通道(文件是立体声)的波形完全标准化(至少上半年......见下一期)。

  2. 虽然Logic Pro X能够比Finder的预览更成功地读取文件,但是在歌曲中途有一个很大的幅度跳跃并且波形开始剪辑(尽管远不及Finder回放中那么多) )。每次生成的歌曲(它们在结构上,节奏上和乐器上每次都不同)都会发生这种情况,我试图写入.WAV。您可以在此处查看示例http://i.stack.imgur.com/59y5w.jpg

  3. 以下是我用来写入.WAV文件的代码:

    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);                // Open file stream at "outFile" location
    
        /* Header */
        stream.write("RIFF", 4);                                        // sGroupID (RIFF = Resource Interchange File Format)
        write<int>(stream, 36 + bufSize);                               // dwFileLength
        stream.write("WAVE", 4);                                        // sRiffType
    
        /* Format Chunk */
        stream.write("fmt ", 4);                                        // sGroupID (fmt = format)
        write<int>(stream, 16);                                         // Chunk size (of Format Chunk)
        write<short>(stream, 1);                                        // Format (1 = PCM)
        write<short>(stream, channels);                                 // Channels
        write<int>(stream, sampleRate);                                 // Sample Rate
        write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
        write<short>(stream, channels * sizeof(SampleType));            // Frame size aka Block align
        write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample
    
        /* Data Chunk */
        stream.write("data", 4);                                        // sGroupID (data)
        stream.write((const char*)&bufSize, 4);                         // Chunk size (of Data, and thus of bufferSize)
        stream.write((const char*)buf, bufSize);                        // The samples DATA!!!
    }
    

    我使用以下行调用“writeWAVData”函数:

    writeWAVData(path.c_str(), &buffer[0], sampleDuration * NUM_OF_CHANNELS * sizeof(buffer[0]), sampleRate, NUM_OF_CHANNELS);
    

    其中:

    • path是包含文件路径的字符串。
    • buffer是动态分配的float s数组,它是我的样本缓冲区(我在此步骤之前对样本进行规范化,当我cout时,我可以看到它们完全在-1.0f1.0f之间,没有任何剪辑。
    • sampleRate的采样率为int
    • sampleDuration是样本中的持续时间int
    • NUM_OF_CHANNELS是定义的标头int(在这种情况下为2)。

    任何建议,手腕上的拍打,完美的解决方案或严厉的批评都非常感谢!

    解决方案:问题是我将“格式块”中的格式标记设置为1表示PCM。将其更改为3(对于FLOAT格式)后,.wav文件将完美播放。原始答案https://stackoverflow.com/a/22227440/1711917

1 个答案:

答案 0 :(得分:2)

我没有检查游标标题,看起来很好,但最好在十六进制编辑器中查看文件并与a reference进行比较。我认为你的问题在于:

  

缓冲区是一个动态分配的浮点数组,它是我的样本缓冲区(我在这一步之前对样本进行规范化,当我对它们进行规范时,我可以看到它们完全在-1.0f和1.0f之间,没有任何剪裁)

您直接转储float数组,但WAV / PCM使用整数样本,通常为8或16位。在这里指定32位样本并将它们编码为浮点数而不是整数。

您有3个选项:

  • 使用char[]short[]数据
  • 生成float[]但在写入文件前转换为char[]short[]
  • 更改格式以支持浮点数据:format-tag 3 / FLOAT而不是1 / PCM,see here