【问题标题】:Play multiple sounds using SoundPlayer使用 SoundPlayer 播放多个声音
【发布时间】:2010-11-20 02:16:47
【问题描述】:

我正在制作一个采样器程序,其中从 1 到 9 的每个键都会发出不同的声音。 一切正常,但是当我同时按下两个(或更多)声音时,第二个“杀死”第一个。

我正在播放 .WAV 文件中的声音,使用 SoundPlayer。我该如何解决这个问题?

【问题讨论】:

    标签: c# .net audio wav


    【解决方案1】:

    您需要使用 DirectX (DirectSound) 或一些旨在允许同时播放多个声音的类似 API。

    【讨论】:

      【解决方案2】:

      我猜想在您的 KeyPress 事件(或您正在使用的任何东西)中,您正在使用构造函数创建一个新的 SoundPlayer 实例,该构造函数采用 WAV 文件的路径,然后调用它的 Play 方法。从理论上讲,这不应该导致您遇到的“单声道”效果,因为自 Windows 98 以来,Windows 已经能够同时播放多个 WAV 文件。我认为您所听到的(基于我自己对此类的使用)不是第二个开始时第一个声音的截止,而是实际上是由于从磁盘加载 WAV 文件时整体播放暂停而导致的故障。

      不要在每次按键时加载一个新的 SoundPlayer 实例,而是尝试创建一个类范围的 SoundPlayer 对象数组,并在表单的 Load 事件中从磁盘预加载它们。然后在按下键时调用每个 SoundPlayer 的 Play 方法。这可能会解决您的问题,尽管我认为您仍然会以这种方式偶尔出现故障。

      【讨论】:

        【解决方案3】:

        有一种简单的方法可以在 C# 或 VB.Net 中一次播放多个声音。您必须调用mciSendString() API 函数来播放每个 .wav 文件。你甚至不必做多线程,除非你在循环播放。 Here 是使用mciSendString() 创建的MusicPlayer 类的完整工作示例。

        // Sound api functions
        [DllImport("winmm.dll")]
        static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);
        

        在上面的函数中,关键是第一个参数命令。只要您使用单独的命令名称调用两个函数,它们就会分别/同时播放。这是我在我的一个 C# 程序中所做的:

        private void PlayWorker()
        {
            StringBuilder sb = new StringBuilder();
            mciSendString("open \"" + FileName + "\" alias " + this.TrackName, sb, 0, IntPtr.Zero);
            mciSendString("play " + this.TrackName, sb, 0, IntPtr.Zero);
            IsBeingPlayed = true;
        }
        

        编辑:添加了一个工作示例的链接。

        【讨论】:

        • 这有效,但前提是您每次都发送一个新的唯一曲目名称,这是设计使然吗?如果您尝试在以前使用的曲目名称上播放另一种声音(即使在第一个停止之后很久),它也会静音。
        • @Sire 这不应该发生。您确定在播放完成后发送“停止”命令和“关闭”命令吗?你可以参考我的整个 MusicPlayer 实现here。请特别注意 PlayWorker(),它在线程内调用以播放音频。
        • 感谢您提供完整的代码!我会将该链接添加到答案中。
        • @Prahlad Yeri:和父亲有同样的问题。声音只会播放一次。一旦声音结束,它应该能够自行停止。我不想跟踪它,即使我这样做了,我也不知道如何检查声音是否播放完毕。即使我知道,我也不希望程序在声音运行时被锁定在一个循环中。
        【解决方案4】:

        你可以这样做:

        SoundPlayer 支持 WAV 流。你可以

        • 混合您“手动”演奏的样本,并且,
        • 假的(从某处获取 WAV 标头,并不复杂)。

        并将这样的流作为参数提供给the SoundPlayer constructor

        这样您就不必使用某种复杂的 DirectSound 库,并且仍然可以进行混音(一次多个声音)。

        【讨论】:

          【解决方案5】:
          using System.Windows.Media
          
          Function void Play(string audioPath)
          {
          MediaPlayer myPlayer = new MediaPlayer();
          myPlayer.Open(new System.Uri(audioPath));
          myPlayer.Play();
          }
          
          Play(Application.StartupPath + "\\Track1.wav");
          Play(Application.StartupPath + "\\Track2.wav");
          

          此代码可以同时播放两个音频文件,第二个音频track2.wav的调用不会干扰track1.wav的播放。

          【讨论】:

          • 这是一个不错的解决方案。 2 个问题:1. 显然,Load 不存在于MediaPlayer 中。不过,没有它它仍然可以工作。 2. 在第一个之后添加另一个mPlayer.Play() 不会播放音频文件两次,而是一次 - 为什么?
          • SoundPlayer 中存在加载方法,应予以更正。其次,它不会两次播放音频文件,因为我们正在传递不同的音频文件。 Track1.wav,Track2.wav。
          • @Pransesh,让我澄清一下我的意图:我的意思是如果我们这样做:Function void Play(string audioPath) { ... myPlayer.Play(); myPlayer.Play(); } 那么 Play 将运行一次,而不是两次。为什么?
          • @HelterSkelter,媒体播放器库 Play() 方法将根据媒体的属性 NaturalDuration 读取媒体内容,持续时间结束将停止播放。所以它可以播放一次。
          • @Pransesh,谢谢。那么,我怎样才能让它连续播放两次呢?
          【解决方案6】:

          您需要通过 SharpDX 使用 xAudio2,它是一个专门用于游戏开发的 directX 组件,您可以在此处找到完整的工作示例: https://github.com/sharpdx/SharpDX-Samples/tree/master/Desktop/XAudio2/PlaySound

          【讨论】:

            猜你喜欢
            • 2014-04-01
            • 1970-01-01
            • 1970-01-01
            • 2023-04-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多