如何从实时流中播放音频

hos*_*ein 6 c# multimedia

我有一个程序可以产生应该同时播放的音频信号.为此,我在每100 ms周期内播放100 ms的音频流间隔.但是我在每个100毫秒音频流的开始和结束时都有不需要的信号(因为DC),因此即使信号值相同,输出声音也不平滑.我的代码附在下面.请帮助我做一些正确的实时音频.

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
            }
        }
     }
}
Run Code Online (Sandbox Code Playgroud)

Mus*_*sis 1

这段代码有很多问题。我猜当您运行此代码时,您每隔 100 毫秒就会听到咔哒声或爆裂声。这是因为 while(true) 循环内调用了 Thread.Sleep(100)。基本上,您的应用程序等待 100 毫秒(给予或花费一小段时间),然后调用 Play(),它会进行一些处理,然后将数组排队等待播放。因此,每个 100 毫秒阵列的播放之间存在一点时间间隙,从而产生喀哒声。

但是,如果您只是注释掉 Thread.Sleep(100) 行,您的应用程序将进入无限循环,在 100 毫秒数组之后不断排队,直到内存耗尽。但至少回放不会每隔 100 毫秒出现伪影。

如果您将该行更改为 Thread.Sleep(80),它会工作得更好一些,因为您需要更长的时间才能耗尽内存,但这种情况仍然会发生,因为您仍然会将缓冲区转储到音频中播放系统的速度比系统播放它们的速度快。

另外,即使您消除了每 100 毫秒一次的喀哒声,您仍然不会听到扬声器发出任何声音,因为您的代码将每个样本值设置为 1000。只有当您改变随时间变化的样本值。顺便说一句,您听到咔嗒声的唯一原因是因为此样本值设置为 1000,并且在块之间的小时间间隔内,播放值返回到 0。如果将每个样本值设置为 0,您将永远不会听到任何声音。

我可以进一步帮助你,但我需要更好地了解你到底想做什么。您是否尝试以特定频率播放连续音调?