C#语音播报(通过CoreAudioAPI完成对扬声器的控制)

1,效果:

  • 作用:
  1. 可对当前内容(例如此例中的重量信息)进行语音合成播报 。
  2. 可设置系统扬声器音量与状态(是否静音),同时根据扬声器状态同步更新当前控件状态与值,实现强制PC扬声器按照指定的音量进行播报,杜绝人为静音的可能。

2,引入相关程序集,命名空间。

  • 程序集

        微软语音合成程序集:System.Speech

        第三方程序集:CoreAudioAPI(为方便使用,进行了部分修改包装)

  • 命名空间:
using System.Speech.Synthesis;
using CoreAudioAPIs;

3,代码:

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="112*"/>
            <ColumnDefinition Width="320*"/>
            <ColumnDefinition Width="85*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="59*"/>
            <RowDefinition Height="51*"/>
            <RowDefinition Height="77*"/>
            <RowDefinition Height="43*"/>
            <RowDefinition Height="32*"/>
            <RowDefinition Height="58*"/>
        </Grid.RowDefinitions>
        <TextBlock Text="重量:" FontSize="32" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,8"></TextBlock>
        <TextBox Grid.Column="1" VerticalContentAlignment="Center" x:Name="txtWeight" FontSize="30"></TextBox>
        <ComboBox x:Name="combo01" Grid.Column="2" VerticalContentAlignment="Center" FontSize="32">
            <ComboBoxItem FontSize="32" IsSelected="True">KG</ComboBoxItem>
            <ComboBoxItem FontSize="32">T</ComboBoxItem>
            <ComboBoxItem FontSize="32">G</ComboBoxItem>
        </ComboBox>
        <Button x:Name="btnPlay" Content="播报" FontSize="25" Grid.Row="1" Grid.Column="1" Margin="20,3" Click="btnPlay_Click"></Button>
        <Grid Grid.Row="2" Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition ></RowDefinition>
                <RowDefinition ></RowDefinition>
               
            </Grid.RowDefinitions>
            <TextBlock x:Name="txtStatus" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Status}" Foreground="{Binding StatusForeground}" FontSize="16"></TextBlock>
            <TextBlock FontSize="24" Grid.Row="1"  Text="PC扬声器设置" HorizontalAlignment="Center" VerticalAlignment="Bottom"></TextBlock>
        </Grid>
        
        <TextBlock Text="播放音量:" Grid.Row="3" FontSize="16" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,11,0,10"></TextBlock>
        <Slider Grid.Row="3" Grid.Column="1" ValueChanged="slider01_ValueChanged" Minimum="0" VerticalAlignment="Center" Maximum="100" x:Name="slider01" SmallChange="1" LargeChange="5" TickPlacement="BottomRight" IsSnapToTickEnabled="True" Margin="0,11,0,10"></Slider>

        <TextBlock Grid.Row="3" Grid.Column="2" FontSize="16" VerticalAlignment="Center" Margin="10,0" DockPanel.Dock="Left" Text="{Binding ElementName=slider01 ,Path=Value}"></TextBlock>
        <CheckBox Grid.Row="4" x:Name="muteCheck01" Click="muteCheck01_Checked" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="16">静音</CheckBox>

    </Grid>
 public partial class MainWindow : Window, System.ComponentModel.INotifyPropertyChanged
    {
        VolumeControl volumeControl = new VolumeControl();
        public event PropertyChangedEventHandler PropertyChanged;
        SpeechSynthesizer speeker = new SpeechSynthesizer();
        public MainWindow()
        {
            InitializeComponent();
            volumeControl.VolumeStateChange += VolumeControl_VolumeStateChange;
            slider01.Value = Volume;
            muteCheck01.IsChecked = Mute;
            this.DataContext = this;
            Status = "准备就绪!";
            StatusForeground = new SolidColorBrush(Colors.Green);
        }
        
        public bool Mute
        {
            get
            {
                return volumeControl.IsMuted;
            }
            set
            {
                volumeControl.IsMuted = value;
                OnPropertyChanged(nameof(Mute));
            }
        }
        public int Volume
        {
            get
            {
                return volumeControl.Volume;
            }
            set
            {
                volumeControl.Volume = value;
                OnPropertyChanged(nameof(Volume));
            }
        }
        string status;
        public string Status
        {
            get
            {
                return status;
            }
            set
            {
                status = value;
                OnPropertyChanged(nameof(Status));
            }
        }
        Brush statusForeground = new SolidColorBrush(Colors.Black);
        public Brush StatusForeground
        {
            set
            {
                statusForeground = value;
                OnPropertyChanged(nameof(statusForeground));
            }
            get
            {
                return statusForeground;
            }
        }
        private void VolumeControl_VolumeStateChange(bool mute, int volumeValue)
        {
            Dispatcher.Invoke(() =>
            {
               //移除注册,否则更新控件时将出现循环,这也是不用绑定的原因
                slider01.ValueChanged -= slider01_ValueChanged;
                muteCheck01.Checked -= muteCheck01_Checked;
                this.muteCheck01.IsChecked = mute;
                slider01.Value = volumeValue;
                //重新注册
                slider01.ValueChanged += slider01_ValueChanged;
                muteCheck01.Checked += muteCheck01_Checked;
            });
        }
        private void slider01_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Volume = (int)slider01.Value;
        }
        private void muteCheck01_Checked(object sender, RoutedEventArgs e)
        {
            Mute = muteCheck01.IsChecked.HasValue ? muteCheck01.IsChecked.Value : false;
        }
      
        private void btnPlay_Click(object sender, RoutedEventArgs e)
        {
            PromptBuilder builder = new PromptBuilder();
            builder.AppendText("当前重量:", PromptVolume.Loud);
            builder.AppendBreak(PromptBreak.Medium);
            PromptStyle style = new PromptStyle();
            style.Emphasis = PromptEmphasis.Strong;
            style.Rate = PromptRate.Medium;
            style.Volume = PromptVolume.ExtraLoud;
            builder.StartStyle(style);
            builder.AppendTextWithHint(txtWeight.Text.Trim(), SayAs.NumberCardinal);
            builder.EndStyle();
            string str = "";
            switch (combo01.Text)
            {
                case "KG":
                    str = "千克";
                    break;
                case "G":
                    str = "克";
                    break;
                default:
                    str = "吨";
                    break;
            }
            builder.AppendBreak(PromptBreak.Small);
            builder.AppendText(str, PromptEmphasis.Strong);
            SpeechBroadcasting(builder);
        }
        async void SpeechBroadcasting(PromptBuilder builder)
        {
            Status = "播报中.....";
            StatusForeground = new SolidColorBrush(Colors.Orange);
            await Task.Run(() =>
             {
                 //耗时长
                 speeker.Speak(builder);
             }).ContinueWith(t =>
             {
                 Dispatcher.Invoke(() =>
                 {
                     Status = "播报完成!";
                     StatusForeground = new SolidColorBrush(Colors.BlueViolet);
                 });
                 System.Threading.Thread.Sleep(1000);
             });
            Status = "准备就绪!";
            StatusForeground = new SolidColorBrush(Colors.Green);
        }
        void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

