使用 ofstream 写入二进制数据时出现问题
大家好,我正在编写一个应用程序,它将麦克风输入记录到 WAV 文件中。以前,我编写了这个来填充指定大小的缓冲区,并且效果很好。现在,我希望能够录制任意长度。这就是我想要做的:
- 设置 32 个小型音频缓冲区(循环缓冲)
- 使用 ofstream 启动一个 WAV 文件 -- 将 PCM 长度设置为 0 的标头
- 添加一个缓冲区以输入
- 当缓冲区完成时,将其数据附加到WAV 文件并更新标题;回收缓冲区
- 当用户点击“停止”时,将剩余的缓冲区写入文件并关闭
它的工作原理是文件达到正确的长度(标头和文件大小并且是正确的)。然而,数据却非常不稳定。我可以看出我所说的内容——而且时间是正确的——但是有一个重复的扭曲块。听起来基本上只有一半的数据进入文件。
以下是代码使用的一些变量(在标头中)
// File writing
ofstream mFile;
WAVFILEHEADER mFileHeader;
int16_t * mPcmBuffer;
int32_t mPcmBufferPosition;
int32_t mPcmBufferSize;
uint32_t mPcmTotalSize;
bool mRecording;
以下是准备文件的代码:
// Start recording audio
void CaptureApp::startRecording()
{
// Set flag
mRecording = true;
// Set size values
mPcmBufferPosition = 0;
mPcmTotalSize = 0;
// Open file for streaming
mFile.open("c:\my.wav", ios::binary|ios::trunc);
}
以下是接收缓冲区的代码。这假设传入的数据是正确的——它应该是正确的,但我并没有排除它不正确的可能性。
// Append file buffer to output WAV
void CaptureApp::writeData()
{
// Update header with new PCM length
mPcmBufferPosition *= sizeof(int16_t);
mPcmTotalSize += mPcmBufferPosition;
mFileHeader.bytes = mPcmTotalSize + sizeof(WAVFILEHEADER);
mFileHeader.pcmbytes = mPcmTotalSize;
mFile.seekp(0);
mFile.write(reinterpret_cast<char *>(&mFileHeader), sizeof(mFileHeader));
// Append PCM data
if (mPcmBufferPosition > 0)
{
mFile.seekp(mPcmTotalSize - mPcmBufferPosition + sizeof(WAVFILEHEADER));
mFile.write(reinterpret_cast<char *>(&mPcmBuffer), mPcmBufferPosition);
}
// Reset file buffer position
mPcmBufferPosition = 0;
}
这是关闭文件的代码:
// Stop recording
void CaptureApp::stopRecording()
{
// Save remaining data
if (mPcmBufferSize > 0)
writeData();
// Close file
if (mFile.is_open())
{
mFile.flush();
mFile.close();
}
// Turn off recording flag
mRecording = false;
}
如果这里有任何内容看起来会导致错误数据附加到文件中,请告诉我。如果没有,我将三次检查输入数据(在回调中)。该数据应该很好,因为如果我将其复制到更大的缓冲区(例如,两分钟)然后将其保存出来,它就可以工作。
Hey all, I'm writing an application which records microphone input to a WAV file. Previously, I had written this to fill a buffer of a specified size and that worked fine. Now, I'd like to be able to record to an arbitrary length. Here's what I'm trying to do:
- Set up 32 small audio buffers (circular buffering)
- Start a WAV file with ofstream -- write the header with PCM length set to 0
- Add a buffer to input
- When a buffer completes, append its data to the WAV file and update the header; recycle the buffer
- When the user hits "stop", write the remaining buffers to file and close
It kind of works in that the files are coming out to the correct length (header and file size and are correct). However, the data is wonky as hell. I can make out a semblance of what I said -- and the timing is correct -- but there's this repetitive block of distortion. It basically sounds like only half the data is getting into the file.
Here are some variables the code uses (in header)
// File writing
ofstream mFile;
WAVFILEHEADER mFileHeader;
int16_t * mPcmBuffer;
int32_t mPcmBufferPosition;
int32_t mPcmBufferSize;
uint32_t mPcmTotalSize;
bool mRecording;
Here is the code that prepares the file:
// Start recording audio
void CaptureApp::startRecording()
{
// Set flag
mRecording = true;
// Set size values
mPcmBufferPosition = 0;
mPcmTotalSize = 0;
// Open file for streaming
mFile.open("c:\my.wav", ios::binary|ios::trunc);
}
Here's the code that receives the buffer. This assumes the incoming data is correct -- it should be, but I haven't ruled out that it isn't.
// Append file buffer to output WAV
void CaptureApp::writeData()
{
// Update header with new PCM length
mPcmBufferPosition *= sizeof(int16_t);
mPcmTotalSize += mPcmBufferPosition;
mFileHeader.bytes = mPcmTotalSize + sizeof(WAVFILEHEADER);
mFileHeader.pcmbytes = mPcmTotalSize;
mFile.seekp(0);
mFile.write(reinterpret_cast<char *>(&mFileHeader), sizeof(mFileHeader));
// Append PCM data
if (mPcmBufferPosition > 0)
{
mFile.seekp(mPcmTotalSize - mPcmBufferPosition + sizeof(WAVFILEHEADER));
mFile.write(reinterpret_cast<char *>(&mPcmBuffer), mPcmBufferPosition);
}
// Reset file buffer position
mPcmBufferPosition = 0;
}
And this is the code that closes the file:
// Stop recording
void CaptureApp::stopRecording()
{
// Save remaining data
if (mPcmBufferSize > 0)
writeData();
// Close file
if (mFile.is_open())
{
mFile.flush();
mFile.close();
}
// Turn off recording flag
mRecording = false;
}
If there's anything here that looks like it would result in bad data getting appended to the file, please let me know. If not, I'll triple check the input data (in the callback). This data should be good, because it works if I copy it to a larger buffer (eg, two minutes) and then save that out.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我只是想知道,如何
工作(顺便说一句。sizeof
int16_t
始终为 2)。您是否在其他地方设置 mPcmBufferPosition ?另外
mPcmBuffer
是一个指针,所以不知道为什么在 write 中使用&
。I am just wondering, how
works (btw. sizeof
int16_t
is always 2). Are you setting mPcmBufferPosition somewhere else?Also
mPcmBuffer
is a pointer, so don't know why you use&
in write.最可能的原因是您从缓冲区指针的地址写入,而不是从缓冲区本身写入。抛弃“&”在最后的mFile.write中。 (如果你的缓冲区分配在附近,并且你碰巧抓住了其中的一块,那么它可能有一些好的数据,但这只是运气,你的写入碰巧与缓冲区重叠)
一般来说,如果你发现自己处于这种情况,您可以尝试考虑如何独立于记录代码来测试此代码:设置一个包含值 0..255 的缓冲区,然后将“块大小”设置为 16 并查看它是否写出跨 16 个独立写入操作的 0..255 连续序列。这将快速验证您的缓冲代码是否正常工作。
The most likely reason is you're writing from the address of the pointer to your buffer, not from the buffer itself. Ditch the "&" in the final mFile.write. (It may have some good data in it if your buffer is allocated nearby and you happen to grab a chunk of it, but that's just luck that your write hapens to overlap your buffer)
In general, if you find yourself in this sort of situation, you could try to think how you can test this code in isolation from the recording code: Set up a buffer that has the values 0..255 in it, and then set your "chunk size" to 16 and see if it writes out a continuous sequence of 0..255 across 16 separate write operations. That will quickly verify if your buffering code is working or not.
我不会调试您的代码,但会尝试为您提供您可以尝试检查并确定错误所在的事项的清单:
尝试所有这些,您就会更好地了解哪里出了问题。
I won't debug your code, but will try to give you checklist of the things you can try to check and determine where's the error:
Try all this, and you'll have much better idea of where something went wrong.
好吧,抱歉——工作到很晚,今天有点休息。我忘了向你们展示实际的回调。就是这样:
将尝试你们的建议和报告。
Shoot, sorry -- had a late night of work and am a bit off today. I forgot to show y'all the actual callback. This is it:
Will try y'alls advice and report.