使用SoundPlayer播放多个声音

17

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

我使用SoundPlayer从.WAV文件播放声音。我该如何解决这个问题?

6个回答

8

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


7

在C#或VB.Net中同时播放多个声音的简单方法是调用mciSendString() API函数以播放每个.wav文件。除非你是循环播放,否则你甚至不需要进行多线程处理。 这里是一个完整的MusicPlayer类示例,使用mciSendString()创建。

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

在上述函数中,关键字是第一个参数command。只要使用不同的命令名称调用两个函数,它们就会分别/同时执行。这是我在我的一个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
@Sire,那不应该发生。您确定在播放完成后发送了“停止”命令,然后是“关闭”命令吗?您可以参考我的整个MusicPlayer实现此处。特别注意PlayWorker(),它在线程内被调用以播放音频。 - Prahlad Yeri
感谢提供完整的代码!我会将链接添加到答案中。 - Sire
@ Prahlad Yeri: 我遇到了与sire相同的问题。声音只会播放一次。它应该能够在声音播放完毕后自动停止。我不想跟踪它,即使我想,我也不知道如何检查声音是否已经播放完毕。而且即使我知道,我也不希望程序在声音正在运行时被锁在一个循环中。 - Dan W

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 的播放。


1
这是一个不错的解决方案。有两个问题:1. 显然,在 MediaPlayer 中不存在 Load。但即使没有它,它仍然可以正常工作。2. 在第一个 mPlayer.Play() 后添加另一个 mPlayer.Play() 不会播放音频文件两次,而是一次 - 为什么? - OfirD
Load方法存在于SoundPlayer中,应进行更正。其次,它不会播放音频文件两次,因为我们传递了不同的音频文件。Track1.wav,Track2.wav。 - Pranesh Janarthanan
@Pransesh,让我澄清一下我的意图:我的意思是,如果我们这样做:Function void Play(string audioPath) { ... myPlayer.Play(); myPlayer.Play(); } 那么Play只会运行一次,而不是两次。为什么? - OfirD
@HelterSkelter,媒体播放库的Play()方法将根据媒体的属性NaturalDuration读取媒体内容,结束时间将停止播放。因此,它只能播放一次。 - Pranesh Janarthanan
@Pransesh,谢谢。那么,我该如何让它连续播放两次呢? - OfirD
@Helter,那么您需要使用线程概念和do while条件,获取媒体的持续时间。将线程置于指定持续时间的休眠状态。检查while条件以播放两次。确保所有这些过程都在单独的线程下调用,以便您的其他进程不会挂起。 - Pranesh Janarthanan

4
你可以这样做: SoundPlayer 支持WAV流。你可以:
- 手动混合你播放的样本 - 模仿(从某处获取WAV头,这并不复杂)。
然后将此类流作为参数提供给 SoundPlayer 构造函数
这样你就不需要使用一些复杂的DirectSound库,仍然可以进行混音(多个声音同时)。

1
我猜测在你的KeyPress事件(或者你使用的其他事件)中,你正在使用SoundPlayer类的构造函数创建一个新的实例,并调用它的Play方法来播放WAV文件。理论上,这不应该导致你遇到的“单声道”效果,因为自Windows 98以来,Windows已经能够同时播放多个WAV文件。根据我自己使用这个类的经验,我认为你听到的不是第二个声音开始时第一个声音被截断,而是由于从磁盘加载WAV文件时整体播放暂停而导致的故障。
尝试在每次按键时不要加载新的SoundPlayer实例,而是在窗体的Load事件中创建一个类范围的SoundPlayer对象数组,并从磁盘预加载它们。然后只需在按键时调用每个SoundPlayer的Play方法即可。这可能会解决你的问题,但我认为你仍然会偶尔遇到故障。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接