无需外部库即可在 C# 中播放动态创建的简单声音

2024-04-13

我需要能够使用 C# 动态生成波形并播放它,无需任何外部库,也无需在硬盘上存储声音文件。延迟不是问题;声音将在应用程序需要之前生成。

实际上,如果不是微软表示 64 位版本的 Windows 不支持 Console.Beep() 方法,它可能会满足我的需求。

如果我动态地生成自己的声音,我可以获得比简单的蜂鸣声更奇特的声音。例如,我可以用三角波制作一个波形,频率从 2 KHz 增加到 4 KHz,同时音量衰减。我不需要花哨的 16 位立体声,只需 8 位单声道就可以了。我不需要对音量和音调进行动态控制,只需在内存中生成一个声音文件并播放它而不存储它。

上次我需要生成声音是在很多年前,在 Apple II、HP 工作站和我的旧 Amiga 计算机上。从那以后就不需要这样做了,而且我描述的简单的事情似乎变得复杂了很多。我很难相信如此简单的事情看起来如此困难。我看到的大多数答案都涉及 NAudio 或类似的库,这不是这个项目的一个选项(除了事实上,只是为了播放一个音调而拉入整个库似乎是一种浪费)。


根据我收到的答案中的一个链接以及我发现的有关 .wav 标头格式的其他一些页面,这是我的一个小类的工作代码,该类生成 8 位“ding!”具有用户指定频率和持续时间的声音。它基本上是一种蜂鸣声,在指定的持续时间内振幅线性衰减到零。

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();
        }
    }
}

希望这可以帮助那些尝试在不需要声音文件的情况下动态生成简单警报声音的其他人。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无需外部库即可在 C# 中播放动态创建的简单声音 的相关文章

  • 如何使用 ASP.NET MVC 编辑多选列表?

    我想编辑一个如下所示的对象 我希望用 UsersGrossList 中的一个或多个用户填充 UsersSelectedList 使用 mvc 中的标准编辑视图 我只得到映射的字符串和布尔值 下面未显示 我在 google 上找到的许多示例都
  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • 异常堆栈跟踪不显示抛出异常的位置

    通常 当我抛出异常 捕获它并打印出堆栈跟踪时 我会看到抛出异常的调用 导致该异常的调用 导致该异常的调用that 依此类推回到整个程序的根 现在它只向我显示异常所在的调用caught 而不是它所在的地方thrown 我不明白是什么改变导致了
  • C++ 将联合强制转换为其成员类型之一

    以下对我来说似乎完全符合逻辑 但不是有效的 C 联合不能隐式转换为其成员类型之一 有人知道为什么不这样做的充分理由吗 union u int i char c function f int i int main u v v i 6 f v
  • 带有运算符语法的错误消息,但不带有函数语法的错误消息

    为什么我在调用 unary 时收到错误消息 使用运算符语法 如果我用函数语法调用它就可以了 现场演示 https godbolt org z j7AbeQ template
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • C# 编译器数字文字

    有谁知道 C 编译器数字文字修饰符的完整列表 默认情况下 声明 0 使其成为 Int32 声明 0 0 使其成为 Double 我可以在末尾使用文字修饰符 f 来确保某些内容被视为 Single 例如像这样 var x 0 x is Int
  • 静态类与类的实例

    我有一个静态类 用于访问我的公共属性 整个应用程序的全局属性 和我在应用程序运行期间使用的方法 例如 我在静态类中设置了一些属性 并且在应用程序运行时我可以从属性中获取值 但我可以使用单例模式创建非静态类并以相同的方式使用它 问题 对于我的
  • 通过 C# Mailkit / Mimekit 发送电子邮件,但出现服务器证书错误

    Visual Studio 2015 中的 0 代码 1 我正在使用 Mailkit 最新版本 1 18 1 1 从我自己的电子邮件服务器发送电子邮件 2 电子邮件服务器具有不受信任的自签名证书 3 我在代码中添加了以下两行 以忽略服务器证
  • 用于连接 DataTable 上的动态列的动态 LINQ

    我目前遇到的情况不确定如何继续 我有两个从数据库填充的数据表 我还有一个可用的列名称列表 可用于将这两个数据表连接在一起 我希望编写一组 LINQ 查询 这些查询将 显示两个数据表中的行 内部联接 用于从一个数据表更新另一个数据表 显示一个
  • 时间:2019-03-17 标签:c++fstream并发访问

    如果从不同的进程 线程同时访问文件会发生什么 据我所知 没有锁定文件的标准方法 只有操作系统特定的功能 就我而言 文件将被经常读取而很少写入 现在如果A打开一个文件进行读取 ifstream 并开始读取块 和B打开相同的文件进行写入 ofs
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 使用 OleDbCommandBuilder 时访问 SQL 语法错误

    我要在 C 中使用 OleDbDataAdapter 在 Access 数据库中插入数据 但收到错误消息INSERT INTO 命令中的语法错误 BackgroundWorker worker new BackgroundWorker Ol
  • ALTER TABLE ... ADD CONSTRAINT 失败时将事务回滚到保存点

    有没有办法在事务中添加检查约束and如果失败回滚到以前的保存点 而不是回滚整个事务 就我而言 当 ALTER TABLE ADD CONSTRAINT 命令失败时 事务无法回滚到保存点 尝试这样做会引发 InvalidOperationEx
  • 无法在 C# 中为 EventArgs 分配使用派生类型的事件处理程序

    所以我有一个事件声明如下 public event EventHandler OnChangeDetected 然后我有以下处理程序被分配给该事件 myObject OnChangeDetected OnTableChanged 我的理解是
  • 如何在dll级别读取app.config? [复制]

    这个问题在这里已经有答案了 我在一个解决方案中有一个控制台应用程序项目和库项目 dll The 图书馆项目有 app config 文件 我在其中存储我在库中使用的一些键值对 控制台应用程序引用此 dll 我有另一个 app config
  • Linq.Select() 中的嵌套表达式方法调用

    I use Select i gt new T 每次手动点击数据库后将我的实体对象转换为 DTO 对象 以下是一些示例实体和 DTOS 用户实体 public partial class User public int Id get set
  • 这种尺寸对齐是如何工作的

    对于所提供的评论 我无法理解以下代码 这段代码的作用是什么 以及等效的代码是什么8 aligned segment size must be 4 aligned attr gt options ssize 3 Here ssize is o
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima

随机推荐

  • 在 C++ 中构造对象的不同方法

    我想使用 C 在堆栈中构造一个对象 你知道这两种调用构造函数的方式 带括号和不带括号 有什么区别吗 a MyClass object b MyClass object 我正在使用 MFC 在为主应用程序构造全局变量时 如果我使用后一种方式
  • React Router 4 中 URL 更改但视图未更改

    我使用的是react router 4而不是react router 3 所以我使用的是react router dom 我试图让 this props history push 工作 但它所做的只是保持视图相同 但 URL 发生了变化 例
  • 如何获取打开的文件弹出窗口

    现在 我有一个设置的类路径 但我想要弹出一个打开的文件 并且用户选择要打开的文件 我尝试过 JFileChooser 但到目前为止还没有成功 这是我的代码 public static void main String args throws
  • 在 PHP 中删除数组项的最佳方法是什么?

    您能告诉我从数组中删除项目的方法吗 你觉得这样好吗 那要看 a1 array a gt 1 b gt 2 c gt 3 unset a1 b array a gt 1 c gt 3 a2 array 1 2 3 unset a2 1 arr
  • 可以在 t4 模板中使用全局变量吗?

    如何在 TT 文件中使用全局变量 如果我在标头中声明一个变量 并且在函数中引用它 则会出现编译错误 lt template debug false hostspecific false language C gt lt output ext
  • 如何使用Delphi在活动显示器的右下角显示消息窗口

    这些天你看到很多软件显示活动屏幕右下角的消息窗口几秒钟或直到单击关闭按钮 例如诺顿在检查下载后执行此操作 我想使用以下方法来做到这一点Delphi 7 如果可能的话德尔福2010 因为我正在慢慢地将代码迁移到最新版本 我在这里找到了一些关于
  • 将日期转换为 GMT - php

    我遇到了一个奇怪的问题 也许你可以帮忙 我正在尝试将日期转换为 GMT 时间 这就是我正在做的事情 date 2010 05 27 23 02 01 gmt date gmdate Y m d H i s date 但产量 gmt date
  • 如何对 Newtonsoft JArray 进行排序?

    是否可以排序JArray下面由col2例如 col1 thiscol col2 thisval col1 thiscol2 col2 thisval2 col1 thiscol3 col2 thisval3 如果将其转换为Array是唯一的
  • 如何在“if x in range”语句中使用浮点数

    我正在尝试写一个if将浮点数作为范围的语句 x 8 2 if x in range 0 4 4 print one if x in range 4 5 8 print two if x in range 8 1 9 9 print thre
  • 更新对象值 Ramda

    在上一个问题中 我尝试按父 ID 对数组进行分组 然后从每个对象中删除它们 按父 ID 对象 Ramda 对数组进行分组 https stackoverflow com q 58682137 9464680 但现在我有一个新问题 例如 我想
  • Android 致命信号 11 (SIGSEGV) at 0x00000040 (code=1) 错误

    我正在开发一个 Android 应用程序 我正在其中获取用户照片图像 5张图像 使用opencv2 4 2具有面部检测功能的相机 并使用 Web 服务保存到服务器中的数据库中 为此 我使用 Opencv2 4 2 人脸检测示例 Ksoap2
  • 裁剪以适合 svg 图案

    我有一些图案 每个图案中都有一个图像 我需要将图像缩放到其容器 即路径 的完整宽度或高度 同时保留其比例 本质上 如果您设置它们 它们的行为就需要像 html 图像一样min width 100 min height 100 我以前没有太多
  • swfupload 不允许我从一台服务器上传到另一台服务器

    我们有两个网络服务器 并且我们在这两个服务器之间专门执行任务 我们决定将所有 asp aspx 页面放入一台服务器中 并将 upload aspx sql 服务器放入另一台服务器中 这是服务器的名称 http server1 somecom
  • 为什么活动需要代表?为什么我们需要事件?

    过去几周我对发生的事情感到困惑 我了解代表如何工作 但不了解其详细工作方式 但足以了解这一点delegate datatype是单个演员委托 delegate void是一个多播委托 对方法的引用列表 我知道委托类型编译为类 但不幸的是我仍
  • 如何制作 npm 安装包并忽略一个(或所有)对等依赖项?

    I have email protected cdn cgi l email protection安装 我要安装vuex module decorators latest 其对等依赖性为vuex 3 not gt 3 我有一种感觉 这会很好
  • 从其他文件调用 php 类

    我正在研究一些自定义帖子类型 我完成了第一个 并意识到我正在使用的元框代码可以被其他未来的自定义帖子类型 以及页面 帖子等 重复使用 因此 我将该类放入其自己的 php 文件中 并将其包含在我的子主题的functions php 文件中 我
  • Haskell:无法导入 System.Random

    我已经按照找到的说明在 MacOS Mojave 上安装了 Haskellhere https www haskell org platform 即使用stack命令 然而 import System Random 带入ghci错误信息找不
  • 如何在 Oracle/SQL 中检索给定序列中的行?

    我有一个带有主键 MY PK 的表 MY TABLE 然后 我有一个有序主键列表 例如 17 13 35 2 9 现在我想检索具有这些主键的所有行 并以与给定键列表相同的方式保持行的顺序 我最初做的是 SELECT FROM MY TABL
  • 如何知道是否发生欠拟合或过拟合?

    我正在尝试用两个类进行图像分类 我有 1000 张具有平衡类别的图像 当我训练模型时 我得到了较低的恒定验证准确性 但验证损失却在减少 这是过度拟合或欠拟合的迹象吗 我还应该注意到 我正在尝试使用新类和不同的数据集重新训练 Inceptio
  • 无需外部库即可在 C# 中播放动态创建的简单声音

    我需要能够使用 C 动态生成波形并播放它 无需任何外部库 也无需在硬盘上存储声音文件 延迟不是问题 声音将在应用程序需要之前生成 实际上 如果不是微软表示 64 位版本的 Windows 不支持 Console Beep 方法 它可能会满足