Record/Convert 音频数据实时转WAV

Record/Convert AUDIO data to WAV in Real-time

我是音频信号处理方面的新手。

目前我已将设备连接到我的 PC,它从 mic/playback 轨道向我发送音频数据。我已经使用连接到设备并重复回调 returns 原始数据的 Steinberg ASIO SDK 2.3 创建了主机应用程序。信号是 24 位的,频率可以随意选择,比方说 44100 hZ,2pan's,单通道。我也将此信号转换为 double <-1.0, 1.0> 因为我正在对其进行一些信号处理。

我现在想做的是为我的主机添加录音功能。例如,在单击按钮时,传入的数据会不断转换为 WAV 文件,当我单击其他按钮时,它会停止并保存。

我已经阅读了有关 WAV 文件、文件格式、比特流格式 (RIFF) 的内容,并且以某种方式对 WAV 文件的外观有了一个整体的了解。我还检查了很多论坛线程、Whosebug 的线程或代码项目帖子,到处都能找到与主题相关的内容,但我不知道如何实时进行持续记录。我发现的很多代码都是关于在对数据数组进行修改后将其转换为 WAV 的。我想进行持续的转换并制作 WAV 文件 appending/expanding 直到我告诉它停止。

例如,我可以修改一下吗?

#include <fstream>

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);
  stream.write("RIFF", 4);
  write<int>(stream, 36 + bufSize);
  stream.write("WAVE", 4);
  stream.write("fmt ", 4);
  write<int>(stream, 16);
  writeFormat<SampleType>(stream);                                // Format
  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
  write<short>(stream, 8 * sizeof(SampleType));                   // Bits per sample
  stream.write("data", 4);
  stream.write((const char*)&bufSize, 4);
  stream.write((const char*)buf, bufSize);
}

并以某种方式在回调中:

writeWAVData("mySound.wav", mySampleBuffer, mySampleBufferSize, 44100, 1);

感谢任何提示/link/建议/形式的帮助。

您的用例与您在网上看到的代码之间的区别在于,在您的用例中,您事先不知道文件最终会持续多长时间,因为您不知道知道用户什么时候会按下停止按钮。

处理这个问题的方法是像往常一样先写出 WAV header,但现在不用担心为 file-size-specific 字段(即字段"RIFF" 之后和 "data" 之后的字段)。您现在可以将这些字段设置为零。

然后在收到音频样本时写出它们,即将它们附加到文件末尾。

最后,在用户按下停止键并且您即将关闭文件后,您需要返回并用正确的值覆盖这两个 header-fields。您现在可以执行此操作,因为此时您知道写入文件的音频数据字节数。完成后,该文件应该 well-formed 并且可用。你可以使用例如ofstream::seekp(fieldOffset, ios_base::beg) 为您需要修改的字段从文件顶部返回到适当的偏移量。