是否可以使用 SoundPlayer 背靠背播放 2 个声音?

Posted

技术标签:

【中文标题】是否可以使用 SoundPlayer 背靠背播放 2 个声音?【英文标题】:Is it possible to play 2 sounds back to back using SoundPlayer? 【发布时间】:2014-12-11 13:55:01 【问题描述】:

我正在寻找一种异步播放多个声音的方法。

其实我有:

jouerSon("_" + nbre1);
jouerSon(operateur);
jouerSon("_" + nbre2);
jouerSon("equal");

public void jouerSon(String son)

    System.Media.SoundPlayer player = new SoundPlayer();
    player.Stream = Properties.Resources.ResourceManager.GetStream(son);
    // player.LoadAsync();
    player.Play();
    //Thread.Sleep(500);
    //player.Stop();
 

我想播放第一个声音,然后在程序仍然响应的时候播放第二个声音等等。

我设法一个接一个地播放每个声音,但只使用同步播放,这会阻止用户在播放所有声音之前做任何事情。

如果我尝试使用异步播放,则只会播放最后一个声音,而不是每个声音。

我四处寻找解决方案,但似乎找不到任何解决方案。有人可以帮我吗?

【问题讨论】:

查看此主题:***.com/questions/1285294/… 您应该可以使用 Windows Media Player 执行此操作,它比 SoundPlayer 更具可编程性。它有一个事件 PlayStateChange,您可以为其创建事件处理程序,然后您可以测试 WMPPlayState.wmppsStopped,如果是,则启动第二个声音。 msdn.microsoft.com/en-us/library/windows/desktop/…如果对这个建议感兴趣,我可以发布一些示例代码,请告诉我。 嗯,我是 C# 的初学者,理解 MediaPlayer 的工作原理有点困难。我查看了msdn.microsoft.com/fr-fr/library/…,但不明白 MediaPlayer 是否可以使用 .wav 文件,以及当我的第一个声音结束时是否可以使用 MediaEnded 事件启动新的 MediaPlayer?我会对它如何工作的示例非常感兴趣。 @abatishchev:我不认为这是另一个问题的重复。这个问题是针对一个接一个的声音,另一个问题是关于同时播放声音。 @RenniePet:有人投票结束这个问题作为一个重复。我同意。但结果我有一个“禁令锤”:) 【参考方案1】:

在不同的线程上播放它们:

    private void button1_Click(object sender, EventArgs e)
    
        // ...
        jouerSon(new String[]  "_" + nbre1, operateur, "_" + nbre2, "equal" );
        // ...
    

    public void jouerSon(String[] sons)
    
        Task t = new Task(() =>
        
            System.Media.SoundPlayer player = new System.Media.SoundPlayer();
            foreach (String son in sons)
            
                player.Stream = Properties.Resources.ResourceManager.GetStream(son);
                player.PlaySync();
                
        );
        t.Start();
    

或者可能是更具体的定制,例如:

    private void button1_Click(object sender, EventArgs e)
    
        // ...
        jouerSon(nbre1, operateur, nbre2);
        // ...
    

    public void jouerSon(string nbre1, string operateur, string nbre2)
    
        Task t = new Task(() =>
        
            System.Media.SoundPlayer player = new System.Media.SoundPlayer();
            player.Stream = Properties.Resources.ResourceManager.GetStream("_" + nbre1);
            player.PlaySync();
            player.Stream = Properties.Resources.ResourceManager.GetStream(operateur);
            player.PlaySync();
            player.Stream = Properties.Resources.ResourceManager.GetStream("_" + nbre2);
            player.PlaySync();
            player.Stream = Properties.Resources.ResourceManager.GetStream("equal");
            player.PlaySync();
        );
        t.Start();
    

【讨论】:

【参考方案2】:

好的,正如所承诺的,这里有一些关于如何使用 Windows Media Player 的示例代码。但是现在我看它,我可以看到它比我想象的要复杂得多——也许太复杂了?

此程序可用于播放声音文件 1 次、2 次、n 次或不定次数,直到调用程序调用 StopPlayer() 方法。修改它以播放第一个声音文件然后播放另一个声音文件应该相当容易。

using WMPLib;

using System;


