简体   繁体   English

SoundPlayer 并播放无缝连续的声音

[英]SoundPlayer and playing a seamless succession of sounds

What I'm trying to do is play a looping wav, but with a specific loop start position like the samples used in music module files (.it, s3m. .mod, etc.).我想要做的是播放循环 wav,但具有特定的循环开始位置,例如音乐模块文件(.it、s3m、.mod 等)中使用的样本。 SoundPlayer doesn't have this feature, so I created two separate files: the original wav and the wav with the beginning cut off to where the loop starts. SoundPlayer 没有这个功能,所以我创建了两个单独的文件:原始 wav 和开头截断到循环开始位置的 wav。 I want to play the two files in succession, seamlessly , first the original wav file with PlaySync() then the loop section with PlayLooping().我想无缝地连续播放这两个文件,首先使用 PlaySync() 播放原始 wav 文件,然后使用 PlayLooping() 播放循环部分。

Unfortunately after I PlaySync() the first wav, there's a split second interruption between it and when PlayLooping() begins to play back the loop wav.不幸的是在我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();
    }

This may not be noticeable when playing two separate distinct sounds, but is very noticeable when trying to pull off the looping mechanism I want.这在播放两个不同的声音时可能不会很明显,但在尝试实现我想要的循环机制时非常明显。 The sound wavs are instrument samples, very small (usually no more than 0x1000 bytes).声音 wavs 是乐器样本,非常小(通常不超过 0x1000 字节)。

Instead of attempting to play multiple SoundPlayer objects consecutively, try concatenating the .wav files on the fly, and loading the merged .wav file into one SoundPlayer object.不要尝试连续播放多个 SoundPlayer 对象,而是尝试动态连接 .wav 文件,并将合并的 .wav 文件加载到一个 SoundPlayer 对象中。

Download this WaveIO class , add it to your project, and try the following code where you want to seamlessly play multiple sounds in a row:下载此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();

I don't know anything about SoundPlayer, but perhaps eliminate lines 3+4 and instead write your second wave to the first stream instead of creating a new stream.我对 SoundPlayer 一无所知,但可能会消除第 3+4 行,而是将第二波写入第一个流而不是创建新流。 That way you are in essence adding more data to the stream for it to play.这样,您实质上是向流中添加更多数据以供其播放。 Assuming you can write to it faster than it can play it, which you should be able to.假设您可以比播放它更快地写入它,您应该能够做到。 I'm not sure off the top of my head if a MemoryStream will allow simultaneous read/write.我不确定 MemoryStream 是否允许同时读/写。 I have done something similar but dont have the code on hand and it might have been slightly different.我做过类似的事情,但手头没有代码,它可能略有不同。

Also, is Play() blocking?另外,Play() 是否阻塞? Ie does the next line not run until it is done playing.即下一行直到播放完毕才运行。 If so, then the pause is when line 3 is reading the wav file.如果是这样,那么暂停是在第 3 行读取 wav 文件时。 So you need to move .Play to another thread so that you can begin loading the next wave while the first wave is playing.因此,您需要将 .Play 移动到另一个线程,以便您可以在第一波播放时开始加载下一波。 Even if you find that you can't write to the first memory stream, and have to create a new memory stream, at least you will have the wav file loaded into the memory stream and ready to play as soon as the first finishes.即使您发现无法写入第一个内存流,并且必须创建一个新的内存流,但至少您会将 wav 文件加载到内存流中并准备在第一个完成后立即播放。 This will significantly reduce the pause.这将显着减少暂停。

Consider media palyers that have a playlist of MP3s.考虑具有 MP3 播放列表的媒体播放器。 When one MP3 is close to being finished, the media player usually will go ahead and load the next mp3 from disk and load it into memory before the first is finished playing.当一个 MP3 接近完成时,媒体播放器通常会继续从磁盘加载下一个 MP3,并在第一个播放完成之前将其加载到内存中。

Here's what my test looked like:这是我的测试的样子:

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

I found that this test worked exactly as you wanted - with no abrupt stops between the files.我发现这个测试完全符合您的要求 - 文件之间没有突然停止。 This could be due to other reasons though, most likely to do with the files themselves这可能是由于其他原因,最有可能与文件本身有关

  • Bit rate: what is the sampling rate of the file?比特率:文件的采样率是多少?
  • Is the sound file interleaved (stereo)?声音文件是否交错(立体声)?
  • How large is the sound file?声音文件有多大?

Perhaps preloading your sounds before playing them might make a difference?也许在播放之前预加载您的声音可能会有所不同?

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

Edit:编辑:

By creating one SoundPlayer object for each sound to be played, it seems possible to bring down the short gap you're experiencing:通过为每个要播放的声音创建一个 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();
        }

Perhaps you could create a collection of SoundPlayer objects and play them as required?也许您可以创建一组 SoundPlayer 对象并根据需要播放它们?

Hope this helps.希望这可以帮助。

Cheers!干杯!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM