0

大家好,我正在编写一个将麦克风输入记录到 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

4 回答 4

2

我只是想知道,如何

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

// (...)
    mPcmBufferPosition = 0;

}

有效(顺便说一句。sizeofint16_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一个指针,所以不知道你为什么&在write中使用。

于 2011-02-11T19:16:14.773 回答
1

最可能的原因是您正在从指向缓冲区的指针地址写入,而不是从缓冲区本身。在最终的 mFile.write 中去掉“&”。(如果您的缓冲区分配在附近并且您碰巧抓住了其中的一大块,它可能有一些很好的数据,但幸运的是您的写入与您的缓冲区重叠)

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

于 2011-02-11T19:20:37.350 回答
0

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

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

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

于 2011-02-11T19:22:17.840 回答
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;

    }

}

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

于 2011-02-11T20:04:36.273 回答