namespace Merlinia.CommonClasses

   /// <summary>
   /// This class provides a very simple wrapper layer for the Microsoft Windows Media Player.
   /// 
   /// Remember to call Dispose() when the player is no longer needed. (Actually, this may not be 
   /// necessary.)
   /// </summary>
   public class MMediaPlayer : IDisposable
   
      #region Private variables

      // Reference to an Interop object for the COM object that interfaces with Microsoft Windows 
      //  Media Player
      private readonly WindowsMediaPlayer _windowsMediaPlayer = null;

      // Number of repeats left, negative = keep looping
      private int _repeatCount = -1;

      // Part of the IDisposable pattern
      private bool _isDisposed = false;

      #endregion Private variables


      #region Constructor

      /// <summary>
      /// Constructor.
      /// </summary>
      public MMediaPlayer()
      
         try
         
            // Instantiate the Windows Media Player Interop object 
            _windowsMediaPlayer = new WindowsMediaPlayer();

            // Hook up a couple of event handlers
            _windowsMediaPlayer.MediaError += WindowsMediaPlayer_MediaError;
            _windowsMediaPlayer.PlayStateChange += WindowsMediaPlayer_PlayStateChange;
         
         catch (Exception e)
         
            _cLog.Error(0x3ad3a52u, e);
         
      

      #endregion Constructor


      #region Public methods

      /// <summary>
      /// Method to start the media player playing a file.
      /// </summary>
      /// <param name="fileName">complete file name</param>
      /// <param name="repeatCount">zero = repeat indefinitely, else number of times to repeat</param>
      public void PlayMediaFile(string fileName, int repeatCount)
      
         if (_windowsMediaPlayer == null)
            return;

         _repeatCount = --repeatCount;  // Zero -> -1, 1 -> zero, etc.

         if (_windowsMediaPlayer.playState == WMPPlayState.wmppsPlaying)
            _windowsMediaPlayer.controls.stop();  // Probably unnecessary

         _windowsMediaPlayer.URL = fileName;
         _windowsMediaPlayer.controls.play();
      


      /// <summary>
      /// Method to stop the media player.
      /// </summary>
      public void StopPlayer()
      
         if (_windowsMediaPlayer == null)
            return;

         _repeatCount = 0;
         _windowsMediaPlayer.controls.stop();
      

      #endregion Public methods


      #region Private methods

      /// <summary>
      /// Event-handler method called by Windows Media Player when the media file can't be opened, 
      /// or some other error. This is logged, but otherwise ignored - the calling module is not 
      /// signaled in any way.
      /// </summary>
      private static void WindowsMediaPlayer_MediaError(object pMediaObject)
      
         _cLog.Error(0x3ad1d3bu);
      


      /// <summary>
      /// Event-handler method called by Windows Media Player when the "state" of the media player 
      /// changes. This is used to repeat the playing of the media for the specified number of 
      /// times, or maybe for an indeterminate number of times.
      /// </summary>
      private void WindowsMediaPlayer_PlayStateChange(int newState)
      
         if ((WMPPlayState)newState == WMPPlayState.wmppsStopped)
         
            if (_repeatCount != 0)
            
               _repeatCount--;
               _windowsMediaPlayer.controls.play();
            
         
      

      #endregion Private methods


      #region IDisposable stuff

      // This copied from here: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

      /// <summary>
      /// Method to implement IDisposable. Do not make this method virtual - a derived class should 
      /// not be able to override this method.
      /// </summary>
      public void Dispose()
      
         // Call the following method
         Dispose(true);

         // This object will be cleaned up by the Dispose() method below. Therefore, we call 
         //  GC.SuppressFinalize to take this object off the finalization queue and prevent 
         //  finalization code for this object from executing a second time.
         GC.SuppressFinalize(this);
      


      /// <summary>
      /// Dispose(bool disposing) executes in two distinct scenarios. If isDisposing equals true, 
      /// the method has been called directly or indirectly by a user's code. Managed and unmanaged 
      /// resources can be disposed. If isDisposing equals false, the method has been called by the 
      /// runtime from inside the finalizer and you should not reference other objects - only 
      /// unmanaged resources can be disposed.
      /// </summary>
      protected virtual void Dispose(bool isDisposing)
      
         // Check to see if Dispose() has already been called
         if (!_isDisposed)
         
            // If isDisposing equals true, dispose all managed and unmanaged resources
            if (isDisposing && _windowsMediaPlayer != null)
            
               // Close the media player. (This may not be necessary?)
               _windowsMediaPlayer.close();
            

            // Note disposing has been done
            _isDisposed = true;
         
      

      #endregion IDisposable stuff

   

忽略与日志记录有关的语句。

但要使其工作,您需要一个用于与 Windows Media Player 接口的 COM 对象的 Interop dll。不幸的是,如果您以前从未这样做过,这有点棘手。 Visual Studio 能够生成 Interop dll。或者,您可以尝试在 Internet 上找到一个。这就是我实际上所做的,我碰巧在这里找到了一个: http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/VisualStudio/HowToUseWindowsMediaPlayerToPlayAudioAndVideo

祝你好运,如果你尝试这样做并遇到问题,欢迎询问。

【讨论】:

还没有让我的程序与它一起工作,但我会尽力至少理解未来。谢谢你的时间

以上是关于是否可以使用 SoundPlayer 背靠背播放 2 个声音?的主要内容,如果未能解决你的问题,请参考以下文章

C# 使用 SoundPlayer 同时发出多个声音

使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音

在播放时从不同的线程停止 SoundPlayer

SoundPlayer 并播放无缝连续的声音

使用 c# wpf 从资源文件播放声音

使用 NAudio 转换为 WAV 后使用 SoundPlayer 播放 MP3