SoundPlayer,并播放无缝连续的声音



我想做的是播放一个循环的wav,但有一个特定的循环开始位置,就像音乐模块文件(.it、s3m.mod等)中使用的样本一样。SoundPlayer没有这个功能,所以我创建了两个独立的文件:原始的wav和开头被截断到循环开始位置的wav。我想连续播放这两个文件,无缝,首先用PlaySync()播放原始wav文件,然后用PlayLooping()播放循环部分。

不幸的是,在我播放Sync()第一个wav之后,它和PlayLooping()开始播放循环wav之间有一个的瞬间中断。

    private static void PlayThread(SoundPlayer soundPlayer, byte[] wav, byte[] loop)
    {
        MemoryStream stream1 = new MemoryStream(wav);
        MemoryStream stream2 = new MemoryStream(loop);
        soundPlayer.Stream = stream1;
        soundPlayer.PlaySync();
        // here is where the split second interruption occurs
        soundPlayer.Stream = stream2;
        soundPlayer.PlayLooping();
    }

当播放两个不同的声音时,这可能不明显,但当试图实现我想要的循环机制时,这是非常明显的。声波是乐器样本,非常小(通常不超过0x1000字节)。

与其尝试连续播放多个SoundPlayer对象,不如尝试动态连接.wav文件,并将合并后的.wav文件加载到一个SoundPlayer对象中。

下载这个WaveIO类,将其添加到您的项目中,并尝试以下代码,以便无缝地连续播放多个声音:

string[] files = new string[3] { @"filepath1.wav", @"filepath2.wav", @"filepath3.wav" };
WaveIO wa = new WaveIO();
wa.Merge(files, @"tempfile.wav");
System.Media.SoundPlayer sp = new System.Media.SoundPlayer(@"tempfile.wav");
sp.Play();

我对SoundPlayer一无所知,但也许可以去掉第3+4行,将第二波写入第一个流,而不是创建一个新的流。这样,你本质上是在向流中添加更多的数据供其播放。假设你写它的速度比播放它的速度快,这是你应该能够做到的。我不确定MemoryStream是否允许同时读/写。我做了一些类似的事情,但手头没有代码,可能略有不同。

另外,Play()正在阻塞吗?也就是说,下一条线在演奏完之前是不会跑的。如果是这样,那么暂停是在第3行读取wav文件时。所以你需要移动。播放到另一个线程,这样你就可以在播放第一波时开始加载下一波。即使你发现你无法写入第一个内存流,并且必须创建一个新的内存流,至少你会将wav文件加载到内存流中,并在第一个完成后立即准备播放。这将大大减少暂停时间。

考虑一下有MP3播放列表的媒体播放器。当一个MP3即将结束时,媒体播放器通常会继续从磁盘加载下一个MP3,并在第一个MP3播放完毕之前将其加载到内存中。

以下是我的测试结果:

        string sMediaPath = @"C:WindowsMedia";
        SoundPlayer soundPlayer = new SoundPlayer();
        soundPlayer.Stream = File.OpenRead(Path.Combine(sMediaPath, "chimes.wav"));
        soundPlayer.PlaySync();
        soundPlayer.Stream = File.OpenRead(Path.Combine(sMediaPath, "chord.wav"));
        soundPlayer.PlaySync();

我发现这个测试完全按照你的意愿运行——文件之间没有突然停止。不过,这可能是由于其他原因,最有可能与文件本身有关

  • 比特率:文件的采样率是多少
  • 声音文件是否交错(立体声)
  • 声音文件有多大

也许在播放之前预先加载你的声音可能会有所不同?

        string sMediaPath = @"C:WindowsMedia";
        SoundPlayer soundPlayer = new SoundPlayer();
        List<Stream> oSoundStreams = new List<Stream>();
        oSoundStreams.Add(File.OpenRead(Path.Combine(sMediaPath, "chimes.wav")));
        oSoundStreams.Add(File.OpenRead(Path.Combine(sMediaPath, "chord.wav")));
        soundPlayer.Stream = oSoundStreams[0];
        soundPlayer.PlaySync();
        soundPlayer.Stream = oSoundStreams[1];
        soundPlayer.PlaySync();

编辑:

通过为每个要播放的声音创建一个SoundPlayer对象,似乎可以减少您正在经历的短暂间隙:

        string sMediaPath = @"C:UsersFoogleDesktop";
        SoundPlayer soundPlayer1 = new SoundPlayer();
        SoundPlayer soundPlayer2 = new SoundPlayer();
        soundPlayer1.Stream = File.OpenRead(Path.Combine(sMediaPath, "W.wav"));
        soundPlayer1.Load();
        soundPlayer2.Stream = File.OpenRead(Path.Combine(sMediaPath, "P.wav"));
        soundPlayer2.Load();
        for (int i = 0; i < 10; i++)
        {
            soundPlayer1.PlaySync();
            soundPlayer2.PlaySync();
        }

也许您可以创建一个SoundPlayer对象的集合,并根据需要播放它们?

希望这能有所帮助。

干杯!

相关内容

  • 没有找到相关文章

最新更新