您好 @电脑先生工作室 ,
感谢您的提问,也感谢您提供了完整的代码示例。
先说明一下大致情况:Windows 系统本身并不自带 Ogg/Vorbis 解码器,因此仅依靠系统原生组件来播放 .ogg 并不是平台开箱即用支持的做法。根据您后续打算如何分发这个项目,可以考虑以下几个方向。
为什么目前的做法只能停留在 .wav
System.Media.SoundPlayer 的文档说明它用于控制来自 .wav 文件的声音播放,并且只处理未压缩的 PCM。如果传入的流不是 PCM .wav,Play() 会引发 InvalidOperationException。这大概可以解释为什么 Ogg 数据无法传给它,压缩格式的 WAV(例如 ADPCM 或 GSM 6.10)也是同样的情况。可参阅 SoundPlayer 类 和 SoundPlayer.Play 方法。
Media Foundation 作为当前的原生媒体框架,其原生支持的格式列表中同样没有列出 Ogg 容器和 Vorbis。可参阅 Media Foundation 中支持的媒体格式 和 支持的编解码器。
1. 在机器上添加编解码器
Microsoft 在 Microsoft Store 上提供了 Web 媒体扩展 扩展包,它会为 Windows 增加 OGG 容器解析器以及 Vorbis/Theora 解码器。安装之后,Ogg 内容即可通过原生管线播放。需要权衡的是,这会成为依赖具体机器的前提条件,如果您打算分发这款游戏,这种方式可能不太实用。如果您走这条路并使用 MCI,请留意 MCI 目前已属于旧版 API,新代码建议改用 MediaPlayer。可参阅 MCI 命令字符串和消息。
2. 在应用程序内部解码为 PCM
托管的 Vorbis 解码器可以在内存中把 Ogg 流转换为 PCM,随后再把这个 PCM 流交给 SoundPlayer。这样所有依赖都包含在程序内部,不受最终用户系统配置的影响;对于需要对外分发的项目而言,通常是更可控的选择。这个社区讨论描述的正是这种做法,其中包括如何把解码器包装成 SoundPlayer 可以直接接受的流。
3. 使用专门的音频库
对于视觉小说引擎,您很可能还需要多音轨叠加播放、循环播放和音量控制,而这些 SoundPlayer 都不提供。NAudio 或许值得评估一下。
4. 直接使用 PCM WAV 分发
如果这些素材只是较短的语音或提示音,在构建阶段完成转换可以让代码保持简单,主要代价就是文件体积。
关于代码示例的一点观察
与格式问题无关,CreateInMemoryPlayer 先调用了十次 PlaySync(),然后才调用 Load() 并返回 player,而调用方又执行了一次 PlaySync(),因此每次调用实际会播放十一次。把"创建"与"播放"分开,并把 Load() 放在播放之前,应该更接近您想要的行为。另外 MemoryStream 没有被释放,由于 SoundPlayer 会持有该流的引用,它需要在 player 的整个生命周期内保持有效,并与 player 一同释放。
请告诉我哪个方向更符合您的项目情况,特别是这款游戏是否会分发到其他机器上,我很乐意进一步展开说明。
如果我的回复对您有帮助或有参考价值,恳请您按照此指南进行确认。
非常感谢。