java学习纯语音版_有了c语音基础,想继续学习c语音还是java或c++ - CSDN
  • Java提供了语音API技术用于支持应用程序或Web页面中的人机语音交互,其核心技术包括语音合成和语音识别。FreeTTS是Java语音合成技术的实现手段之一,以创建电话号码朗读程序为例, 探讨了基于该技术的Java语音API实现...
    Java提供了语音API技术用于支持应用程序或Web页面中的人机语音交互,其核心技术包括语音合成和语音识别。FreeTTS是Java语音合成技术的实现手段之一,以创建电话号码朗读程序为例, 探讨了基于该技术的Java语音API实现方法及相关问题。
    
        计算机技术的快速发展同时也推动了多媒体技术的广泛应用, 人机语音交互已经不再是纯粹的理论研究, 其应用在日常生活中越来越普遍: 如移动终端、通信、信息系统服务、家庭娱乐等。作为流行的编程语言, Java 提供了语音A P I 技术用于实现应用程序或者Web 页面中的人机语音交互, 包括语音合成和语音识别两部分核心技术,但官方并未提供其实现工具。
           FreeTTS 属于第三方免费语音合成java组件, 由Speech Interat ion Group of Sun Micro systemsLaboratiories 和来自IBM的Speech for Java两公司合作开发。本文探讨了基于FreeTTS的语音朗读程序设计与实现, 为工业应用中相关系统的开发提供一个技术参考。
    1.FreeTTS 的获得、安装与配置
        FreeTTS属于免费的开源java组件, 其官方网站是: http://freetts.sourceforge.net,用户可以在该网站上免费下载。目前最新的版本是11211,下载后的文件名与格式是: freetts-1.2.2-bin.zip。基于java的特点,该组件是跨平台的,安装方法与普通java 应用程序或者组件的方法类似, 将文件解压至特定目录并设置环境变量即可, 具体过程可以参考其安装说明。
    2.语音合成功能实现
        以一个例子来说明FreeTTS 的应用。该程序最终实现的效果如图1所示。用户在下拉菜单中可选择“张三”、“王五”、“赵七”三个名字,三人依次对应电话号码:“07138616661”,“13871990001”,“07136767555”。选择人名后点击“读出号码”,系统即可发出声音,将对应的电话号码读出。该程序的设计包括以下过程:
    ①导入Java 语音API包
    主要代码:
    Import javax.speech.* ;
    Import javax.speech.synthesis.* ;
    其中javax1speech中的类和接口用来支持音频连通性;javax1speech.synthesis中的类和接口用来支持语音合成。
    ②为语音合成器声明实例变量
        例如: private Synthesizer speechSynthesizer;
    ③语音合成器的初始化
        初始化是FreeTTS应用中关键的部分。首先需要建立一个SynthesizerModeDesc 对象,该对象用于指明语音合成器的属性,包括语音引擎的的名称、语音引擎的操作模式、支持的语言、语音引擎的运行状态以及其发音能力等。
        Syn thesizerModeDesc的构造方法需要接收5 个参数。第一个St ring 类型的参数用于指明文本到语音引擎的的名称,如果是FreeTTS 自
    带,其名称为“Unlimited dom ain FreeTTS Speech Synthesizerrom Sun Labs”; 第二个String 类型的参数用于标示语音引擎的操作模式,如果设置为null,则意味该引擎不存在特定的操作要求; 第三个参数用于指明该语音引擎所支持的语言,为Local类型,Local对象代表世界上特定的区域, 如果设置为Locale1US,则代表与之关联的语言为英语;第四个参数是布尔类型,表示是否有一个正在运行的语音引擎,如果为False,表示不去选择已得到运行的引擎;第五个参数是一个Voice数组对象, 允许开发人员指定某一语音合成器所输出的语言,设置为null代表不存在特定的要求。下面是构造的例子:
    SynthesizerModeDesc descriptor = new
    SynthesizerModeDesc(
    "Unlimited domain FreeTTS Speech Synthesizer " +
    " from Sun Labs", null, Locale1US, Boolean1FALSE,null) ;
    ④创建语音合成器
        创建语言合成器时需要用到Cen t ral 类, 其作用是提供用来访问所有语音输入和输出的能力, 同时也可以定为语言引擎, 根据描述符所定义的属性集合选择匹配的引擎, 从而创建语音识别器和语音合成器。语音合成器的创建需使用Central类的createSynthesizer方法,该方法接受一个SynthesizerModeDesc描述符并返回同描述符中所指定属性相匹配的一个Synthesizer对象,用以实现语音合成。示例如下:
    speechSynthesizer = Cent ral1createSynthesizer(descriptor)
    ⑤准备用于朗读的Synthesizer 对象
        该部分通过Synthesizer对象的allocate和resume方法分配语音引擎所需要的资源并取得可用于朗读的语音合成器。实现较为简单:speechSynthesizer1allocate();speechSynthesizer1resume();
    ⑥设置Syn thesizer 对象的属性
            利用getSynthesizerProperties 方法可以获得Synthesizer对象的属性,其返回值是与语音合成器相关联的SynthesizerProperties对象,该对象包含语音合成器的多种属性, 每种属性可以通过setProperties方法设置。例如: setSpeakingRate方法可设置speakingRate属性,实现每分钟朗读单词速率的控制。
    示例:
    SynthesizerP ropertiesproperties =
    speechSynthesizer1getSynthesizerP roperties();
    properties.setSpeakingRate(100.0f) ; //设置朗读速率,为浮点型数据
    ⑦事件处理程序设计
         speak ingRate 属性, 实现每分钟朗读单词速率的控制。完成应用程序界面中JButton“读出号码”的事件程序设计, 首先通过JComboBox(选择人名的下拉列表)取得人名(namesArray)的一个索引,该索引与电话号码索引(numbersArray)保持对应,然后调用Synthesizer对象speakingPlainText方法朗读整理后的电话号码字符串。下面是主要功能实现代码:
    private String[] namesArray = {“张三”,“王五”,“赵七”};
    private String [] numbersA rray = {“071328616661”,“13871990001”,“07136767555”};
    //部分界面设计代码, 省略
    //⋯⋯
    instruction.JLabel = new JLabel();
    instruction.JLabel1setBounds(16,8,264,23);
    //添加说明标签
    instruction.JLabel1setText(“请从下拉列表中选择一个姓名1”);
    contentPane.add(instruction.JLabel);
    //设计下拉列表JComboBox, 此处略
    //⋯
    instruction JLabel = new JLabel() ;
    instruction JLabel.setBounds(16,35,264,23) ;
    //添加说明标签
    instruction JLabel.setText (“单击按钮听号码朗读1”) ;
    contentPane1add(instruction JLabel) ;
    öö设计按钮JBut ton 以及其他界面, 此处略
    //⋯
    //编写按钮事件过程
    private void getPhoneN umberJButtonActionPerformed
    (ActionEvent event )
    {
     //获得下拉列表选定的索引
     int selectedName = nameJComboBox1getSelectedIndex();
     //设置朗读电话号码字符
    String textToSpeak = "sphone number is " + numbersArray[selectedName];
     //实现朗读
     speechSynthesizer.speakPlainText(textToSpeak,null);
    }
    3.其他说明
        开发者在验证或者运行该示例程序时需要注意运行环境的配置, 首先要安装好java2 软件包j2sdk,根据FreeTTS 的版本, j2sdk 至少应该为114版本,同时应对环境变量进行正确的设置。在程序设计中需要注意相关资源(如: Synthesizer对象) 的释放, 以使程序能够作为子模块高效运行,而不影响大型系统的整体性能。
    2.2 MCU(LPC2132)主控程序
        LPC2132 主控程序流程图如图3 所示,LPC2132首先初始化芯片ENC28J60初始化部分主要完成:软件复位;设定临时使用的以太网物理地址; 设定接收帧的类型;确定数据的传送方向;中断允许;使能接收中断;接收发送使能。LPC2132主要完成数据的解包打包。LPC2132从网络接收到数据报,则对数据报进行分析,如果是ARP数据包,则程序转入ARP处理程序。如果是IP数据包且使用UDP协议,端口正确,则将数据解包后通过串口输出。反之,如果LPC2132从串口收到数据,则将数据按照UDP 协议格式打包,送入ENC28J 60, 由ENC28J 60 把数据输出到局域网中。可以看出,链路层由ENC28J60 完成,TCP/IP 的网络层和传输层由LPC2132 来处理,而应用层则由用户根据需要进行数据处理。整个系统模块是通过UC/OS2II 来对系统资源进行有效管理并合理调度任务的。
    展开全文
  • Java——是否确实的 “面向对象”?让我们深入到Java的世界,试图来证实它。 在我刚开始学习 Java 的前面几年,我从书本里知道了 Java 是遵循 “面向对象编程范式(Object Oriented Programming paradigm)”的。...

    Java——是否确实的 “纯面向对象”?让我们深入到Java的世界,试图来证实它。

    在我刚开始学习 Java 的前面几年,我从书本里知道了 Java 是遵循 “面向对象编程范式(Object Oriented Programming paradigm)”的。在Java世界内一切都是对象,甚至包括字符串(String)这些都是对象(在 C 语言中,字符串是字符数组),那时候,我认为 Java是一种面向对象的语言。

    但是在后来,我在互联网站上陆续看到不少开发者说 “Java实际上不是纯粹的面向对象,因为并不是所有的东西在 Java 世界都是一个对象”。他们很多的论点都可以概括为以下两点:

    • 所有的静态内容( static 关键修饰的变量和方法)不属于任何对象,所以这些是非对象的东西。
    • 所有基本类型(char,boolean,byte,short,int,long,float,double)都不是对象,因为我们不能做类似正常对象的所具有的操作(例如:使用“.”来访问对象的属性和方法)。

    在那时,由于个人知识经验储备有限,我又很容地相信上面的论点,并且也开始认为 “Java 不是纯粹的面向对象编程语言”。

    到了更后来,在我的一次JVM学习过程中,我有了新的发现:

    JVM 在创建对象的时候,实际上会创建两个对象:

    • 一个是实例对象。
    • 另一个是Class 对象。该 Class 对象在JVM内仅仅会装载一次,该类的静态方法和静态属性也一同装载,JVM使用该 Class 对象来创建具体的实例对象(如上面的对象)。

    例如,在下面的 Java 语句中,将有两个对象被创建:

    Employee emp = new Employee();

    一个是实例对象 emp ;另一个则是 Class对象,我们可以通过 Employee.class 引用到它;这个 Class 对象拥有所有的这个类定义的静态变量和静态方法,同时,如果我们访问 通过 emp 对象来访问静态内容,会发现它其实指向的对象就是 Employee.class 。

    这也揭开了另一个迷:为什么静态内容在一个对象中(不管是emp还是emp2)改变了,在另一个对象中也同时改变,因为这两个对象改变的都是在 Employee.class 同一个对象里面的内容。

    现在,上面说到的第一个论点我们要取消了。因为,静态内容确实被证实属于一个对象。

    但是我们还要确认第二个论点:正如早前提到的,原始类型在Java中不是对象,它们无法做类似对象的操作。为了解决这个问题,Java 官方为每一个原始类型推出了对应的包装类(比如:Integer 对应 int,Long 对应 long,Character 对应 char),所以,其实现在我们可以为原始类型创建一个包装对象,同时对它们做对象相关的操作。并且,由于自动拆装箱,我们可以把一个原始类型值赋值给它对应的包装类的引用。但是我们仍然不能对这些原始类型做对象的操作——我们需要创建对应包装类的对象。

    例如:

    
     
    1. Integer obj = new Integer(5); // here we can do i.toString();

    2. int i = 5; // but we can't do i.toString() here

    到目前为止,从一个最终用户的角度上来看的,我们可以确认 “原始类别不是对象”。( Java开发人员是Java的最终用户,因为我们正在使用它,而不是创造它 )。

    如果站在JVM的视角,会有新的发现:

    其实,在JVM看来它把所有的 “原始类型” 都是当作对象处理” ,要证明这一点可以通过 Class类的源代码 或者 Javadoc中Class类的说明。

    根据 java.lang.Class 类的源代码,该类的注释是:

    Java官方描述:

    Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.

    参考译文:

    Class类的实例表示正在运行的Java应用程序的类和接口。像枚举是一种类和注解则是一种接口。每个数组也属于被反射作为由具有相同的元素类型和尺寸的数目的所有阵列共享一类对象的类。原始的Java类型(boolean, byte, char, short, int, long, float, and double)和关键字void也表示为Class对象。

    同时也根据Javadoc中对Class.isPrimitive()方法的定义,来判断

    Java官方描述:

    public boolean isPrimitive()
    Determines if the specified Class object represents a primitive type.
    There are nine predefined Class objects to represent the eight primitive types and void. These are created by the Java Virtual Machine, and have the same names as t he primitive types that they represent, namely boolean,byte, char, short, int, long, float, and double.
    These objects may only be accessed via the following public static final variables, and are the only Class objects for which this method returns true.
    Returns:
    true if and only if this class represents a primitive type
    Since:
    JDK1.1

    参考翻译:

    public boolean isPrimitive()
    判断指定的Class对象是否代表一个基本类型。
    一共有9种设定好的Class对象来表示对应的基本类型和void关键字。这些对象都是由JVM创建的。…
    return

    当且仅当该类表示一个真正的基本类型

    以上都说明,在JVM内部,其实原始类型就是对象。

    当你打开 Javadoc 对 Class 类的定义中,通过 “CTRL+F ” 查找关键字 “primitive”, 将会发现证据在表面 “在JVM里,它把基本类型当作对象来处理的”。

    我们可以再来看一个例子: Integer.TYPE,在这部分文档清晰记录着:

    Java官方描述:

    public static final Class<Integer> TYPE
    The Class instance representing the primitive type int.

    以上都说明,在JVM内部,其实原始类型就是对象。

    那么,既然说 “JVM”会为所有的基本类型创建一个对象,那我们为什么还那么常用 “原始类型”, 而不是直接使用对应的包装类对象呢?

    这是因为,为 “原始类型” 创建的对象,在JVM内部是很轻量级的,相对与我们直接创建的对应包装类对象做了许多优化; 也正因为轻量的缘故,这些原始类的功能就比较少(例如我们不能调用其内部的方法,因为他们内部已经优化成没有方法了)

    使用实际的例子来说明,为什么我们更应该使用 “原始类型”:

    “原始类型”有更快的速度(例如,下面的代码执行,在我们的机器上需要9秒,但当我把 Long 改成 long 之后,0秒内就完成了)

    public static void main(String[] args) {
        long millis = System.currentTimeMillis();
        Long sum = 0L; // uses Long, not long
        for (long i = 0; i <= Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
        System.out.println((System.currentTimeMillis() - millis) / 1000);
    }

    “原始类型”允许我们直接使用 “==”来进行比较

    
     
    1. new Integer(3) == new Integer(3); // false

    2. new Integer(100) == new Integer(100); // false

    3. Integer.valueOf(5) == Integer.valueOf(5); //true

    4. Integer.valueOf(200) == Integer.valueOf(200); //false

    我们注意看第四句,输出结果确实为 “false” 。这个是因在 [-128; 127] 这个区间的265个整数会被 JVM 缓存存放, 所以在这个区间, JVM返回相同的对象;然而,超出这个区间, JVM就不再有缓存了,将会创建新的对象,所以结果是不等的。

    所以总结一下是: 在JVM内部,原始类型就是被当作对象来处理的。但是我们开发者直接把 “原始类型” 当作对象使用,开发者应该使用对应的包装来。

    以上就是为什么我说 “ Java确实是一个纯粹的面向对象语言 ”的证实过程。如果你们对这个有什么其他的观点,请在评论留言,一起讨论。

    译文链接:http://www.codeceo.com/article/why-java-purely-object-oriented-language.html

    英文原文:Why Java Is a Purely Object-Oriented Language... Or Why Not
    翻译作者:码农网 – Dee1024

    展开全文
  • Java局域网通信——飞鸽传书源代码 28个目标文件 内容索引:JAVA源码,媒体网络,飞鸽传书 Java局域网通信——飞鸽传书源代码,大家都知道VB、VC还有Delphi的飞鸽传书软件,但是Java版的确实不多,因此这个Java...
  •  Java局域网通信——飞鸽传书源代码,大家都知道VB、VC还有Delphi的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
  • 语音识别技术概述与调研 语音识别已经成为人工智能应用的一个重点,通过语音控制设备简单方便,在各个领域兴起了研究应用的热潮。数据、算法及芯片是语音识别技术的3个关键,大量优质的数据、精准快速的算法和高性能...

    语音识别技术概述与调研

    语音识别已经成为人工智能应用的一个重点,通过语音控制设备简单方便,在各个领域兴起了研究应用的热潮。数据、算法及芯片是语音识别技术的3个关键,大量优质的数据、精准快速的算法和高性能语音识别芯片是提升语音识别的核心。语音是人工智能产品的主要入口,乃兵家必争之地也。相关算法研究日新月异,CNN RNN CLRNN HMM LACE等模型都尤其优势,将多种算法综合运用修改更佳。

    一、应用场景

    目前语音识别在智能家居、智能车载、智能客服机器人方面有广泛的应用,未来将会深入到学习、生活、工作的各个环节。国内外许多大公司都在倾力研究此技术,并不断推出实际产品。比如科大讯飞的翻译器译呗,可实现汉语与各种语言之间的互译,效果不错。
    百度借助自己的人工智能生态平台,推出了智能行车助手CoDriver。科大讯飞与奇瑞等汽车制造商合作,推出了飞鱼汽车助理,推进车联网进程。搜狗与四维图新合作推出了飞歌导航。云知声、思必驰在导航、平视显示器等车载应用方面推出了多款智能语控车载产品。出门问问则基于自己的问问魔镜进入到智能车载市场。
    在语音识别的商业化落地中,需要内容、算法等各个方面的协同支撑,但是良好的用户体验是商业应用的第一要素,而识别算法是提升用户体验的核心因素。下文将从语音识别的算法发展路径、算法发展现状及前沿算法研究三个方面来探讨语音识别技术。

    二、算法

    对于语音识别系统而言,第一步要检测是否有语音输入,即,语音激活检测(VAD)。在低功耗设计中,相比于语音识别的其它部分,VAD采用always on的工作机制。当VAD检测到有语音输入之后,VAD便会唤醒后续的识别系统。主要包括特征提取、识别建模及模型训练、解码得到结果几个步骤。
    首先,我们知道声音实际上是一种波。常见的mp3、wmv等格式都是压缩格式,必须转成非压缩的纯波形文件来处理,比如Windows PCM文件,也就是俗称的wav文件。wav文件里存储的除了一个文件头以外,就是声音波形的一个个点了。下图是一个波形的示例。
    在这里插入图片描述
    在开始语音识别之前,有时需要把首尾端的静音切除,降低对后续步骤造成的干扰。这个静音切除的操作一般称为VAD,需要用到信号处理的一些技术。要对声音进行分析,需要对声音分帧,也就是把声音切开成一小段一小段,每小段称为一帧。分帧操作一般不是简单的切开,而是使用移动窗函数来实现,这里不详述。帧与帧之间一般是有交叠的,就像下图这样:
    在这里插入图片描述
    图中,每帧的长度为25毫秒,每两帧之间有25-10=15毫秒的交叠。我们称为以帧长25ms、帧移10ms分帧。图中,每帧的长度为25毫秒,每两帧之间有25-10=15毫秒的交叠。我们称为以帧长25ms、帧移10ms分帧。
    分帧后,语音就变成了很多小段。但波形在时域上几乎没有描述能力,因此必须将波形作变换。常见的一种变换方法是提取MFCC特征,根据人耳的生理特性,把每一帧波形变成一个多维向量,可以简单地理解为这个向量包含了这帧语音的内容信息。这个过程叫做声学特征提取。实际应用中,这一步有很多细节,声学特征也不止有MFCC这一种,具体这里不讲。
    至此,声音就成了一个12行(假设声学特征是12维)、N列的一个矩阵,称之为观察序列,这里N为总帧数。观察序列如下图所示,图中,每一帧都用一个12维的向量表示,色块的颜色深浅表示向量值的大小。
    在这里插入图片描述
    接下来就要介绍怎样把这个矩阵变成文本了。首先要介绍两个概念:

    1. 音素:单词的发音由音素构成。对英语,一种常用的音素集是卡内基梅隆大学的一套由39个音素构成的音素集,参见The CMU Pronouncing Dictionary。汉语一般直接用全部声母和韵母作为音素集,另外汉语识别还分有调无调,不详述。
    2. 状态:这里理解成比音素更细致的语音单位就行啦。通常把一个音素划分成3个状态。
      语音识别是怎么工作的呢?实际上一点都不神秘,无非是:
      第一步,把帧识别成状态(难点);第二步,把状态组合成音素;第三步,把音素组合成单词。
      如下图所示:
      在这里插入图片描述
      图中,每个小竖条代表一帧,若干帧语音对应一个状态,每三个状态组合成一个音素,若干个音素组合成一个单词。也就是说,只要知道每帧语音对应哪个状态了,语音识别的结果也就出来了。图中,每个小竖条代表一帧,若干帧语音对应一个状态,每三个状态组合成一个音素,若干个音素组合成一个单词。也就是说,只要知道每帧语音对应哪个状态了,语音识别的结果也就出来了。
      那每帧音素对应哪个状态呢?有个容易想到的办法,看某帧对应哪个状态的概率最大,那这帧就属于哪个状态。比如下面的示意图,这帧对应S3状态的概率最大,因此就让这帧属于S3状态。
      在这里插入图片描述
      那这些用到的概率从哪里读取呢?有个叫“声学模型”的东西,里面存了一大堆参数,通过这些参数,就可以知道帧和状态对应的概率。获取这一大堆参数的方法叫做“训练”,需要使用巨大数量的语音数据,训练的方法比较繁琐,这里不讲。
      但这样做有一个问题:每一帧都会得到一个状态号,最后整个语音就会得到一堆乱七八糟的状态号,相邻两帧间的状态号基本都不相同。假设语音有1000帧,每帧对应1个状态,每3个状态组合成一个音素,那么大概会组合成300个音素,但这段语音其实根本没有这么多音素。如果真这么做,得到的状态号可能根本无法组合成音素。实际上,相邻帧的状态应该大多数都是相同的才合理,因为每帧很短。
      解决这个问题的常用方法就是使用隐马尔可夫模型(Hidden Markov Model,HMM)。这东西听起来好像很高深的样子,实际上用起来很简单:
      第一步,构建一个状态网络。
      第二步,从状态网络中寻找与声音最匹配的路径。
      这样就把结果限制在预先设定的网络中,避免了刚才说到的问题,当然也带来一个局限,比如你设定的网络里只包含了“今天晴天”和“今天下雨”两个句子的状态路径,那么不管说些什么,识别出的结果必然是这两个句子中的一句。
      那如果想识别任意文本呢?把这个网络搭得足够大,包含任意文本的路径就可以了。但这个网络越大,想要达到比较好的识别准确率就越难。所以要根据实际任务的需求,合理选择网络大小和结构。
      搭建状态网络,是由单词级网络展开成音素网络,再展开成状态网络。语音识别过程其实就是在状态网络中搜索一条最佳路径,语音对应这条路径的概率最大,这称之为“解码”。路径搜索的算法是一种动态规划剪枝的算法,称之为Viterbi算法,用于寻找全局最优路径。
      在这里插入图片描述
      这里所说的累积概率,由三部分构成,分别是:
      观察概率:每帧和每个状态对应的概率
      转移概率:每个状态转移到自身或转移到下个状态的概率
      语言概率:根据语言统计规律得到的概率
      其中,前两种概率从声学模型中获取,最后一种概率从语言模型中获取。语言模型是使用大量的文本训练出来的,可以利用某门语言本身的统计规律来帮助提升识别正确率。语言模型很重要,如果不使用语言模型,当状态网络较大时,识别出的结果基本是一团乱麻。

    三 、调研

    百度语音识别技术

    注册百度AI开放平台,点击左侧栏语音技术,在控制栏创建应用:百度AI平台
    在这里插入图片描述

    创建应用后记录如图三个字段信息。
    在这里插入图片描述

    1语音存储及识别

    相关文件:16k.pcm (百度ai平台下载)
    百度API提供两种类型的语音识别功能,故语音存储可有两种存储方式:

    1. 直接文件存储方式(数据库表存储文件名、类型、地址等信息)。
    2. 二进制存储方式。

    数据库配置及创建测试表

    spring.datasource.url=jdbc:mysql://localhost:3306/ass_test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=UTC
    spring.datasource.username=
    spring.datasource.password=
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    创建fileinfo表

    CREATE TABLE `fileinfo` (
     `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
    `filename` varchar(50) NOT NULL COMMENT '文件名',
    `filepath` varchar(50) NOT NULL COMMENT '文件路径',
    `filetype` varchar(50) NOT NULL COMMENT '文件类型',
    `filedata` MEDIUMBLOB  COMMENT '文件DATA',
    `creattime` datetime COMMENT '创建时间',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    

    Html demo.html:

    <html>
    	<head>
    	<script type='text/javascript'>
    	function spack(){
    		var wrapSpk = document.getElementById('wrapSpk');
    		var spkAudio=document.getElementById('spkAudio');
    		var spkText=document.getElementById('spkText').value;
    		wrapSpk.removeChild(spkAudio);
    		var spk1='<audio id="spkAudio" autoplay="autoplay">';
    		var spk2='<source src="http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=6&text='+spkText+'" type="audio/mpeg">';
    		var spk3='<embed height="0" width="0" src="">';
    		var spk4='</audio>';
    		wrapSpk.innerHTML = spk1+spk2+spk3+spk4;
    		var spkAudio=document.getElementById('spkAudio');
    		spkAudio.play();
    	}
    	function voiceToWord(){
    	window.location.href="http://localhost:8080/voice/voiceToWord";}
    	
    	if (document.createElement("input").webkitSpeech == undefined) {  
    		alert("很遗憾,你的浏览器不支持语音识别。");
    		}
    	else{
    		alert("尝试使用语言识别来输入内容吧");
    		}
    	</script>
    	</head>
    	<body>
    		<!--<input name="s" type="text" x-webkit-speech x-webkit-grammar="builtin:translate" />
    		<input x-webkit-speech lang="zh-CN" />
    		<input x-webkit-speech x-webkit-grammar="bUIltin:search" />
    	<form action="http://www.google.com/search" >
    		<input type="search" name="q" lang="zh-CN" x-webkit-speech x-webkit-grammar="builtin:search" onwebkitspeechchange="startSearch(event)"/>
    	</form>
    	-->
    	<div>
    		汉字转语音播放:<input type="text" id="spkText">
    		<input type="button" id="spkBtn" onclick="spack()" value="播放">
    	</div>
    	<div id="wrapSpk">
    		<audio id="spkAudio" autoplay="autoplay">
    			<source src="http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=6&text=" type="audio/mpeg">
    			<embed height="0" width="0" src="">
    		</audio>
    	</div>
    	<div id="wrapSpk">
    		<form action="http://localhost:8080/voice/receiveToHost" method="post" id="iconForm" enctype="multipart/form-data">
                            <table">
                         
                                <tr>
                                    <td>语音文件:</td>
                                    <td><input id="pcmFile" name="pcmFile" type="file" /></td>
                                    <td><input type="submit" value="上传到本地"/></td>
                                </tr>
                            </table>
                         
             </form>
    	</div>
    		<div id="wrapSpk1">
    		<form action="http://localhost:8080/voice/receiveToBase" method="post" id="iconForm1" enctype="multipart/form-data">
                            <table">
                                <tr>
                                    <td>语音文件:</td>
                                    <td><input id="pcmFile1" name="pcmFile1" type="file" /></td>
                                    <td><input type="submit" value="上传到数据库"/></td>
                                </tr>
                            </table>
                         
             </form>
    	</div>
    		<div id="wrapSpk2">
    		<form action="http://localhost:8080/voice/voiceToWordD" method="post" id="iconForm2" enctype="multipart/form-data">
                            <table">
                                <tr>
                                    <td>语音文件:</td>
                                    <td><input id="pcmFile2" name="pcmFile2" type="file" /></td>
                                    <td><input type="submit" value="直接识别"/></td>
                                </tr>
                            </table>
                         
             </form>
    	</div>
    	<div id="wrapSpk">
    			文件识别:<input type="button" id = "shibie" value="语音转文字" onclick="voiceToWord()"/>
    	</div>
    	</body>
    </html>
    

    百度链接客户端:

    在此之前,需要导入百度api的jar包。
    Mave配置:

     <dependency>
        <groupId>com.baidu.aip</groupId>
        <artifactId>java-sdk</artifactId>
        <version>4.1.1</version>
    	</dependency>
    	
    	<!-- jdbcTemplate -->
    	<dependency>
        	<groupId>org.springframework.boot</groupId>
        	<artifactId>spring-boot-starter-jdbc</artifactId>
    	</dependency>
     
    	<!-- MySQL连接 -->
    	<dependency>
        	<groupId>mysql</groupId>
        	<artifactId>mysql-connector-java</artifactId>
        	<scope>runtime</scope>
    	</dependency>
    

    客户端AipSpeechClient.java 代码示例:

    public class AipSpeechClient {
    	//设置APPID/AK/SK
        private static final String APP_ID = "";
        private static final String API_KEY = "";
        private static final String SECRET_KEY = "";
        
        public static AipSpeech AIPSPEECH=null;
    
        private static AipSpeechClient aipSpeechClient;
        
        private AipSpeechClient(){
        }
        
        public static AipSpeechClient getInstance(){
        	if(aipSpeechClient==null){
        		AIPSPEECH=new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
            	AIPSPEECH.setConnectionTimeoutInMillis(2000);
            	AIPSPEECH.setSocketTimeoutInMillis(60000);
        		aipSpeechClient = new AipSpeechClient();
        	}
    		return aipSpeechClient;
        }
    }
    

    或者创建配置类AppConfig.java,代码如下:

    @Configuration
    public class AppConfig {
    
    	//设置APPID/AK/SK
        private static final String APP_ID = "";
        private static final String API_KEY = "";
        private static final String SECRET_KEY = "";
        
        @Bean
        public AipSpeech aipSpeech() {
        	return new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
        }
    }
    

    Controller层用@Autowired注入。

    Controller类VoiceReceiveController.java:

    /**
     * 语音识别controller
     * 
     * @author zhangjx
     * @version 1.0
     * @since 2019-9-4
     */
    @RestController
    @RequestMapping("/voice")
    public class VoiceReceiveController {
    
    	public static final String path = "E:\\testFile\\";
    
    //	public AipSpeech client = AipSpeechClient.getInstance().AIPSPEECH;
    
    	public static final String filePath = "E:\\testFile\\16k.pcm";
    
    	@Autowired
    	public AipSpeech aipSpeech;
    
    	@Autowired
    	public JdbcTemplate jdbcTemplate;
    
    	/**
    	 * 测试demo,直接存入本地,业务环境需要创建表来存储文件名、文件类型及文件路径 此方法亦可存储其他类型文件
    	 * 
    	 * @param pcmFile
    	 * @param request
    	 * @return
    	 * @throws IOException
    	 */
    	@PostMapping(value = "/receiveToHost")
    	public String uploadToHost(MultipartFile pcmFile, HttpServletRequest request) throws IOException {
    		
    		long startTime = System.currentTimeMillis(); //获取开始时间
    
    		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    
    		MultipartFile file = multipartRequest.getFile("pcmFile");
    
    		savePic(file.getInputStream(), file.getOriginalFilename());
    
    		String sql = "insert into fileinfo (filename,filepath,filetype,filedata,creattime) values(?,?,?,?,?);";
    
    		jdbcTemplate.update(sql, file.getOriginalFilename(), path, file.getOriginalFilename().split("\\.")[1], null,
    				new Date());
    		long endTime = System.currentTimeMillis(); //获取结束时间
    		return "success!"+"程序运行时间:" + (endTime - startTime) + "ms";
    
    	}
    
    	/**
    	 * 测试demo,直接存入数据库,业务环境需要创建表来存储文件名、文件类型及文件路径 此方法也可以存储其他类型文件,文件大小不宜过大。
    	 * 
    	 * @param pcmFile
    	 * @param request
    	 * @return
    	 * @throws IOException
    	 */
    	@PostMapping(value = "/receiveToBase")
    	public String uploadToDatabase(MultipartFile pcmFile, HttpServletRequest request) throws IOException {
    		
    		long startTime = System.currentTimeMillis(); //获取开始时间
    
    		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    
    		MultipartFile file = multipartRequest.getFile("pcmFile1");
    
    		String sql = "insert into fileinfo (filename,filepath,filetype,filedata,creattime) values(?,?,?,?,?);";
    
    		jdbcTemplate.update(sql, file.getOriginalFilename(), "DATABASE", file.getOriginalFilename().split("\\.")[1],
    				file.getInputStream(), new Date());
    
    		long endTime = System.currentTimeMillis(); //获取结束时间
    		
    		return "success!"+"程序运行时间:" + (endTime - startTime) + "ms";
    
    	}
    
    	
    	/**
    	 * 测试demo,读取本地文件及二进制数据并识别。
    	 * 
    	 * @param pcmFile
    	 * @param request
    	 * @return
    	 * @throws IOException
    	 */
    	@GetMapping(value = "/voiceToWord")
    	public String voiceToWorld() throws IOException {
    		long startTime = System.currentTimeMillis(); //获取开始时间
    		// 文件读取方式,aipSpeech.asr()方法为多态方法,实际上都是调用的二进制方法,可自行查看api
    		JSONObject asrRes = aipSpeech.asr(filePath, "pcm", 16000, null);
    
    		long endTime = System.currentTimeMillis(); //获取结束时间
    		
    		return asrRes.get("result").toString()+"程序运行时间:" + (endTime - startTime) + "ms";
    
    	}
    
    	/**
    	 * 测试demo,上传文件直接识别。
    	 * 
    	 * @param pcmFile
    	 * @param request
    	 * @return
    	 * @throws IOException
    	 */
    	@PostMapping(value = "/voiceToWordD")
    	public String voiceToWorldDirect(MultipartFile pcmFile, HttpServletRequest request) throws IOException {
    		
    		long startTime = System.currentTimeMillis(); //获取开始时间
    		
    		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    
    		MultipartFile file = multipartRequest.getFile("pcmFile2");
    		
    		JSONObject asrRes = aipSpeech.asr(file.getBytes(), "pcm", 16000, null);
    		
    		long endTime = System.currentTimeMillis(); //获取结束时间
    
    		return asrRes.get("result").toString()+"程序运行时间:" + (endTime - startTime) + "ms";
    
    	}
    	/**
    	 * 测试demo,文件流
    	 * 
    	 * @param inputStream
    	 * @param fileName
    	 * 
    	 */
    	private void savePic(InputStream inputStream, String fileName) {
    
    		OutputStream os = null;
    		try {
    			byte[] bs = new byte[1024];
    			int len;
    			File tempFile = new File(path);
    			if (!tempFile.exists()) {
    				tempFile.mkdirs();
    			}
    			os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
    			while ((len = inputStream.read(bs)) != -1) {
    				os.write(bs, 0, len);
    			}
    
    		} catch (IOException e) {
    			e.printStackTrace();
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				os.close();
    				inputStream.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    测试方法:

    启动springboot。
    浏览器打开html。
    在这里插入图片描述
    依次进行测试并查看数据库及配置的存储位置。
    文件上传响应结果:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    文件存入数据库响应结果:
    在这里插入图片描述
    在这里插入图片描述
    直接识别结果:
    在这里插入图片描述
    文件识别结果:
    在这里插入图片描述
    注意事项:
    1、 上传需要完整的录音文件,录音文件时长不超过60s。
    2、 系统默认为普通话模式,本次调用为非极速模式语音输入法。
    3、 原始 PCM 的录音参数必须符合 16k 采样率、16bit 位深、单声道,支持的格式有:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)。
    4、 上传文件亦适用其他类型文件上传,数据库存储方式不适合大文件存储,系统设置为16M限制。
    5、 本次测试基于springboot进行,demo中的AppID、API Key、Secret Key需自行申请。
    6、 错误码
    在这里插入图片描述
    7、 接口函数说明
    在这里插入图片描述

    2、资费标准

    语音识别极速版价格

    语音识别极速版采用分段阶梯定价方式,调用单价按照自然月累积调用量所落阶梯区间而变化。月初,上月累积的调用量清零,重新开始累积本月调用量。 每账号前50000次调用免费,免费额度用尽后开始计费,价格如下:

    月调用量(万次) 语音识别极速版(元/次)
    0<调用次数<=600 0.0042
    600<调用次数<=3000 0.0036
    3000<调用次数<=6000 0.0029
    6000<调用次数<=15000 0.0019
    15000<调用次数 0.0014

    语音识别价格

    语音识别包含输入法、搜索、粤语、英语、四川话、远场模型。可按天/月购买QPS。价格如下:

    QPS购买方式 单价(元)
    1QPS/天 80
    1QPS/月 1400
    1QPS/年 12000

    说明:若原有QPS默认配额为2,则购买10QPS/月后,该月QPS提升至12。不限调用量。

    免费额度

    接口服务 免费调用量额度 QPS限额 计费模式
    语音识别 不限制 默认2-10QPS(可通过企业认证提升) 可购买提升QPS
    语音识别极速版 每账号共50000次 默认5QPS;开通付费后提升至50QPS 按调用量阶梯计费
    注:成功调用与失败调用均算作一次调用,消耗免费额度。
    个人创建的应用控制台,企业认证QPS值为10.
    在这里插入图片描述

    其他语音识别平台资费

    科大讯飞

    调用方法类似于百度api。
    计费标准:
    在这里插入图片描述
    优点:
    1、 支持语种多。
    2、 支持长时间录音识别(5小时内)。
    3、 转换精度高。
    缺点:
    1、 付费。

    腾讯

    企业认证10QPS,个人认证2QPS。
    优点:
    1、 免费。
    2、 提供多版本语音识别技术,如语音识别-echo版,语音识别-流式版(AI Lab),语音识别-流式版(WeChat AI),流式版可做到边录编译。
    缺点:
    1、 echo版单次请求上限15s,只支持普通话。
    2、 AI Lab及WeChat AI只支持普通话。

    阿里

    1. 语音数据处理费用

    • 实时语音识别服务,按照处理的语音时长计费,可以自助开通后付费或购买预付费资源包。
    • 一句话语音识别服务,按照调用次数计费,可以自助开通后付费或购买预付费资源包。
    • 录音文件识别服务,按照录音时长计费,可以自助开通后付费或购买预付费资源包。
    • 语音合成服务,按照调用次数计费,可以自助开通后付费或购买预付费资源包。

    2. 附加产品费用

    • 超额并发线路费用,商用客户默认提供200路并发,如果客户业务量较大超过200路的,可以自助购买额外并发线路
    • 文本自学习定制模型,用于提高客户业务领域的名词句子识别率,可以自助开通

    3.计费方式和报价

    预付费方式

    在这里插入图片描述
    注意:预付费资源包的有效期是购买之日起1年以内

    后付费方式

    按天结算,量大优惠,随调用量增加梯度报价。
    在这里插入图片描述

    计费细则

    试用版:
    • 目前试用版不计费,您可免费试用,如有变化,请关注官网通知;
    • 一句话识别、实时语音识别、语音合成在2个并发内每个自然日使用量不限;
    • 录音文件识别每个自然日识别时长不超过2小时;
    商用版:
    • 如果您需要超过2个并发或更大量的录音文件识别接口的时长使用,请您开通商用版;
    • 开通商用版之后,默认为后付费模式。购买预付费资源包之后,自动变更为预付费模式,并使用资源包内资源进行抵扣,当预付费资源包内资源使用完之后,会再次变更为后付费模式;
    • 商用版(包括预付费模式和后付费模式)按每个自然日实际使用量计费,无免费额度,不使用则不产生费用,若使用则每天结算。北京时间每晚24点,系统将自动对您当天用量进行全量计算和计费,具体账单生成会有延迟;
    • 计费规则:

    1. 按时长计费的,会累加每次调用的语音时长(按秒向下取整,如本次发送的语音长度22.8秒,则记为22秒)。
    2. 按照次数计费的,返回失败的调用不会计入次数。
    3. 计费总额按照当天24点总体用量最后达到的梯度价格进行全量计费,例如一句话识别当天达到500千次调用量,则当日扣费500*3.0元(300-999千次阶梯价格)=1500.0元。
    4. 语音合成的计费调用次数按照每次请求中传入的字符数(UTF-8编码,以下字符数均以此编码为准。1个汉字、英文字母、全半角标点符号均算1个有效字符)作为统计依据:100个字符以内(含100个字符)记为1次计费调用;每超过100个字符则多记1次计费调用,且1次请求最多传入300个字符。例如,102个字符记为2次计费调用,201个字符记为3次计费调用,依此类推。(2019年6月10日零点前开通预付费或后付费的商用版客户,将于2020年6月9日24点开始自动调整为新规格的计费方式。)

    并发数计算

    并发数指同一个账号同时在处理的请求数。
    一般语音请求的处理都会延续一段时间,例如用户新建一个语音识别请求,持续发送语音数据给服务端,这时并发数就是1;在这个请求处理的同时,这个用户又新建了另一个请求,开始发送语音数据,这时服务端在处理这个账号的2个请求,并发数就变成2。

    超额并发线路

    在这里插入图片描述
    优点:
    1、 识别准确率高。
    2、 超快的解码速率。
    3、 独创的模型优化工具。
    4、 广泛的领域覆盖。
    缺点:
    1、付费。

    展开全文
  • JMF--视频通话篇

    2011-03-28 18:38:00
    Java媒体框架(JMF):该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作音频流和视频流。 这里只是说模拟视频通话的过程,而关于JMF的学习介绍请另见其他...

      Java媒体框架(JMF):该核心框架支持不同媒体(如:音频输出和视频输出)间的时钟同步。它是一个标准的扩展框架,允许用户制作纯音频流和视频流。

      这里只是说模拟视频通话的过程,而关于JMF的学习介绍请另见其他文章。

      2.

    JMF在处理对媒体数据方面体现了很强的功能,MyQQ的制作在这学期的前段时间已经完成了视频通话功能的模拟。语音聊天不太直观,无法截图,但其原理也和视频通话一样,只是处理的数据流不同而已。

    视频聊天的过程如下:

      1.服务器VideoListener监听视频聊天请求

      (2)收到用户A请求后(A把自己的Ip和端口发给服务端)

      (3)客户端线程接收服务端发来的信息。根据信息的不同进行处理,需要处理的基本信息可能有:a.请求视频 b.撤销视频请求 c.同意视频通话 d.不同意视频通话
     
      比较服务端所有的连接

        如果用户名B和用户A请求的用户名B一样就向该用户发送用户请求,再读取用户B的回应,

        如果用户B同意语音或者视频聊天,通知用户A,此时两用户都启动两个类,一个是发送并播放自己画面的类,另一个是等待接收对方的视频流或者音频流,收到即播放。

        如果用户B不同意,将结果发回给用户A,结束此次请求

       传输过程采用RTP协议,可以处理多道数据流(混合数据流),例如可以把音频和视频流一起传输过去,在接收方接收到数据流时再进行处理,分出音频流和视频流,就可以实现在视频的同时进行语音聊天了。

     3.

    下面模拟视频通话的过程:

    (1) 视频服务器监听截图

    (2)模拟一个ll用户登录

    (3)模拟一个用户ss登录

    (4)ss回应ll的视频截图   

                             

    (5)ll申请与ss视频聊天反馈信息截图

    (6)ss接受ll聊天请求,显示本地视频并传送数据流截图

    (7) 用户ll接到ss传来的数据流,处理并播放数据流

     

      4.  

      还有一些问题没有解决,例如因为视频设备只能供一个用户使用,如果一台机器登录两个用户,并且他们都要和其他好友视频通话,就会产生抢资源的现象,这个问题依然没有解决。还有一个比较突出的是:如果一个用户同时和多个用户视频通话,上面的情况依然会发生,虽然查到资料说可以采用克隆数据源的办法来解决这个问题,但是几经尝试仍未果。腾讯QQ可以解决这样的问题,但是它究竟怎么实现的我们却不得而知。

      上面两个是比较突出的问题,如果你有解决的办法,请留下你的想法。

         5.

          如果需要代码请到CSDN下载(の,貌似CSDN有个毛病,就是刚上传的东西查看不到,所以我也不能给出网址了)-----现在可以了,http://download.csdn.net/source/2220344

     

    展开全文
  • 阿里巴巴,三面,java实习 昨天晚上11点打电话来,问我可以面试不,我说不可以,然后就约到了今天, 1.上来问我项目用的框架,然后问我springmvc里面有的参数的设定,问的是细节,然后问我如果传的多个值是一个...
  • Java是计算机编程语言中应用最广泛的计算机编程语言,从Java在IT领域中站稳脚跟以来,就没有编程语言可以从Java应用中分羹。为什么这么说呢?因为Java语言既能写前端,也能写后端。 其实,Java总的来说算是后端开发...
  • Java 的语言是一种比较简单的语言,与常用的c++简洁很多,并且提高可靠性。J同时ava语言是一种特殊的高级语言,它既具有解释型语言的特4征,也具有编译型语言的特征。因为java程序先编译后解释的过程。 注释:在...
  • 对于很多想从事Java开发的人来说,都会有这样一个疑问,纠结是直接参加培训机构还是选择自学的问题。其实在我们过来人(已经做了几年的Java工作)的角度看问题就非常简单,一定要选择自学,而不是选择参加速成的培训...
  • 在国内我找到了一个比较好音视频通信解决方案,该案例提供了纯Java语言接口供我们调用,随后我参照官方android demo程序和开发文档并结合自己的见解写了一个android音频通信软件,200行以内代码就搞定了(难以相信吧...
  • 2.4机器学习应用流程我们已经了解了机器学习的方法,以及这些方法是如何识别模式的。这一节里,我们会学习使用机器学习挖掘数据时该选择或者必须选择哪一套学习流程。每一种机器学习方法都会依据模型参数设置决策...
  • Android studio创建java项目 一、前言 以前用习惯了eclipse写java项目和android项目,后来因为主攻Android,使用的ide便从eclipse逐渐转移到了Android studio(下面简称as),于是乎很长一段时间内一直使用as做...
  • Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用Java。另一方面,Java丢弃了C++中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,Java...
  • Java Swing学习

    2019-11-15 19:37:45
    内容来源于《java语言程序设计》(郎波著)以及一些个人理解。 文章目录一、JFC 简介二、Swing简介三、Swing组件类层次 一、JFC 简介 JFC(Java Foundation Classes,Java基础类库)是Java平台的一个重要组成...
  • 从零开始搭建一个语音对话机器人 目录 01-初心缘由 02-准备工作 03-语音机器人的搭建思路 04-语音生成音频文件 05-音频文件转文字STT 06-与图灵机器人对话 07-文字转语音 08-语音对话机器人的完整代码 09-...
  • 1. SRS(simple rtmp service) srs之深入浅出看流媒体 - CSDN博客 http://blog.csdn.net/zjqlovell/article/details/50786040 SRS产品规划 https://github.com/ossrs/srs/wiki/v1_CN_Product SRS2.0 home ...
  • JAVA与GUI

    2016-02-05 10:13:02
     最近在维护公司的老项目,居然还在用Java Swing做客户端工具,如下图:  从第二张图片的版本号可以看出来,这个老家伙是2014年的产物,而且很可能之后一直没有更新过。但是没办法,老项目需要人维护,只有硬着...
  • 机器学习和算法优化。  噪声问题一直是语音识别的一个老大难的问题,在理想的实验室的环境下,识别效果已经非常好了,之前听很多音频算法工程师抱怨,在给识别做降噪时,经常发现WER不降反升,降低了识别率,...
1 2 3 4 5 ... 20
收藏数 3,368
精华内容 1,347
关键字:

java学习纯语音版