问题
I'm looking for a way to play multiples sound back to back asynchronously.
I actually have :
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();
}
I'd like to play the first sound, then when it's over the second one etc all while the program is still responsive.
I managed to play each sound one after another but only using a synchronous play, which prevent the user from doing anything until all sound are played.
And if I try using with an asynchronous play, only the last sound is played instead of each one.
I've looked around for a solution, but can't seem to find any. Could someone help me?
回答1:
Play them on a different thread:
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();
}
Or possibly something more specifically tailored, like this:
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:
OK, as promised, here is some sample code for how to use Windows Media Player. But now that I look at it, I can see that it is quite a bit more complicated than I thought - maybe too complicated?
This program can be used to play a sound file 1 time, or 2 times, or n times, or an indeterminate number of times, until the calling program calls the StopPlayer() method. It should be fairly easy to modify it to play first one sound file and then another one.
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
}
}
Ignore the statements that have to do with logging.
But for this to work you need an Interop dll for the COM object that interfaces with Windows Media Player. This is unfortunately a bit tricky if you've never done this before. Visual Studio is able to generate an Interop dll. Alternatively you can try to find one on the Internet. That's what I did in fact, I happened to find one here: http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/VisualStudio/HowToUseWindowsMediaPlayerToPlayAudioAndVideo
Good luck, and you're welcome to ask if you try to do this and run into problems.
来源:https://stackoverflow.com/questions/27424538/is-it-possible-to-play-2-sounds-back-to-back-using-soundplayer