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

news2024/9/21 8:03:33

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible常用变量【上】

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 在Ansible中会用到很多的变量&#xff0c;Ansible常用变量包括以下几种&#xff1a; 1. 自定义变量——在playbook中用户自定义…

函数重载和函数模板

c语言中函数名字不可重复,但是可以写代码实现 普通的函数重载 这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同和返回值没有关系(因为就像我想调用Add(1,2),Add重载的几个函数仅仅返回值不同,编辑器就不知道去找哪一个,就有歧义了) 情况1-数组 int ave(int*pa,i…

用 Supabase CLI 进行本地开发环境搭建

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;Supabase CLI&#xff08;1.1&#xff09;安装 Scoop&#xff08;1.2&#xff09;用 Scoop 安装 Supabase CLI &#xff08;二&#xff09;本地项目环境&#xff08;2.1&#xff09;初始化项目&#xff08;2…

【全开源】微凌客洗护小程序FastAdmin+Uniapp(源码搭建/上线/运营/售后/维护更新)

一款基于FastAdminUniapp开发的洗护小程序系统&#xff0c;适用于线上下单到店核销的业务场景&#xff0c;拥有会员卡、优惠券、充值提现、商户管理等功能&#xff0c;提供Uniapp后台无加密源代码。 线上线下融合&#xff1a;微凌客洗护小程序适用于线上下单到店核销的业务场景…

nacos命名空间的配置

给微服务配置namespace 给微服务配置namespace只能通过修改配置来实现。 例如&#xff0c;修改order-service的application.yml文件&#xff1a; spring:cloud:nacos:server-addr: localhost:8848discovery:cluster-name: HZnamespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f…

C语言数据结构 - 选择题集合(二叉树)

一生负气成今日 四海无人对夕阳 目录 树的专辑 树的专辑 1.有n个元素的完全二叉树的深度是&#xff08; &#xff09; A.nlogn B.nlogn1 C.logn D.logn1 答案&#xff1a;D 解析&#xff1a; 设完全二叉树的节点数为 N&#xff0c;高度为 h &#xff0c;高度为 h 时空的结点…

python零基础知识 - 定义列表的三种方式,循环列表索引值

这一小节&#xff0c;我们将从零基础的角度看一下&#xff0c;python都有哪些定义列表的方式&#xff0c;并且循环这个列表的时候&#xff0c;怎么循环&#xff0c;怎么循环他的索引值&#xff0c;怎么拿到的就是元素值。 说完循环&#xff0c;我们会说一说关键的break和contin…

分布式存储故障导致数据库无法启动故障处理---惜分飞

国内xx医院使用了国外医疗行业龙头的pacs系统,由于是一个历史库,存放在分布式存储中,由于存储同时多个节点故障,导致数据库多个文件异常,数据库无法启动,三方维护人员尝试通通过rman归档进行应用日志,结果发现日志有损坏报ORA-00354 ORA-00353,无法记录恢复,希望我们给予支持 M…

AI智能分析高精度烟火算法EasyCVR视频方案助力打造森林防火建设

一、背景 随着夏季的来临&#xff0c;高温、干燥的天气条件使得火灾隐患显著增加&#xff0c;特别是对于广袤的森林地区来说&#xff0c;一旦发生火灾&#xff0c;后果将不堪设想。在这样的背景下&#xff0c;视频汇聚系统EasyCVR视频融合云平台AI智能分析在森林防火中发挥着至…

人脸消费给传统食堂带来的变化

消费的技术基础是脸部识别&#xff0c;脸部识别是基于人的容貌特征信息进行认证的生物特征识别技术&#xff0c;其突出的特征是以非接触方式进行识别&#xff0c;避免个人信息的泄露。 面部识别和指纹识别、掌纹识别、视网膜识别、骨骼识别、心率识别等都是人体生物特征识别技术…

自然资源-城镇开发边界内详细规划编制技术指南解读

自然资源-城镇开发边界内详细规划编制技术指南解读

护眼台灯和普通台灯差别很大吗?专业护眼灯品牌有哪些?

随着科技的不断演进&#xff0c;台灯的设计也日益脱胎换骨&#xff0c;从曾经的笨重造型转变为如今轻盈雅致的外观。它们的功能同样经历了多样化的革新&#xff0c;变得更加人性化和便捷。作为学习、阅读和办公环境中不可或缺的照明工具&#xff0c;台灯所提供的光线舒适度至关…

redis抖动问题导致延迟或者断开的处理方案

目录&#xff1a; 1、使用背景2、redis重试机制3、redis重连机制4、其他一些解决redis抖动问题方案 1、使用背景 客户反馈文件偶现打不开&#xff0c;报错现象是session not exist&#xff0c;最终定位是redis抖动导致的延迟/断开的现象&#xff0c;最终研发团方案是加入redis…

电脑nvidia驱动和合适版本的duda--自用 回忆版

参考文献&#xff1a;http://t.csdnimg.cn/ecDuG 内容很多抄的这个&#xff0c;主要害怕链接失效 一、Ubuntu 18.04 安装NVIDIA显卡驱动 1、查看本机显卡能够配置的驱动信息 ubuntu-drivers devices所以可以看出&#xff0c;推荐 nvidia-driver-530 - distro non-free 2、安…

HTML/CSS2

1.前置说明 HTML/CSS1 2.img元素 格式&#xff1a; <img src"图片地址" alt"占位文字" width"图片宽度" height"图片高度">其中alt是当图片加载失败时显示的文字 而且不同内核的浏览器显示出来的占位文字的效果也是不尽相同…

【linux软件基础知识】如何使用 run_list 字段将任务放入就绪队列中

在给定的代码片段中,struct task_struct 表示内核中任务或进程的进程控制块 (PCB)。 run_list 字段的类型为 struct list_head,这表明它是链表实现的一部分。 run_list字段在Linux内核中常用来表示任务在调度队列中的位置,例如就绪队列或各种优先级队列。 init_task是一个…

Elasticsearch入门基础和集群部署

Elasticsearch入门基础和集群部署 简介基础概念索引&#xff08;Index&#xff09;类型&#xff08;Type&#xff09;&#xff08;逐步弃用&#xff09;文档&#xff08;Document&#xff09;字段&#xff08;Field&#xff09;映射&#xff08;Mapping&#xff09;分片&#x…

人工智能能否解决科学问题:Wolfram的视角

引言 在当今AI技术飞速发展的背景下&#xff0c;它在科学研究领域的应用正逐渐深入。从AlphaFold 3的推出到日益复杂的计算模型&#xff0c;AI似乎在向科学家的角色靠拢。然而&#xff0c;美国计算机科学家Stephen Wolfram在一系列讲座和文章中提出了反思&#xff1a;AI真的能…

网站localhost和127.0.0.1可以访问,本地ip不可访问解决方案

部署了一个网站, 使用localhost和127.0.0.1加端口号可以访问, 但是使用本机的ip地址加端口号却不行. 原因可能有多种. 可能的原因: 1 首先要确认是否localhost对应的端口是通的(直接网址访问), 以及你无法访问的那个本机ip是否正确(使用ping测试)&#xff1b; 2 检查本机的防火…

uniapp开发小程序使用vue的v-html解析富文本图片过大过宽显示超过屏幕解决办法

如果没有设置的话&#xff0c;就会导致图片溢出&#xff0c;过宽显示或者错位显示&#xff0c;显示效果非常的丑陋&#xff1a; 修改后显示的效果&#xff1a; 网上比较low的解决办法&#xff1a;网上各种解决方法核心思想就是在数据层把数据模板上的img数据加上style样式&…