2

我正在玩一些 C#,我正在编写一个钢琴应用程序。

每当用户单击钢琴音符时,我都会将声音的位置 (.wav) 存储到列表中……以下是 button1_MouseDown 方法中的一些代码。

if (e.Button == MouseButtons.Left)
   {
       SoundPlayer sp = new SoundPlayer();
       string musName = Convert.ToString(mk.pitch);
       string loc = @"D:\OneDrive\Year 2 Semester 1\OOP\Notes-Sound files\Notes-Sound files\mapped\" + musName + ".wav";
       sp.SoundLocation = loc;
       sp.Play();
       music.Add(loc);
    }

现在,我想遍历循环以一次性播放所有单击的键。我这样做如下(当用户点击播放按钮时)

int k = 0;
for (k = 1; k < music.Count; k++)
{
   SoundPlayer sp = new SoundPlayer();
   sp.SoundLocation = music[k];
   sp.Play();
 }

问题是,每当单击播放按钮时,只会播放最后按下的音符。但是,当我调试时,不知何故,所有音符都会播放。有任何想法吗?

4

3 回答 3

5

根据MSDN,这是该Play方法的描述:

使用新线程播放 .wav 文件,如果尚未加载,则首先加载 .wav 文件。

因此,无论何时调用Play,它都会异步运行,并且您的循环会在当前文件完成之前继续执行播放下一个 wav 文件。调试时,您可能一直在等待,然后再继续循环。

相反,尝试使用PlaySync同步播放声音

PS。此外,您可能需要考虑使用SoundPlayer列表中的实例而不是文件名,以避免每次播放 wav 文件时创建新实例:

List<SoundPlayer> music = new List<SoundPlayer>();
//...

//In your first loop, you would add the SoundPlayer object
music.Add(sp);

//.. 
//Then when you're playing back:
for (int k = 0; k < music.Count; k++)
{
   music[k].PlaySync();
}

请注意,for循环中的索引也应从 0 开始

于 2016-11-30T09:39:36.730 回答
0

您可能需要Asynchronously使用LoadAsync如下方式播放声音:如何:在 Windows 窗体中异步加载声音

于 2016-11-30T09:46:15.720 回答
0

您的主要问题是所有音符都在播放,但随后的音符实际上在第一个音符完成之前开始播放。因此,您只听到最后一个。

使用PlaySync,它会同步播放声音,如果您由于某种原因必须遍历List<>并说,在播放之前对每个项目进行检查(好吧,至少如果您将 SoundPlayer 派生到另一个类以便它实际上有东西要检查),您可以对 PlaySync 调用使用检查。

SoundPlayer sp = new SoundPlayer();

foreach(var note in music)
{
    sp.SoundLocation = note;
    bool everythingIsFine = false;

    // Logic for everythingIsFine;

    if(everythingIsFine){
        sp.PlaySync(); 
    }
}
于 2016-11-30T09:59:02.717 回答