我希望能够一次播放多个声音。我使用多线程进行了尝试,但是发现它们仍然可以一个接一个地播放。有办法让他们同时玩吗?
static void Main(string[] args)
{
Console.WriteLine("Hello World");
Thread th = new Thread(playSound);
Thread th1 = new Thread(playSound1);
th.Start();
th1.Start();
}
public static void playSound()
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(@"c:\Users\Ben\Documents\c#\note_c.wav");
s1.Load();
s1.PlaySync();
}
public static void playSound1()
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(@"c:\Users\Ben\Documents\c#\note_e.wav");
s1.Load();
s1.PlaySync();
}
}
答案 0 :(得分:1)
如果我们安排并行执行怎么样? 像这样:
var files = new List<string>() {"note_1.wav", "note_2.wav"};
Parallel.ForEach(files, (currentFile) =>
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(currentFile);
s1.Load();
s1.PlaySync();
});
答案 1 :(得分:0)
尝试使用
[DllImport("winmm.dll")]
static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);
用法:
mciSendString(@"open path\to\your\file.wav type waveaudio alias anAliasForYourSound", null, 0, IntPtr.Zero);
mciSendString(@"play anAliasForYourSound", null, 0, IntPtr.Zero);
mciSendString(@"open path\to\your\anotherFile.wav type waveaudio alias anAliasForYourAnotherSound", null, 0, IntPtr.Zero);
mciSendString(@"play anAliasForYourAnotherSound", null, 0, IntPtr.Zero);
答案 2 :(得分:0)
您不能完全同时启动线程,但是在这种情况下,可以通过在启动线程之前加载声音来改善代码:
static void Main(string[] args)
{
System.Media.SoundPlayer s1 = new System.Media.SoundPlayer(
@"c:\Users\Ben\Documents\c#\note_c.wav");
s1.Load();
System.Media.SoundPlayer s2 = new System.Media.SoundPlayer(
@"c:\Users\Ben\Documents\c#\note_e.wav");
s2.Load();
Console.WriteLine("Hello World");
Thread th = new Thread(() => playSound(s1));
Thread th1 = new Thread(() => playSound(s2));
th.Start();
th1.Start();
}
public static void playSound(System.Media.SoundPlayer s)
{
s.PlaySync();
}
否则,您将需要实现一个同步系统。
答案 3 :(得分:0)
最好的方法是通过SharpDX使用DirectX xAudio2,您可以在这里找到它: https://github.com/sharpdx/SharpDX-Samples/tree/master/Desktop/XAudio2/PlaySound
它可以完美工作,但是要利用事件和任务而不是while循环和同步执行来使代码更好,并且能够动态加载xAudio2图以更改声音而无需重构,这将有些棘手整个图。
答案 4 :(得分:0)
添加这些Nuget软件包SharpDx 夏普DX媒体基金会 夏普Dx.Xaudio2 并使用下面的代码,它使用DirectX xAudio2并使用混音器构建图形,它也可以播放WAV 8和16。
@RunWith(SpringRunner.class)
@DataMongoTest
@Import(CustomConversionsConfiguration.class)
public class MyMongoTest { ... }
您可以根据需要使用多个SoundServices实例:
public class SoundServices : IDisposable
{
/// <summary>
/// Gets current sound file
/// </summary>
string SoundFile { get; }
/// <summary>
/// Gets current sound stream
/// </summary>
public Stream SoundStream { get; private set; }
/// <summary>
/// Gets/Sets looping option, sound will loop if set to true.
/// </summary>
public bool IsLooping { get; private set; }
/// <summary>
/// Holds the message of last error if any, check it if some feature fails
/// </summary>
public string LastErrorMsg { get; private set; }
//Play control flags
bool IsPlaying = false;
bool IsUserStop = false;
AutoResetEvent Playing;
float CurrentVolume = 1.0f;
bool IsInitialized = false;
SoundStream stream;
WaveFormat waveFormat;
AudioBuffer buffer;
SourceVoice sourceVoice;
XAudio2 xaudio2;
MasteringVoice masteringVoice;
/// <summary>
/// Initializes an instance by creating xAudio2 graph and preparing audio Buffers
/// </summary>
/// <param name="soundStream">WAV format sound stream</param>
/// <param name="loop">Bool indicating to loop sound playing or not</param>
public SoundServices(Stream soundStream, bool loop)
{
try
{
if (soundStream == null)
{
throw new ArgumentNullException("soundStream", "Null is not allowed, please specify a valid stream");
}
SoundStream = soundStream;
SoundFile = null;
IsLooping = loop;
//Playing = new ManualResetEvent(false);
Playing = new AutoResetEvent(false);
BuildxAudio2Graph();
}
catch (Exception e)
{
throw e;
}
}
#region Sound Play API
/// <summary>
/// Plays the sound stream loaded during initialization
/// </summary>
/// <returns>Task of sound playing</returns>
public Task PlaySound()
{
return Task.Factory.StartNew(() =>
{
PlayRepeatAsync();
});
}
/// <summary>
/// Task for starting play of sound buffers using xAudio2 graph
/// </summary>
void PlayRepeatAsync()
{
try
{
IsPlaying = true;
if (buffer == null)
{
//stream = new SoundStream(SoundStream);
//waveFormat = stream.Format;
buffer = new AudioBuffer
{
Stream = stream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
if (IsLooping)
buffer.LoopCount = AudioBuffer.LoopInfinite;
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
//Close the stream as it is now loaded in buffer already
//stream.Close();
}
sourceVoice.Start();
Playing.WaitOne();
sourceVoice.Stop();
IsPlaying = false;
sourceVoice.FlushSourceBuffers();
//xAudio2 graph creation step (5) send the AudioBuffer to sourceVoice
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
}
catch (Exception e)
{
LastErrorMsg = "PlayRepeatAsync(): "+ e.Message;
IsPlaying = false;
}
}
/// <summary>
/// Initializes xAudio2 graph to be used for sound playing
/// </summary>
void BuildxAudio2Graph()
{
try
{
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
//xAudio2 graph creation step (1) Create XAudio2 device
xaudio2 = new XAudio2();
//xAudio2 graph creation step (2) Create MasteringVoice and connect it to device
//*Note: You must use aMasteringVoice to connect to xAudioDevice
masteringVoice = new MasteringVoice(xaudio2);
//SetVolume(CurrentVolume);
//xAudio2 graph creation step (3) Prepare sourceVoice
sourceVoice = new SourceVoice(xaudio2, waveFormat, true);
// Adds a callback check buffer end and Looping option
sourceVoice.BufferEnd += SourceVoice_BufferEnd;
//xAudio2 graph creation step (5) send the AudioBuffer to sourceVoice
IsInitialized = true;
}
catch (Exception e)
{
LastErrorMsg = "BuildxAudio2Graph(): " + e.Message;
IsInitialized = false;
}
}
/// <summary>
/// Recreates source buffer allowing sound change or loop change
/// </summary>
void RecreateBuffer()
{
try
{
SoundStream.Seek(0, SeekOrigin.Begin);
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
//if (buffer == null)
{
//stream = new SoundStream(SoundStream);
//waveFormat = stream.Format;
buffer = new AudioBuffer
{
Stream = stream.ToDataStream(),
AudioBytes = (int)stream.Length,
Flags = SharpDX.XAudio2.BufferFlags.EndOfStream
};
if (IsLooping)
buffer.LoopCount = AudioBuffer.LoopInfinite;
sourceVoice.FlushSourceBuffers();
sourceVoice.SubmitSourceBuffer(buffer, stream.DecodedPacketsInfo);
//Close the stream as it is now loaded in buffer already
//stream.Close();
}
}
catch (Exception e)
{
LastErrorMsg = "RecreateBuffer(): " + e.Message;
}
}
/// <summary>
/// Changes current audio to a new one
/// </summary>
/// <param name="soundStream">a stream from wav file</param>
public void ChangeSoundTo(Stream soundStream, bool Loop)
{
try
{
IsLooping = Loop;
SoundStream = soundStream;
stream = new SoundStream(SoundStream);
waveFormat = stream.Format;
sourceVoice = new SourceVoice(xaudio2, waveFormat, true);
sourceVoice.BufferEnd += SourceVoice_BufferEnd;
RecreateBuffer();
}
catch (Exception e)
{
IsInitialized = false;
LastErrorMsg = "ChangeSoundTo(): " + e.Message;
}
}
/// <summary>
/// Set loop ot no loop
/// </summary>
/// <param name="loop">True = Loop forever, false = play till end</param>
public void SetLooping(bool loop)
{
if (IsPlaying)
Stop();
IsLooping = loop;
RecreateBuffer();
}
#endregion
/// <summary>
/// Immediately Stops currently playing sound
/// </summary>
public void Stop()
{
try
{
if (IsPlaying)
{
IsUserStop = true;
Playing.Set();
}
}
catch (Exception e)
{
LastErrorMsg = "Stop(): " + e.Message;
}
}
/// <summary>
/// Gets Current Volume
/// </summary>
/// <returns>Current volume</returns>
public float GetVolume()
{
float current = 0.0f;
try
{
if (sourceVoice == null || sourceVoice.IsDisposed) return CurrentVolume;
sourceVoice.GetVolume(out current);
}
catch (Exception e)
{
LastErrorMsg = "GetVolume(): " + e.Message;
}
return current;
}
/// <summary>
/// Sets the current volume
/// </summary>
/// <param name="newVolume">returns back the current setting for confirmation</param>
/// <returns>The current set volume</returns>
public float SetVolume(float newVolume)
{
try
{
if (newVolume > 1 || newVolume < 0) return GetVolume();
if (sourceVoice == null || sourceVoice.IsDisposed)
{
CurrentVolume = newVolume;
return newVolume;
}
sourceVoice.SetVolume(newVolume, 0);
return GetVolume();
}
catch (Exception e)
{
LastErrorMsg = "SetVolume(): " + e.Message;
return 0.0f;
}
}
/// <summary>
/// End of buffer event handler
/// </summary>
/// <param name="obj"></param>
private void SourceVoice_BufferEnd(IntPtr obj)
{
//Debug.WriteLine($"buffer end reached with looping {IsLooping}");
if (!IsLooping)
{
if (IsPlaying && !IsUserStop)
Playing.Set();
else if(IsUserStop)
{
IsUserStop = false;
}
}
}
public void Dispose()
{
if (sourceVoice != null && !sourceVoice.IsDisposed)
{
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
if (buffer != null && buffer.Stream != null)
buffer.Stream.Dispose();
if (masteringVoice != null && !masteringVoice.IsDisposed)
masteringVoice.Dispose();
if (xaudio2 != null && !xaudio2.IsDisposed)
xaudio2.Dispose();
}
~SoundServices()
{
if (sourceVoice != null && !sourceVoice.IsDisposed)
{
sourceVoice.DestroyVoice();
sourceVoice.Dispose();
}
if (buffer != null && buffer.Stream != null)
buffer.Stream.Dispose();
if (masteringVoice != null && !masteringVoice.IsDisposed)
masteringVoice.Dispose();
if (xaudio2 != null && !xaudio2.IsDisposed)
xaudio2.Dispose();
}
}