Question

I need to play single sound repeatedly in my app, for example, a gunshot, using XAudio2.

This is the part of the code I wrote for that purpose:

public sealed class X2SoundPlayer : IDisposable
    {
        private readonly WaveStream _stream;
        private readonly AudioBuffer _buffer;
        private readonly SourceVoice _voice;

        public X2SoundPlayer(XAudio2 device, string pcmFile)
        {
            var fileStream = File.OpenRead(pcmFile);
            _stream = new WaveStream(fileStream);
            fileStream.Close();

            _buffer = new AudioBuffer
                          {
                              AudioData = _stream,
                              AudioBytes = (int) _stream.Length,
                              Flags = BufferFlags.EndOfStream

                          };

            _voice = new SourceVoice(device, _stream.Format);
        }

        public void Play()
        {
            _voice.SubmitSourceBuffer(_buffer);
            _voice.Start();
        }

        public void Dispose()
        {
            _stream.Close();
            _stream.Dispose();
            _buffer.Dispose();
            _voice.Dispose();
        }
    }

The code above is actually based on SlimDX sample.

What it does now is, when I call Play() repeatedly, the sound plays like:

sound -> sound -> sound

So it just fills the buffer and plays it.

But, I need to be able to play the same sound while the current one is playing, so effectively these two or more should mix and play at the same time.

Is there something here that I've missed, or it's not possible with my current solution (perhaps SubmixVoices could help)?

I'm trying to find something related in docs, but I've had no success, and there are not many examples online I could reference.

Thanks.

Was it helpful?

Solution

Although it's better option to use XACT for this purpose because it supports sound cues (exactly what I needed), I did managed to get it working this way.

I've changed the code so it would always create new SourceVoice object from the stream and play it.

        // ------ code piece 

        /// <summary>
        /// Gets the available voice.
        /// </summary>
        /// <returns>New SourceVoice object is always returned. </returns>
        private SourceVoice GetAvailableVoice()
        {
            return new SourceVoice(_player.GetDevice(), _stream.Format);
        }

        /// <summary>
        /// Plays this sound asynchronously.
        /// </summary>
        public void Play()
        {
            // get the next available voice
            var voice = GetAvailableVoice();
            if (voice != null)
            {
                // submit new buffer and start playing.
                voice.FlushSourceBuffers();
                voice.SubmitSourceBuffer(_buffer);

                voice.Start();
            }
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top