如何使用waveOutWrite()使音频播放流畅

how to make audio playback smooth using waveOutWrite()

本文关键字:音频 播放 何使用 waveOutWrite      更新时间:2023-10-16

我在尝试使用waveOutWrite()实现平滑音频播放时遇到了一个问题。我的数据包括许多从相机获得的adpcmdata块,在解码每个adpcm块后,我使用waveOutWrite()播放它。第一个区块打得很成功(至少我能听到),但当我打下一个区块时,我遇到了问题,这些区块之间存在差距。我试着在使用waveOutWrite()后调用sleep(),但不好。有人能告诉我在这种情况下如何变得平滑吗?我播放音频的方式有问题吗?

for (i = 0, i < MaxBlockData, i++)  

        BYTE * pcmBuff = new BYTE[length*8];
        memset(pcmBuff, 0, length*8);
        G726 g726;
        int pcmDataSize = 0;
        g726.SetRate(g726.Rate32kBits);
        g726.SetLaw(g726.PCM16);
        pcmDataSize = g726.Decode(pcmBuff, adpcmData[i], 0, length*8); /decode adcmData PCM 16
        if(pcmDataSize > 0)
        {
            int sampleRate = 8000;
            CHAR* waveIn = new CHAR[pcmDataSize];
            HWAVEIN hWaveIn;
            WAVEHDR WaveInHdr;
            MMRESULT result;
            HWAVEOUT hWaveOut;
            WAVEFORMATEX pFormat;
            pFormat.wFormatTag = WAVE_FORMAT_PCM;
            pFormat.nChannels = 1;
            pFormat.nSamplesPerSec = sampleRate;
            pFormat.nAvgBytesPerSec = 2 * sampleRate;
            pFormat.nBlockAlign = 2;
            pFormat.wBitsPerSample = 16;
            pFormat.cbSize = 0;
            result = waveInOpen(&hWaveIn, WAVE_MAPPER, &pFormat, 0, 0, WAVE_FORMAT_DIRECT);
            if(result != MMSYSERR_NOERROR)
            {
                char fault[256];
                waveInGetErrorTextA(result, fault, 256);
                MessageBoxA(NULL, fault, "Failed to open waveform input device.", MB_OK | MB_ICONEXCLAMATION);
                return;
            }
            WaveInHdr.lpData = (LPSTR)waveIn;
            WaveInHdr.dwBufferLength = pcmDataSize;
            WaveInHdr.dwBytesRecorded = 0;
            WaveInHdr.dwUser = 0;
            WaveInHdr.dwFlags = 0;
            WaveInHdr.dwLoops = 0;
            waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
            memcpy(WaveInHdr.lpData, pcmBuff, pcmDataSize);
            if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &pFormat, 0, 0, WAVE_FORMAT_DIRECT))
            {
                MessageBoxA(NULL, "Failed to replay", NULL, MB_OK | MB_ICONEXCLAMATION );
            }
            waveOutWrite(hWaveOut, &WaveInHdr, sizeof(WaveInHdr)); 
            Sleep((pcmDataSize/sampleRate ) * 1000); //Sleep for as long as there was recorded
            waveOutUnprepareHeader(hWaveOut, &WaveInHdr, sizeof(WAVEHDR));
            waveInUnprepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
            waveInClose(hWaveIn);
            waveOutClose(hWaveOut);

            WaveInHdr.lpData = NULL;
            delete []waveIn;
        }
    }

谢谢你阅读我的问题。

我不会这样工作的
当您播放第一个样本时,您不能在下一个样本的时间内睡觉,相反,您应该使用双缓冲或多缓冲以及回调机制
总体协议如下:
1) 从相机或其他位置获取第一个块
2) 从相机或其他位置获取第二块
3) 在没有任何等待的情况下写入第一块然后写入第二块
然后创建等待来自回调的信号的循环,并在接收到信号时写入下一个捕获的块。

要使用waveOut*系列平稳播放音频,请打开设备,分配缓冲区并不断向设备发送缓冲区,以保留待播放的积压数据。在代码中使用Sleep的情况下,应该准备新数据并将其写入设备,同时检查播放的缓冲区(设置WHDR_DONE标志表示驱动程序不再使用缓冲区,应用程序将接收到缓冲区)。