15

I'm making a sampler program where each key from 1 to 9 will make a different sound. Everything works fine, but when I press two (or more) sounds at the same time, the second one "kills" the first one.

I'm playing the sounds from .WAV files, using SoundPlayer. How can I solve this?

Sam
  • 7,252
  • 16
  • 46
  • 65

6 Answers6

8

You'll need to use DirectX (DirectSound) or some similar API that is designed to allow the playing of multiple sounds at the same time.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
7

There is one simple way to play multiple sounds at once in C# or VB.Net. You will have to call the mciSendString() API Function to play each .wav file. You won't even have to do multi-threading, unless you are loop-playing. Here is a complete working example of a MusicPlayer class created using mciSendString().

// Sound api functions
[DllImport("winmm.dll")]
static extern Int32 mciSendString(string command, StringBuilder buffer, int bufferSize, IntPtr hwndCallback);

In the above function, the key is first parameter command. As long as you call two functions with a separate command name, they will play separately/simultaneously. This is what I did in one of my C# programs:

private void PlayWorker()
{
    StringBuilder sb = new StringBuilder();
    mciSendString("open \"" + FileName + "\" alias " + this.TrackName, sb, 0, IntPtr.Zero);
    mciSendString("play " + this.TrackName, sb, 0, IntPtr.Zero);
    IsBeingPlayed = true;
}

EDIT: Added link to a working example.

Prahlad Yeri
  • 3,567
  • 4
  • 25
  • 55
  • This works but only if you send in a NEW unique track name every time, is this by design? If you try to play another sound on a previously used trackname (even long after the first one stopped), it's silent. – Sire Feb 17 '15 at 09:25
  • @Sire That should not happen. Are you sure you are sending the "stop" command followed by "close" command after playing is complete? You can refer to my entire MusicPlayer implementation [here](http://pastebin.com/TtrCdeER). Pay special attention to PlayWorker() which is called inside a thread for playing an audio. – Prahlad Yeri Feb 17 '15 at 10:30
  • Thanks for the complete code! I would add that link to the answer. – Sire Feb 17 '15 at 10:51
  • @ Prahlad Yeri: Having the same problem as sire. The sound will only play once. It should be able to stop itself once the sound has finished. I don't want to keep track of that, and even if I did, I would not know how to check if the sound was finished playing. And even if I did know, I would not want the program being locked in a loop while the sound is running. – Dan W Jan 21 '18 at 20:33
4
using System.Windows.Media

Function void Play(string audioPath)
{
MediaPlayer myPlayer = new MediaPlayer();
myPlayer.Open(new System.Uri(audioPath));
myPlayer.Play();
}

Play(Application.StartupPath + "\\Track1.wav");
Play(Application.StartupPath + "\\Track2.wav");

This code could play two audio files simultaneously, the call in second audio track2.wav will not disturb the play of track1.wav .

Safa
  • 178
  • 1
  • 12
Pranesh Janarthanan
  • 1,134
  • 17
  • 26
  • 1
    that's a nice solution. 2 questions: 1. apparently, `Load` doesn't exist within `MediaPlayer`. It still works without it, though. 2. Adding another `mPlayer.Play()` right after the first one won't play the audio file twice, but once - why? – OfirD Sep 14 '16 at 12:46
  • Load method is present in SoundPlayer, it shall be corrected. Second, it wont play the the audio file twice because we are passing different audio files. Track1.wav, Track2.wav. – Pranesh Janarthanan Sep 15 '16 at 14:45
  • @Pransesh, let me clarify my intention: What I meant is that if we do: `Function void Play(string audioPath) { ... myPlayer.Play(); myPlayer.Play(); }` then Play will run once, instead of twice. Why? – OfirD Sep 15 '16 at 15:05
  • @HelterSkelter, Media player library Play() method will read media content based on property NaturalDuration of the media, end of duration will stop play. So it can play once. – Pranesh Janarthanan Sep 18 '16 at 11:19
  • @Pransesh, thanks. Well, how, then, can I make it play twice in a row? – OfirD Sep 18 '16 at 11:56
  • @Helter, then u need to use thread concept and do while condition, get the duration of media. put the thread under sleep for the specified duration. check the while condition to play twice. make sure all these process called under a seperate thread so that your other process wont hang up. – Pranesh Janarthanan Sep 19 '16 at 12:43
4

You could do this:

SoundPlayer supports WAV Stream. You could

  • MIX samples you play 'by-hand' and,
  • Fake (get the WAV header from somewhere, it's not complicated).

And provide such stream as a parameter to the SoundPlayer constructor.

That way you won't have to use somehow complicated DirectSound libraries, and still have mixing (multiple sounds at once).

Sam
  • 7,252
  • 16
  • 46
  • 65
Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
1

I'm guessing that in your KeyPress event (or whatever you're using) you're creating a new instance of SoundPlayer using the constructor that takes a path to the WAV file, and then calling its Play method. In theory this shouldn't cause the "mono" effect that you're encountering, since Windows has been capable of playing multiple WAV files simultaneously since Windows 98. What I think you're hearing (based on my own use of this class) is not a cutoff of the first sound when the second starts, but actually a glitch that results from overall playback pausing as the WAV file is loaded from disk.

Instead of loading up a new instance of SoundPlayer on each key press, try creating an array of class-scoped SoundPlayer objects and pre-loading them from disk in your form's Load event. Then just call each SoundPlayer's Play method when the key is pressed. This may fix your problem, although I think you will still get occasional glitches this way.

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
0

you need to use xAudio2 via SharpDX , it is a directX component dedicated for game development , you can find a full working sample here: https://github.com/sharpdx/SharpDX-Samples/tree/master/Desktop/XAudio2/PlaySound