波形音频-waveOutWrite发出起伏的声音 我试图创建一个C++程序,它将播放另一个程序提供的音频文件(原始音频数据,每个帧大约1920字节)(现在我只是通过读取文件作为音频文件来模拟)。通过修改源代码,我可以创建一个SoundPlayer类来完成这项工作,但是我得到的输出非常不稳定。更大的帧会更好,但即使是96000字节的帧,音频仍会每秒左右出现故障(我需要的帧也要比这小得多)

波形音频-waveOutWrite发出起伏的声音 我试图创建一个C++程序,它将播放另一个程序提供的音频文件(原始音频数据,每个帧大约1920字节)(现在我只是通过读取文件作为音频文件来模拟)。通过修改源代码,我可以创建一个SoundPlayer类来完成这项工作,但是我得到的输出非常不稳定。更大的帧会更好,但即使是96000字节的帧,音频仍会每秒左右出现故障(我需要的帧也要比这小得多),c++,audio,playback,waveform,C++,Audio,Playback,Waveform,如何解决此问题 是我正在使用的测试文件。下面是代码本身: #include <windows.h> #include <iostream> #pragma comment(lib, "Winmm.lib") constexpr int FRAME_SIZE_IN_BYTES = 1920; struct AudioFrame { char *Data; int DataSize; }; class SoundPlayer { public:

如何解决此问题

是我正在使用的测试文件。下面是代码本身:

#include <windows.h>
#include <iostream>
#pragma comment(lib, "Winmm.lib")

constexpr int FRAME_SIZE_IN_BYTES = 1920;

struct AudioFrame
{
    char *Data;
    int DataSize;
};

class SoundPlayer
{
public:

    SoundPlayer()
    {
        // Initialize the sound format we will request from sound card
        m_waveFormat.wFormatTag = WAVE_FORMAT_PCM;     // Uncompressed sound format
        m_waveFormat.nChannels = 1;                    // 1 = Mono, 2 = Stereo
        m_waveFormat.wBitsPerSample = 16;               // Bits per sample per channel
        m_waveFormat.nSamplesPerSec = 48000;           // Sample Per Second
        m_waveFormat.nBlockAlign = m_waveFormat.nChannels * m_waveFormat.wBitsPerSample / 8;
        m_waveFormat.nAvgBytesPerSec = m_waveFormat.nSamplesPerSec * m_waveFormat.nBlockAlign;
        m_waveFormat.cbSize = 0;
    }

