我正在使用 Win32 MultiMedia 函数 PlaySound 从我的应用程序中播放声音。
我希望能够在 不 修改系统音量级别的情况下动态调整正在播放的声音的音量。
我能找到的关于通过 PlaySound 播放声音音量的唯一建议是使用 waveOutSetVolume ,但是该函数设置系统范围的音量级别(不是我想要的)。
原文由 David Citron 发布,翻译遵循 CC BY-SA 4.0 许可协议
我正在使用 Win32 MultiMedia 函数 PlaySound 从我的应用程序中播放声音。
我希望能够在 不 修改系统音量级别的情况下动态调整正在播放的声音的音量。
我能找到的关于通过 PlaySound 播放声音音量的唯一建议是使用 waveOutSetVolume ,但是该函数设置系统范围的音量级别(不是我想要的)。
原文由 David Citron 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答843 阅读✓ 已解决
1 回答2.2k 阅读
1 回答822 阅读✓ 已解决
2 回答1.1k 阅读
1 回答1.2k 阅读
1 回答709 阅读
1 回答776 阅读
两种可能的解决方案:
首先,如果您的目标是 Vista 及更高版本,您可以使用新的 Windows 音频 API 来调整每个应用程序的音量。 ISimpleAudioVolume、IAudioEndpointVolume 等…
如果这不合适,可以将 WAV 文件直接加载到内存中并就地修改样本。尝试这个:
将 WAV 文件从磁盘读取到内存缓冲区,然后按比例缩小样本。我将假设有问题的 WAV 文件是带有未压缩 (PCM) 样本的 16 位立体声。立体声或单声道。如果不是,那么大部分内容都会消失。
我将把 WAV 文件字节读取到内存中作为练习留给读者:但是让我们从以下代码开始,其中“ReadWavFileIntoMemory”是您自己的函数。
此时,对 pFileBytes 的检查将如下所示:
这是 WAV 文件头。 “数据”是音频样本块的开始。
查找“数据”部分,并将“数据”后面的 4 个字节读入 DWORD。这是包含音频样本的“数据”块的大小。样本数(假设 PCM 16 位是这个数除以 2)。
现在,我们将创建一个指向内存缓冲区中第一个真实样本的样本指针:
pSample 指向 WAV 文件中的第一个 16 位样本。因此,我们已准备好将音频样本缩放到适当的音量级别。假设我们的音量范围在 0.0 和 1.0 之间。其中 0.0 是完全静音。而1.0是正常的全音量。现在我们只需将每个样本乘以目标体积:
此时,您已准备好使用 PlaySound 播放内存中的 WAV 文件:
那应该这样做。如果您打算使用 SND_ASYNC 标志使上述调用成为非阻塞的,那么您将无法释放内存缓冲区,直到它完成播放。所以要小心。
至于WAV文件头的解析。我通过声明一个名为“FindDataChunk”的假设函数来摆脱这种情况。您可能应该投资于编写适当的 WAV 文件头解析器,而不是仅仅寻找您第一次在头中遇到“数据”的位置。为了简洁起见,我省略了通常的错误检查。因此,上面的代码可能需要解决一些安全问题——尤其是涉及到遍历内存缓冲区并写入其中时。