播放动态创建简单的声音在C#中没有外部库 [英] Play dynamically-created simple sounds in C# without external libraries

查看:156
本文介绍了播放动态创建简单的声音在C#中没有外部库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要能够动态地生成一个波形并播放它,使用C#,而没有任何外部库,而不必声音文件存储在硬盘上。延迟不是一个问题;的声音,就可以产生很好的应用需要才。

I need to be able to generate dynamically a waveform and play it, using C#, without any external libraries, and without having to store sound files on the hard disk. Latency isn't an issue; the sounds would be generated well before they are needed by the application.

其实Console.Beep()方法可能会满足我的需求,如果不是因为微软说,它不能在Windows的64位版本支持的事实。

Actually the Console.Beep() method might meet my needs if it weren't for the fact that Microsoft says it isn't supported in 64-bit versions of Windows.

如果我给自己的声音动态,我可以得到一个比一个简单的蜂鸣声更看中的。例如,我可以做从三角波从2kHz到4kHz而在量衰减频率,增加的波形。我并不需要花哨的16位立体声,仅有8位单声道的罚款。我并不需要动态地控制音量和音调,基本上只是在内存中生成一个音效档,并发挥它没有保存它。

If I generate my own sound dynamically I can get a more fancy than a simple beep. For example, I could make a waveform from a triangle wave that increases in frequency from 2 KHz to 4 KHz while decaying in volume. I don't need fancy 16-bit stereo, just 8-bit mono is fine. I don't need dynamic control over volume and pitch, just basically generate a soundfile in memory and play it without storing it.

我最后一次需要产生的声音是很多年前,在苹果II,惠普工作站和我的旧的Amiga计算机上。有没有必要做从那时起,它似乎是简单的东西,我已经描述得到了很多更复杂。我无法相信,这么简单的东西似乎很难。最让我看看是指n音讯或类似的库,而不是这个项目的一个选项的答案(从事实搁置在整个库拉只是起到一个基调似乎是一种浪费)。

Last time I needed to generate sounds was many years ago, on Apple II, on HP workstations, and on my old Amiga computer. Haven't needed to do it since then, and it seems that something simple that I describe has gotten a lot more complicated. I am having trouble believing that something so simple seems so hard. Most of the answers I see refer to NAudio or similar libraries, and that isn't an option for this project (aside from the fact that pulling in an entire library just to play a tone seems like a waste).

推荐答案

根据在我收到答案的链接,以及其他一些网页中的一个,我发现有关的.wav头格式,这是我的工作code代表有点类,生成一个8位的叮!声音与用户指定的频率和持续时间。它基本上是在振幅指定的持续时间期间线性衰减到零蜂鸣声。

Based on one of the links in the answers I received, and some other pages I found about .wav header formats, here is my working code for a little class that generates an 8-bit "ding!" sound with a user-specified frequency and duration. It's basically a beep that decays linearly to zero in amplitude during the specified duration.

public class AlertDing {
    private SoundPlayer player = null;
    private BinaryWriter writer = null;

    /// <summary>
    /// Dynamically generate a "ding" sound and save it to a memory stream
    /// </summary>
    /// <param name="freq">Frequency in Hertz, e.g. 880</param>
    /// <param name="tenthseconds">Duration in multiple of 1/10 second</param>
    public AlertDing(double freq, uint tenthseconds) {

        string header_GroupID = "RIFF";  // RIFF
        uint header_FileLength = 0;      // total file length minus 8, which is taken up by RIFF
        string header_RiffType = "WAVE"; // always WAVE

        string fmt_ChunkID = "fmt "; // Four bytes: "fmt "
        uint fmt_ChunkSize = 16;     // Length of header in bytes
        ushort fmt_FormatTag = 1;        // 1 for PCM
        ushort fmt_Channels = 1;         // Number of channels, 2=stereo
        uint fmt_SamplesPerSec = 14000;  // sample rate, e.g. CD=44100
        ushort fmt_BitsPerSample = 8;   // bits per sample
        ushort fmt_BlockAlign =
            (ushort)(fmt_Channels * (fmt_BitsPerSample / 8)); // sample frame size, in bytes
        uint fmt_AvgBytesPerSec =
            fmt_SamplesPerSec * fmt_BlockAlign; // for estimating RAM allocation

        string data_ChunkID = "data";  // "data"
        uint data_ChunkSize;           // Length of header in bytes
        byte [] data_ByteArray;

        // Fill the data array with sample data

        // Number of samples = sample rate * channels * bytes per sample * duration in seconds
        uint numSamples = fmt_SamplesPerSec * fmt_Channels * tenthseconds / 10;
        data_ByteArray = new byte[numSamples];

        //int amplitude = 32760, offset=0; // for 16-bit audio
        int amplitude = 127, offset = 128; // for 8-audio
        double period = (2.0*Math.PI*freq) / (fmt_SamplesPerSec * fmt_Channels);
        double amp;
        for (uint i = 0; i < numSamples - 1; i += fmt_Channels) {
            amp = amplitude * (double)(numSamples - i) / numSamples; // amplitude decay
            // Fill with a waveform on each channel with amplitude decay
            for (int channel = 0; channel < fmt_Channels; channel++) {
                data_ByteArray[i+channel] = Convert.ToByte(amp * Math.Sin(i*period) + offset);
            }
        }

        // Calculate file and data chunk size in bytes
        data_ChunkSize = (uint)(data_ByteArray.Length * (fmt_BitsPerSample / 8));
        header_FileLength = 4 + (8 + fmt_ChunkSize) + (8 + data_ChunkSize);

        // write data to a MemoryStream with BinaryWriter
        MemoryStream audioStream = new MemoryStream();
        BinaryWriter writer = new BinaryWriter(audioStream);

        // Write the header
        writer.Write(header_GroupID.ToCharArray());
        writer.Write(header_FileLength);
        writer.Write(header_RiffType.ToCharArray());

        // Write the format chunk
        writer.Write(fmt_ChunkID.ToCharArray());
        writer.Write(fmt_ChunkSize);
        writer.Write(fmt_FormatTag);
        writer.Write(fmt_Channels);
        writer.Write(fmt_SamplesPerSec);
        writer.Write(fmt_AvgBytesPerSec);
        writer.Write(fmt_BlockAlign);
        writer.Write(fmt_BitsPerSample);

        // Write the data chunk
        writer.Write(data_ChunkID.ToCharArray());
        writer.Write(data_ChunkSize);
        foreach (byte dataPoint in data_ByteArray) {
            writer.Write(dataPoint);
        }
        player = new SoundPlayer(audioStream);
    }

    /// <summary>
    /// Call this to clean up when program is done using this sound
    /// </summary>
    public void Dispose() {
        if (writer != null) writer.Close();
        if (player != null) player.Dispose();
        writer = null;
        player = null;
    }

    /// <summary>
    /// Play "ding" sound
    /// </summary>
    public void Play() {
        if (player != null) {
            player.Stream.Seek(0, SeekOrigin.Begin); // rewind stream
            player.Play();
        }
    }
}

这应该可以帮助别人谁试图动态生成一个简单的警报声,而不需要一个声音文件。

Hopefully this should help others who are trying to produce a simple alert sound dynamically without needing a sound file.

这篇关于播放动态创建简单的声音在C#中没有外部库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