You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段Windows C++简易音频代码无法发声?

Windows C++ 音频播放静音问题排查与修复

核心问题分析

  • 未指定音频格式:waveOutOpen调用时第三个参数传了NULL,Windows音频设备无法识别生成的PCM样本格式(单声道、16位、44100Hz),导致无法正确解码播放。
  • 循环等待逻辑错误:原代码的循环条件运算符优先级错误,&的优先级低于!=,导致判断逻辑失效,可能程序还没完成播放就进入清理步骤。
  • 缺少错误检测:未对音频API调用的返回值做检查,无法定位潜在的调用失败问题。

修复后的代码

#include <iostream>
#include <cmath>
#include <windows.h>
#include <mmsystem.h>

// 采样率
const int SAMPLE_RATE = 44100;
// 正弦波频率
const int FREQUENCY = 440;

int main()
{
    // 定义音频格式:单声道、16位、44100Hz
    WAVEFORMATEX wfx = {0};
    wfx.wFormatTag = WAVE_FORMAT_PCM;
    wfx.nChannels = 1;
    wfx.nSamplesPerSec = SAMPLE_RATE;
    wfx.wBitsPerSample = 16;
    wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;

    // 打开音频设备,传入格式参数
    HWAVEOUT hWaveOut = NULL;
    MMRESULT result = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
    if (result != MMSYSERR_NOERROR) {
        std::cerr << "waveOutOpen 失败,错误码:" << result << std::endl;
        return 1;
    }

    WAVEHDR waveHdr;
    memset(&waveHdr, 0, sizeof(waveHdr));

    const int BUFFER_SIZE = SAMPLE_RATE * sizeof(short);
    short* samples = (short*)malloc(BUFFER_SIZE);
    if (!samples) {
        std::cerr << "内存分配失败" << std::endl;
        waveOutClose(hWaveOut);
        return 1;
    }

    // 生成正弦波样本
    for (int i = 0; i < SAMPLE_RATE; ++i) {
        float t = static_cast<float>(i) / SAMPLE_RATE;
        float sample = sin(2 * M_PI * FREQUENCY * t);
        samples[i] = static_cast<short>(sample * 32767);
    }

    waveHdr.lpData = reinterpret_cast<LPSTR>(samples);
    waveHdr.dwBufferLength = BUFFER_SIZE;

    // 准备头部,检查错误
    result = waveOutPrepareHeader(hWaveOut, &waveHdr, sizeof(waveHdr));
    if (result != MMSYSERR_NOERROR) {
        std::cerr << "waveOutPrepareHeader 失败,错误码:" << result << std::endl;
        free(samples);
        waveOutClose(hWaveOut);
        return 1;
    }

    // 写入音频数据,检查错误
    result = waveOutWrite(hWaveOut, &waveHdr, sizeof(waveHdr));
    if (result != MMSYSERR_NOERROR) {
        std::cerr << "waveOutWrite 失败,错误码:" << result << std::endl;
        waveOutUnprepareHeader(hWaveOut, &waveHdr, sizeof(waveHdr));
        free(samples);
        waveOutClose(hWaveOut);
        return 1;
    }

    // 修正循环等待逻辑,添加延迟避免占用CPU
    while (!(waveHdr.dwFlags & WHDR_DONE)) {
        Sleep(10);
    }

    // 资源清理
    waveOutUnprepareHeader(hWaveOut, &waveHdr, sizeof(waveHdr));
    waveOutClose(hWaveOut);
    free(samples);

    return 0;
}

关键修复点说明

  • 添加WAVEFORMATEX结构:明确告诉音频设备样本的格式参数,确保设备能正确解码播放PCM数据。
  • 修正循环条件:调整运算符优先级,并添加Sleep(10)减少CPU占用,避免空循环导致高负载。
  • 增加错误检查:对每个音频API调用的返回值进行校验,方便快速定位调用失败的原因。

内容的提问来源于stack exchange,提问作者Henry Stone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:01:19