从数据实时创建WAV文件 - 需要帮助

Creating WAV file from data in real time - need assist

本文关键字:帮助 文件 WAV 数据 实时 创建      更新时间:2023-10-16

我对音频处理很陌生,我的C++编程技能也处于基础水平。我必须创建记录功能,并以回调的形式从设备接收数据信号。我希望有人在基本理论方面帮助我,我应该如何管理 WAV 内存,因为我迷路了。现在我的代码如下所示:

我目前正在使用的功能:

template <typename T>
void write(std::ofstream& stream, const T& t) {
  stream.write((const char*)&t, sizeof(T));
}
template <typename T>
void writeFormat(std::ofstream& stream) {
  write<short>(stream, 1);
}
template <>
void writeFormat<float>(std::ofstream& stream) {
  write<short>(stream, 3);
}
template <typename SampleType>
void writeWAVData(
  char const* outFile,
  SampleType* buf,
  size_t bufSize,
  int sampleRate,
  short channels)
{
  std::ofstream stream(outFile, std::ios::binary|ios::app|ios::ate);
  stream.write("RIFF", 4);                                        // Start writting RIFF
  write<int>(stream, 0);                                          // (file-size)-8 - FOR NOW IGNORED
  stream.write("WAVE", 4);                                        // File type
  stream.write("fmt ", 4);                                        // Start Writting format chunk "fmt"
  write<int>(stream, 16);                                         // Chunk Data Size 16 + extra format bytes
  writeFormat<SampleType>(stream);                                // Format (compression code)
  write<short>(stream, channels);                                 // Channels
  write<int>(stream, sampleRate);                                 // Sample Rate
  write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate (byte/per sec)
  write<short>(stream, channels * sizeof(SampleType));            // Frame size (block align)
  write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample 
  stream.write("data", 4);                                        // Start writting chunk for extra format bytes
  stream.write((const char*)&bufSize, 0);                         //  - FOR NOW IGNORED
  stream.write((const char*)buf, 0);                              //  - FOR NOW IGNORED
}

我想做的大致想法是:

  1. 创建 *.wav 文件。
  2. 写入标头块。
  3. 文件末尾添加新数据,只要用户不停止它。
  4. 当用户单击停止时,返回到标头内存并编辑"RIFF"和"数据"块下的字段,具有正确的值。

第一个问题:所以我有缓冲区存储 256 个样本,所以循环,每 256 个我尝试将带有新数据的缓冲区写入文件,如下面的代码所示。阅读 *.wav 文档 http://www.sonicspot.com/guide/wavefiles.html 后,我明白 *.wav 文件应该在每个块的开头都有 RIFF 标头。但是,如果我编写包含 256 个样本的缓冲区并将 RIFF 块放在它之前,如果我输入 512 个样本有什么区别?每个样本都需要 RIFF 块才能使用吗?

for (int j = 0 ; j < 256 ; j++)
{
    if (j == 255) 
        writeWAVData("mySound0.wav", (int*)bufferInfos[0].buffers[doubleBufferIndex], buffSize, 44100, 1);
}

哪里:

  • bufferInfos[] - 保存各种缓冲区的表,但我现在只想保存一个缓冲区的数据
  • bufferInfos[0].buffers[doubleBufferIndex] - 是指向第一个缓冲区数据块的指针
  • 双缓冲区索引 - 平移的索引,取值 0-1,左、右、左、右等

第二个问题:是关于通道参数的,因为它有点混乱。我的信号由依次接收的值组成:左平移、右平移、左平移、右平移......所以这意味着我有 2 个通道 - 左和右?

第三个问题:我来自设备的信号是24位...我不应该只写每个样本 24 的位,或者它应该如何包含这些信息。

RIFF 标头在每个文件的开头出现一次。您尝试包含多个。

通常,WAVE标头在每个记录中显示一次。这。WAV 格式允许多个,但这类似于专辑。

显然,你确实有两个渠道。

是的,如果每个样本有 24 位,那么您必须将其放入,并且每个样本正好写入 3 个字节。也就是说,

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

不太可能这样做。sizeof(SampleType)可能也不是 3。