Reputation: 389
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.). 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. I want to play the two files in succession, seamlessly, first the original wav file with PlaySync() then the loop section with 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.
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).
Upvotes: 1
Views: 8728
Reputation: 11
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.
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:
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();
Upvotes: 1
Reputation: 416
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
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:
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?
Hope this helps.
Cheers!
Upvotes: 0
Reputation: 38367
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. 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. I have done something similar but dont have the code on hand and it might have been slightly different.
Also, is Play() blocking? I.e. 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. So you need to move .Play to another thread so that you can begin loading the next wave while the first wave is playing. 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. This will significantly reduce the pause.
Consider media palyers that have a playlist of MP3s. 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.
Upvotes: 0