How to play audio from a real-time stream

11,947

Solution 1

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?

Solution 2

There are a number of things wrong with this code. I'm guessing that when you run this code, you're hearing clicking or popping sounds every 100 ms. This is because of the Thread.Sleep(100) call inside the while(true) loop. Basically, your app is waiting 100 ms (give or take a small time amount) then calling Play(), which does a little processing and then queues up the array for playback. As a result, there is a little time gap between the playing of each 100 ms array, which is producing the clicks.

However, if you just commented out the Thread.Sleep(100) line, your app would go into an infinite loop where it keeps queueing up 100 ms array after 100 ms array until you ran out of memory. But at least the playback would not have the artifacts every 100 ms.

If you changed the line to Thread.Sleep(80), it would work a little better, in the sense that it would take you longer to run out of memory, but this would still happen because you would still be dumping buffers into the audio playback system faster than the system can play them.

Also, even if you get rid of the clicking every 100 ms, you still won't hear anything at all coming out of your speakers, because your code is setting every sample value to 1000. You will only ever hear anything if you vary the sample values over time. Incidentally, the only reason you're hearing clicks at all is because this sample value is set to 1000, and during those little time intervals between chunks the playback value goes back to 0. If you set each sample value to 0, you would never hear anything at all.

I could help you further with this, but I'd need to have a better idea of what you're trying to do, exactly. Are you trying to play a continuous tone at a certain frequency?

Share:
11,947
Admin
Author by

Admin

Updated on June 06, 2022

Comments

  • Admin
    Admin almost 2 years

    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
                }
            }
         }
    }