用C ++将缓冲区导出为WAV

时间:2015-06-24 10:27:58

标签: c++ audio wav cycle sine

我有一个简单的程序,它创建一个单循环正弦波并将浮点数放入缓冲区。然后将其导出到文本文件。 但我希望能够将其导出为WAV文件(24位)。是否有一种简单的方法可以像在文本文件中那样进行操作?

这是我到目前为止的代码:

#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

int main ()
{
    long double pi = 3.14159265359; // Declaration of PI

    ofstream textfile; // Text object
    textfile.open("sine.txt"); // Creating the txt

    double samplerate = 44100.00; // Sample rate

    double frequency = 200.00; // Frequency

    int bufferSize = (1/frequency)*samplerate; // Buffer size

    double buffer[bufferSize]; // Buffer

    for (int i = 0; i <= (1/frequency)*samplerate; ++i) // Single cycle
    {
        buffer[i] = sin(frequency * (2 * pi) * i / samplerate); // Putting into buffer the float values
        textfile << buffer[i] << endl; // Exporting to txt
    }

    textfile.close(); // Closing the txt
    return 0; // Success
}

1 个答案:

答案 0 :(得分:3)

首先,您需要打开二进制流。

ofstream stream;
stream.open("sine.wav", ios::out | ios::binary);

接下来,您需要写出一个wave标头。您可以搜索以查找波形文件格式的详细信息。重要的位是采样率,位深度和数据长度。

int bufferSize = (1/frequency)*samplerate; 
stream.write("RIFF", 4);                    // RIFF chunk
write<int>(stream, 36 + bufferSize*sizeof(int)); // RIFF chunk size in bytes
stream.write("WAVE", 4);                    // WAVE chunk
stream.write("fmt ", 4);                    // fmt chunk
write32(stream, 16);                     // size of fmt chunk
write16(stream, 1);                       // Format = PCM
write16(stream, 1);                       // # of Channels
write32(stream, samplerate);                // Sample Rate
write32(stream, samplerate*sizeof(int));    // Byte rate
write16(stream, sizeof(int));             // Frame size
write16(stream, 24);                      // Bits per sample
stream.write("data", 4);                   // data chunk
write32(stream, bufferSize*sizeof(int));   // data chunk size in bytes

现在标题已经不在了,你只需要修改你的循环就可以先将double(-1.0,1.0)样本转换成32位signed int。截断底部的8位,因为您只需要24位然后写出数据。您知道,通常的做法是在32位字中存储24位样本,因为使用本机类型更容易实现。

for (int i = 0; i < bufferSize; ++i) // Single cycle
{
    double tmp = sin(frequency * (2 * pi) * i / samplerate); 
    int intVal = (int)(tmp * 2147483647.0) & 0xffffff00;
    stream << intVal;
}

其他一些事情:

1)我不知道你在循环中使用buffer是如何溢出<=的。我将其更改为<

2)再次考虑缓冲区大小。我不确定您是否知道,但是对于所有频率,您不能以单个周期表示重复波形。我的意思是,对于大多数频率,如果您使用此代码并期望重复播放波形,您将在每个周期听到一个小故障。它适用于1kHz等漂亮的同步频率,因为每个周期将有48个样本,它将会出现完全相同的相位。然而,999.9赫兹将是一个不同的故事。