SoundPlayer 并播放无缝连续的声音

Posted

技术标签:

【中文标题】SoundPlayer 并播放无缝连续的声音【英文标题】:SoundPlayer and playing a seamless succession of sounds 【发布时间】:2012-08-23 23:25:45 【问题描述】:

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

不幸的是,在我 PlaySync() 第一个 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();
    

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

【问题讨论】:

【参考方案1】:

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

下载此WaveIO class,将其添加到您的项目中,并在您希望连续无缝播放多个声音的地方尝试以下代码:

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();

【讨论】:

【参考方案2】:

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

另外,Play() 是否阻塞? IE。下一行在完成播放之前不会运行。如果是这样,那么暂停是当第 3 行正在读取 wav 文件时。因此,您需要将 .Play 移动到另一个线程,以便您可以在播放第一波时开始加载下一波。即使您发现无法写入第一个内存流,并且必须创建一个新的内存流,至少您会将 wav 文件加载到内存流中,并在第一个完成后立即准备好播放。这将显着减少暂停。

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

【讨论】:

【参考方案3】:

这是我的测试的样子:

        string sMediaPath = @"C:\Windows\Media";
        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:\Windows\Media";
        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:\Users\Foogle\Desktop\";
        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 对象的集合并根据需要播放它们?

希望这会有所帮助。

干杯!

【讨论】:

我改变了我原来的帖子来准确描述我想要完成的事情。中断很快,瞬间,但在尝试执行我想要的循环机制时非常明显。我制作了两个单独的流,但仍然无法正常工作。 @giangurgolo 没问题,我已经编辑了我的答案并包含了另一个场景供您测试。

以上是关于SoundPlayer 并播放无缝连续的声音的主要内容,如果未能解决你的问题,请参考以下文章

使用 System.Media.SoundPlayer 播放 Windows 系统声音

SoundPlayer 不播放任何捆绑的 Windows 声音 PCM wav 文件

是否可以使用 SoundPlayer 背靠背播放 2 个声音?

使用 System.Media.SoundPlayer.PlaySync() 和 AxWindowsMediaPlayer 并行播放声音

无法在 Visual Studio 2010 c# 中使用 SoundPlayer 播放声音

C# 播放声音的方法?