4,Demo链接:

https://download.csdn.net/download/lingxiao16888/89298014

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/630467.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

原生IP介绍

原生IP&#xff0c;顾名思义&#xff0c;即初始真实IP地址&#xff0c;是指从互联网服务提供商获得的IP地址&#xff0c;IP地址在互联网与用户之间直接建立联系&#xff0c;不需要经过代理服务器代理转发。 原生IP具备以下特点。 1.直接性 原生IP可以直接连接互联网&#xff…

Docker mysql主从同步

1. 在主节点注册一个账号&#xff0c;用于子节点访问主节点 #mysql 1主2从&#xff0c;先创建主节点 ,注意 \ 后面不要带空格 docker run --name mysql-m \ -v /usr/local/mysql/data:/var/lib/mysql \ -v /usr/local/mysql/conf:/etc/mysql/conf.d \ -v /usr/local/mysql/log:…

STK中的光照计算模型

本文简要阐述STK中光照计算的模型。 在航天任务中&#xff0c;通常需要分析地面站、飞行器在一定时间内的光照情况&#xff0c;具体包括&#xff1a; 地面站处在光照区和阴影区的具体时间范围&#xff1b;考虑地形遮挡后&#xff0c;地面站的光照区和阴影区的变化情况&#x…

实战+代码!Selenium + Phantom JS爬取天天基金数据

功能&#xff1a; 通过程序实现从基金列表页&#xff0c;获取指定页数内所有基金的近一周收益率以及每支基金的详情页链接。再进入每支基金的详情页获取其余的基金信息&#xff0c;将所有获取到的基金详细信息按近6月收益率倒序排列写入一个Excel表格。 思路&#xff1a; 1.…

物联网设计竞赛_5_Jetson Nano连接摄像头解决运行卡顿问题

我在命令行用camorama命令打开摄像头的时候发现摄像头非常流畅 当我用python的cv2库打开摄像头的时候发现摄像头显示图片异常卡顿&#xff0c;在网上多方寻觅无果后&#xff0c;经过偶然尝试&#xff0c;我发现了卡顿原来是视频帧率问题 淘宝官方资料看我的摄像头只有30fps, …

Gone框架介绍17 - 创建一个可运行在生产环境的Web项目

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档原地址&#xff1a;https://goner.fun/zh/guide/auto-gen-priest.html 请帮忙在github上点个 ⭐️吧&#xff0c;这对我很重要 &#xff1b;万分感谢&#xff01;&a…

练习队列的相关操作:循环队列

1. 思路解析 循环队列就是在只有有限的空间时使用队列实现循环存储数据&#xff0c;有双向链表和数组两种选择&#xff0c;这里我们使用数组实现循环队列&#xff08;因为链表我不会 >-<&#xff09; 2. 相关函数及其实现 2.1 判空与判满 判空&#xff1a;直接返回头尾…

