用ofstream写二进制数据的问题

时间:2011-02-11 18:45:49

标签: c++ audio binary wav 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;

}

如果此处有任何内容会导致错误数据附加到文件中,请告知我们。如果没有,我将三重检查输入数据(在回调中)。这个数据应该是好的,因为如果我将它复制到更大的缓冲区(例如,两分钟)然后保存它就可以了。

4 个答案:

答案 0 :(得分:2)

我只是想知道,

void CaptureApp::writeData()
{
    mPcmBufferPosition *= sizeof(int16_t); // mPcmBufferPosition = 0, so 0*2 = 0;

// (...)
    mPcmBufferPosition = 0;

}

工作(顺便说一句,sizeof int16_t总是2)。你在其他地方设置mPcmBufferPosition吗?

void CaptureApp::writeData()
{

    // Update header with new PCM length
    long pos = mFile.tellp();
    mPcmBufferBytesToWrite *= 2;
    mPcmTotalSize += mPcmBufferBytesToWrite;
    mFileHeader.bytes = mPcmTotalSize + sizeof(WAVFILEHEADER);
    mFileHeader.pcmbytes = mPcmTotalSize;

    mFile.seekp(0);
    mFile.write(reinterpret_cast<char *>(&mFileHeader), sizeof(mFileHeader));
    mFile.seekp(pos);

    // Append PCM data
    if (mPcmBufferBytesToWrite > 0)    
        mFile.write(reinterpret_cast<char *>(mPcmBuffer), mPcmBufferBytesToWrite);
}

同样mPcmBuffer是一个指针,所以不知道你为什么在写中使用&

答案 1 :(得分:1)

最可能的原因是你从指针的地址写入缓冲区,而不是缓冲区本身。放弃“&amp;”在最后的mFile.write中。 (如果你的缓冲区是在附近分配的,那么它可能会有一些很好的数据,你碰巧抓住了它的一大块,但这只是运气,你的写作需要重叠你的缓冲区)

一般情况下,如果您发现自己处于这种情况,您可以尝试考虑如何独立于录制代码测试此代码:设置一个值为0..255的缓冲区,并且然后将“块大小”设置为16,看它是否在16个独立的写操作中写出了连续的0..255序列。这将很快验证您的缓冲代码是否正常工作。

答案 2 :(得分:0)

我不会调试您的代码,但会尝试为您提供可以尝试检查的内容的清单,并确定错误的位置:

  • 总是有参考录音机或播放器方便。它可以像Windows Sound Recorder,Audacity或Adobe Audition一样简单。拥有一台能够正确录制和播放文件的录像机/播放器。
  • 使用您的应用记录文件并尝试使用参考播放器播放。工作?
  • 尝试使用参考录音机录制文件,并与播放器一起播放。工作?
  • 当您将SOUND数据写入刻录机中的WAV文件时,请将其写入一个额外的文件。使用播放器以RAW模式打开该文件(Windows Sound Recorder在这里是不够的)。它能正常播放吗?
  • 在播放器中播放文件并写入声卡时,将输出写入RAW文件,查看您是否正在正确播放数据,或者您是否有声卡问题。它能正常播放吗?

尝试所有这些,你会更好地了解哪里出了问题。

答案 3 :(得分:0)

拍摄,对不起 - 工作深夜,今天有点休息。我忘了向你们展示实际的回调。就是这样:

// Called when buffer is full
void CaptureApp::onData(float * data, int32_t & size)
{

    // Check recording flag and buffer size
    if (mRecording && size <= BUFFER_LENGTH)
    {

        // Save the PCM data to file and reset the array if we 
        // don't have room for this buffer
        if (mPcmBufferPosition + size >= mPcmBufferSize) 
            writeData();

        // Copy PCM data to file buffer
        copy(mAudioInput.getData(), mAudioInput.getData() + size, mPcmBuffer + mPcmBufferPosition);

        // Update PCM position
        mPcmBufferPosition += size;

    }

}

将尝试你们的建议和报告。