How to play audio from a real-time stream

hossein picture hossein · Aug 19, 2009 · Viewed 11.8k times · Source

I have a program which produces audio signals which supposed to be played simultaneously. For this, I play an interval of 100 ms of audio stream in each 100 ms period. But I have undesired signals in beginning and ending of each 100 ms audio stream (because of DC) so that the output sound is not smooth even the value of signals is the same. My code is attached bellow. Please help me what I should do to have a correct real-time audio.

using System;
using System.Windows.Forms;
using Microsoft.DirectX.DirectSound;
using System.IO;

namespace TestSound
{
    class CSound : Form
    {
        const int HEADER_SIZE = 44;
        const bool FLAG_STEREO = true;
        const short BITS_PER_SAMPLE = 16;
        const int SAMPLE_RATE = 44100;

        int numberOfSamples;
        MemoryStream stream;
        BinaryWriter writer;
        Device ApplicationDevice = null;
        SecondaryBuffer buffer = null;
        BufferDescription description;

        public CSound()
        {
            try
            {
                ApplicationDevice = new Device();
            }
            catch
            {
                MessageBox.Show("Unable to create sound device.");
                ApplicationDevice = null;
                return;
            }
            ApplicationDevice.SetCooperativeLevel(this, CooperativeLevel.Priority);
            description = new BufferDescription();
            description.ControlEffects = false;
            stream = new MemoryStream();
            writer = new BinaryWriter(stream);
        }

        private void AddHeader()
        {
            stream.Position = 0;

            writer.Write(0x46464952); // "RIFF" in ASCII
            writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1) / 8)) - 8);
            writer.Write(0x45564157); // "WAVE" in ASCII
            writer.Write(0x20746d66); // "fmt " in ASCII
            writer.Write(16);
            writer.Write((short)1);
            writer.Write((short)(FLAG_STEREO ? 2 : 1));
            writer.Write(SAMPLE_RATE);
            writer.Write(SAMPLE_RATE * (FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE / 8);
            writer.Write((short)((FLAG_STEREO ? 2 : 1) * BITS_PER_SAMPLE / 8));
            writer.Write(BITS_PER_SAMPLE);
            writer.Write(0x61746164); // "data" in ASCII
            writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * (FLAG_STEREO ? 2 : 1) / 8));
        }

        public void Play(short[] samples)
        {
            if (ApplicationDevice == null)
                return;

            stream.Position = HEADER_SIZE;
            numberOfSamples = samples.Length;
            for (int i = 0; i < numberOfSamples; i++)
            {
                writer.Write(samples[i]);
                if (FLAG_STEREO)
                    writer.Write(samples[i]);
            }
            AddHeader();
            stream.Position = 0;

            try
            {
                if (buffer != null)
                {
                    buffer.Dispose();
                    buffer = null;
                }
                buffer = new SecondaryBuffer(stream, description, ApplicationDevice);
                buffer.Play(0, BufferPlayFlags.Default);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        static short[] samples = new short[4410]; // 100 ms
        static CSound sound;

        static void Main()
        {
            Form form = new Form();
            form.Show();

            sound = new CSound();
            Random random = new Random();
            for (int i = 0; i < samples.Length; i++)
                samples[i] = 1000; // constant value

            while (true)
            {
                sound.Play(samples);
                System.Threading.Thread.Sleep(100); // 100 ms
            }
        }
     }
}

Answer

Sebastian Gray picture Sebastian Gray · Aug 20, 2009

If your looking for a way to play audio out through a defined stream, have you considered NAudio http://naudio.codeplex.com/?

You can define a stream, from either a file or some other location (i.e. memory) and then populate the stream with the data you want played back. As long as you are able to continue providing audio data to the stream before the read pointer arrives at the end of the buffer, you wont hear these artefacts in the generated audio.

BTW - I assume you know that the Managed Direct X libraries for .Net are no longer being developed and is effectively a dead end for this sort of Audio development?