景源畅信数字:做抖音切片的方法分享?

一提起抖音切片&#xff0c;很多人可能会想到那些让人眼前一亮的短视频。它们通常短小精悍&#xff0c;内容丰富多彩&#xff0c;能够迅速吸引观众的注意力。但是&#xff0c;如何制作出这样的切片视频呢?这就是我们今天要探讨的问题。 一、选材与剪辑 制作抖音切片&#xff0…

每日一日 kotori和气球

kotori和气球 (nowcoder.com) 题目描述&#xff0c;就是只要相邻的气球不相同即可&#xff0c; 解题思路 使用高中的排列组合&#xff1a;第一个位置 可以填n种情况 其次后推不可与前一个相同所以可以 填n -1中情况&#xff0c;结果相乘即可 可以使用bigInteger实现 或者说…

记录计全支付切换到RabbitMQ时启动报错的问题

记录计全支付切换到RabbitMQ时启动报错的问题 首先在application.yml中切换到RabbitMQ配置安装RabbitMQ、Erlang、延时插件 rabbitmq_delayed_message_exchange&#xff0c;延迟插件必装 首先在application.yml中切换到RabbitMQ配置 # 第一处rabbitmq:addresses: 127.0.0.1:56…

微信视频号开店需要多少钱?2024年最新入驻条件,商家必看!

哈喽~我是电商月月 视频号小店逐渐走入大众视野&#xff0c;观众多&#xff0c;但里面的商家却很少&#xff0c;很多想创业做电商的朋友&#xff0c;就把目光锁定到了视频号平台&#xff0c;那现在视频号小店的入驻费用肯定是新手&#xff0c;最关心的事情了&#xff01; 今天…

javaEE进阶——SpringBoot与SpringMVC第一讲

文章目录 什么是springMVCSpringMVC什么是模型、视图、控制器MVC和SpringMVC的关系SpringMVC的使用第一个SpringMVC程序RestController什么是注解 那么RestController到底是干嘛的呢&#xff1f;RequestMapping 如何接收来自请求中的querystryingRequestParamRequestMapping(&q…

Java入门基础学习笔记18——赋值运算符

赋值运算符&#xff1a; 就是“”&#xff0c;就是给变量赋值的&#xff0c;从右边往左边看。 int a 10; // 把数据赋值给左边的变量a存储。 扩展赋值运算符&#xff1a; 注意&#xff1a;扩展的赋值运算符隐含了强制类型转换。 package cn.ensource.operator;public class…

Linux 第三十四章

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

svn批量解锁

问题 svn对文件进行checkout之后&#xff0c;先进行lock&#xff0c;之后再去更改&#xff0c;最后进行Commit操作&#xff1b; 上述为我们通过svn管理代码的正常方式&#xff0c;但总会有其他现象发生&#xff1b; 如果我们非正常操作&#xff0c;批量锁所有的svn文件&#x…

中国农业大学:学硕11408复试线上涨40分,今年还会持续涨吗?中国农业大学计算机考研考情分析!

中国农业大学&#xff08;China Agricultural University&#xff09;&#xff0c;简称“中国农大”&#xff0c;坐落于中国首都北京&#xff0c;由中华人民共和国教育部直属&#xff0c;中央直管副部级建制&#xff0c;水利部、农业部和北京市共建&#xff0c;位列国家“双一流…

串,数组和广义表

2.1.求next和nextval的实现 代码&#xff1a; int next_one(char *str, int len) {int result 1;if(len 1 || len 0) return len;for (size_t i 1; i < len; i){ if(compare(str, strlen-i, i)) {result i1;//break;}}return result; }int next(char *str, int *…

【校园生活小程序_超详细部署】

校园生活小程序 1 完整小程序源码2 运行环境3 初次运行3.1 启动后端程序3.1.1 导入项目&#xff0c;找到项目的pom.xml文件&#xff0c;点击ok进行打开。3.1.2 创建数据库并插入内容 3.1.3 配置项目结构信息3.1.4 配置Tomcat服务器3.1.5 正式启动后端项目3.1.6出现BUG3.1.7 解决…

小程序框架是智能融媒体平台构建的最佳线路

过去5年&#xff0c;媒体行业一直都在进行着信息化建设向融媒体平台建设的转变。一些融媒体的建设演变总结如下&#xff1a; 新闻终端的端侧内容矩阵建设&#xff0c;如App新闻端&#xff0c;社交平台上的官方媒体等新闻本地生活双旗舰客户端&#xff0c;兼顾主流媒体核心宣传…

【密评】 | 商用密码应用安全性评估从业人员考核题库(09)

Hill密码是重要古典密码之一&#xff0c;其加密的核心思想的是&#xff08;&#xff09;。 A.线性变换 B.非线性变换 C.循环移位 D.移位 著名的Kerckhoff原则是指&#xff08;&#xff09;。 A.系统的保密性不但依赖于对加密体制或算法的保密&#xff0c;而且依赖于密钥 B.系统…