    void Play(AudioFrame* af)
    {
        // Create our "Sound is Done" event
        m_done = CreateEvent(0, FALSE, FALSE, 0);

        // Open the audio device
        if (waveOutOpen(&m_waveOut, 0, &m_waveFormat, (DWORD)m_done, 0, CALLBACK_EVENT) != MMSYSERR_NOERROR)
        {
            std::cout << "Sound card cannot be opened." << std::endl;
            return;
        }

        // Create the wave header for our sound buffer
        m_waveHeader.lpData = af->Data;
        m_waveHeader.dwBufferLength = af->DataSize;
        m_waveHeader.dwFlags = 0;
        m_waveHeader.dwLoops = 0;

        // Prepare the header for playback on sound card
        if (waveOutPrepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
        {
            std::cout << "Error preparing Header!" << std::endl;
            return;
        }

        ResetEvent(m_done); // Reset our Event so it is non-signaled, it will be signaled again with buffer finished

        // Play the sound!
        if (waveOutWrite(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
        {
            std::cout << "Error writing to sound card!" << std::endl;
            return;
        }

        // Wait until sound finishes playing
        if (WaitForSingleObject(m_done, INFINITE) != WAIT_OBJECT_0)
        {
            std::cout << "Error waiting for sound to finish" << std::endl;
            return;
        }

        // Unprepare our wav header
        if (waveOutUnprepareHeader(m_waveOut, &m_waveHeader, sizeof(m_waveHeader)) != MMSYSERR_NOERROR)
        {
            std::cout << "Error unpreparing header!" << std::endl;
            return;
        }

        // Close the wav device
        if (waveOutClose(m_waveOut) != MMSYSERR_NOERROR)
        {
            std::cout << "Sound card cannot be closed!" << std::endl;
            return;
        }

        // Release our event handle
        CloseHandle(m_done);
    }



private:
    HWAVEOUT m_waveOut; // Handle to sound card output
    WAVEFORMATEX m_waveFormat; // The sound format
    WAVEHDR m_waveHeader; // WAVE header for our sound data
    HANDLE m_done; // Event Handle that tells us the sound has finished being played.
                   // This is a very efficient way to put the program to sleep
                   // while the sound card is processing the sound buffer

};

int main()
{
    FILE * fileDes;
    fopen_s(&fileDes, "Ducksauce.raw", "rb");
    if (fileDes == nullptr)
        std::cout << "File opening failed.\n";

    int bufferSize = FRAME_SIZE_IN_BYTES;
    char *buffer = new char[bufferSize];

    SoundPlayer sp;

    while (fread(buffer, sizeof(char), bufferSize, fileDes) > 0)
    {
        AudioFrame af;
        af.Data = buffer;
        af.DataSize = bufferSize;
        sp.Play(&af);
    }

    fclose(fileDes);
    delete[] buffer;
    return 0;
}
#包括
#包括
#pragma注释(lib,“Winmm.lib”)
constexpr int FRAME_SIZE_,单位为字节=1920;
结构音频帧
{
字符*数据;
int-DataSize;
};
类声音播放器
{
公众:
声音播放器()
{
//初始化我们将从声卡请求的声音格式
m_waveFormat.wFormatTag=WAVE_FORMAT_PCM;//未压缩的声音格式
m_waveFormat.nChannels=1;//1=单声道,2=立体声
m_waveFormat.wBitsPerSample=16;//每个通道的每个采样位数
m_waveFormat.nSamplesPerSec=48000;//每秒采样数
m_waveFormat.nblockallign=m_waveFormat.nChannels*m_waveFormat.wBitsPerSample/8;
m_waveFormat.nAvgBytesPerSec=m_waveFormat.nSamplesPerSec*m_waveFormat.nblockallign;
m_waveFormat.cbSize=0;
}
无效播放(音频帧*af)
{
//创建我们的“声音完成”活动
m_done=CreateEvent(0,FALSE,FALSE,0);
//打开音频设备
如果(waveOutOpen(&m_waveOut,0,&m_波形格式,(DWORD)m_done,0,回调事件)!=MMSYSERR\u NOERROR)
{
std::cout数据大小;
m_waveHeader.dwFlags=0;
m_waveHeader.dwLoops=0;
//准备要在声卡上播放的标题
if(WaveOutprepreHeader(m_waveOut,&m_waveHeader,sizeof(m_waveHeader))!=MMSYSERR\u NOERROR)
{

std::cout您应该在声音播放时从磁盘读取数据,而不是在缓冲区之间

如果无法一次读取整个文件,则应更改
Play
函数,使其不只是调用
WaitForSingleObject
。使用它会使代码阻塞并等待声音停止播放

您需要的是开始播放,然后返回阅读循环,准备下一个缓冲区,然后等待音乐结束,就像这样(在
SoundPlayer
):

然后回到
主循环中:

// Read first frame
fread(buffer, sizeof(char), bufferSize, fileDes);

while (true)
{
    AudioFrame af;
    af.Data = buffer;
    af.DataSize = bufferSize;

    // Start playing, but don't block
    sp.Play(&af);

    // Prepare the next chunk
    if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0) {
        break;

    // Now block the code, waiting with next chunk already loaded
    // and ready to be played in the next iteration.
    sp.WaitUntilFrameFinishes();
}
//读取第一帧
fread(buffer,sizeof(char),bufferSize,fileDes);
while(true)
{
音频帧自动对焦;
数据=缓冲区;
af.DataSize=缓冲区大小;
//开始玩,但不要阻挡
sp.Play&af;
//准备下一块

if(fread(buffer,sizeof(char),bufferSize,fileDes)在一天的努力之后,我仅仅根据我找到的文档就想知道如何进行音频播放。如果有人在尝试使用波形音频创建音频播放时发现了这个线程,这是一个非常好的参考点(肯定比我上面的错误代码好得多)


关于我的代码,我怀疑它不能正常工作,因为应该让AudioFrames队列始终至少使用几个帧,以防止出现声卡必须等待另一个AudioFrames的情况。

我尝试实现此解决方案,但我不知道是否正确,因为问题仍然存在。@Soonm当你的问题被它解决后,或者至少在它帮助你之后,你才应该接受答案。我需要构建完整的代码并尝试复制你的问题,因为这会解决问题。对此感到抱歉。经过一点实验,我发现在等待之前写3帧似乎可以解决问题。关于编辑:这是intere斯汀。如果你一直在等待音频结束,我想把3帧放进去应该没什么大不了的。很明显,还有一些事情我不知道。很高兴你已经解决了你的问题,但我会在一个舒适的时间深入了解这个问题。@BartekBanachewicz现在95%的情况下都是这样,但有时是这样几秒钟后它会变得起伏。可能与其他应用程序同时使用播放设备有关。
for (int i = 0; i < 3; i++ )
{
    fread(buffer, sizeof(char), bufferSize, fileDes);
    af.Data = buffer;
    af.DataSize = bufferSize;
    sp.StartPlaying(&af);
}
while (true)
{
    // Prepare the next chunk
    if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0)
        break;
    // Now block the code, waiting with next chunk already loaded
    // and ready to be played in the next iteration.
    sp.WaitUntilFrameFinishes();

    af.Data = buffer;
    af.DataSize = bufferSize;
    sp.StartPlaying(&af);
}
void WaitUntilFrameFinishes() {
    // Wait until sound finishes playing
    if (WaitForSingleObject(m_done, INFINITE) != WAIT_OBJECT_0)

    // ... move all the code from Play till the end here
}
// Read first frame
fread(buffer, sizeof(char), bufferSize, fileDes);

while (true)
{
    AudioFrame af;
    af.Data = buffer;
    af.DataSize = bufferSize;

    // Start playing, but don't block
    sp.Play(&af);

    // Prepare the next chunk
    if (fread(buffer, sizeof(char), bufferSize, fileDes) <= 0) {
        break;

    // Now block the code, waiting with next chunk already loaded
    // and ready to be played in the next iteration.
    sp.WaitUntilFrameFinishes();
}