离线文字转语音识别

2018-09-27 11:05:52 weixin_43112746 阅读数 9550

#用java调用科大讯飞的离线语音识别dll实现离线识别(JNA实现)(一)

本人接的任务,做离线语音识别,用的是科大讯飞的离线识别,java不支持离线了,所以下载了windows的离线包,用JNA进行调用。之前用的是jni,但是一直没有测试通过,本人又不会C++,研究了一个星期终究放弃。转而使用JNA,JNA使用只要导入一个jar包即可,JNA实际上是对JNI的一种封装。

【在线语音识别的实现看我的另一篇】科大讯飞 在线语音识别 音频来源为【文件】的java接入实现, 适用于初学者

说明

本人一边做一边写,记录问题和解决办法,留给自己思考和大家交流。如有不对的地方,欢迎批评指正!
【ps】现在已经做完,参考第二篇

一、注册用户,下载dll这个先略过,很简单,可以参考其他的……【待】
1、先进入讯飞开放平台,先注册【地址】https://www.xfyun.cn/
2、创建应用,记得平台选windows,因为java不支持离线
在这里插入图片描述

3、创建完成之后,在 我的应用 中
在这里插入图片描述

选择【离线命令词识别】
就完成创建了!

4、下载需要的SDK,这个SDK包含了动态库dll,静态库lib,头文件.h,以及非常重要的例子!
在这里插入图片描述
【点亮需要的功能,下载相应的SDK】
在这里插入图片描述
下载好之后,找出其中的dll文件,两个版本,上面是32位系统,下面是64位系统,本人是64位的
在这里插入图片描述

二、调用JNA
1下载jna的jar包
【JNA包下载地址】:https://download.csdn.net/download/weixin_43112746/10690193

2导入java工程中
在这里插入图片描述
jar包的位置,可以放在根目录,也可以像我一样创立一个lib文件夹来放置
然后
右键工程–properties—java Build Path----libraries—add jars
在这里插入图片描述
【找到相应的JNA包的位置,添加之后点击Apply and Close】就完成JNA包的导入
【JNA包下载地址】:https://download.csdn.net/download/weixin_43112746/10690193

没有做过的,先加载个例子试试!
在这里插入图片描述

创建一个class,一个interface,下面的是讯飞的dll文件放在根目录下
【接口】这里只测试登录的函数

package test;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;

public interface VoiceLib extends Library {
	  int MSPLogin(String usr, String pwd, String params);
	  VoiceLib instance = (VoiceLib)Native.loadLibrary("msc_x64", VoiceLib.class);//接口直接对动态库文件进行调用,
	  //省去JNI的繁琐步骤
		

}

【类】
package test;

import com.sun.jna.Native;

public class Voice {
		public static void main(String[] args) {
		String usr=null;
		String pwd=null;
		String params="appid=5ba4bc08";//这里填写自己的appid,从讯飞的我的应用里面粘贴过来
		int a;
		a=VoiceLib.instance.MSPLogin(usr, pwd, params);//调用接口的方法传参数
		System.out.println(“a=+a);
		
		
	}
}




输出结果a=0
很明显测试成功了!
能够继续往下写了。

又遇到问题,参数的转换!
普通的倒是还好,转换关系如下:
在这里插入图片描述
来源:https://github.com/java-native-access/jna/blob/master/www/Mappings.md
可是问题来了,讯飞中有指针,句柄,回调函数等等各种乱七八糟的参数,这可怎么转换?头顶一直乌鸦飞过……

三、参数的转换(难点)
登录做完了,再做构建语法,其中用到的函数是

int MSPAPI QISRBuildGrammar(const char *grammarType, const char *grammarContent, unsigned int grammarLength,
 const char *params, GrammarCallBack callback, void *userData);

除了无符号int那个,其他都没有!又一只乌鸦飞过……
竟然还有语法回调函数!这是什么!又一只乌鸦飞过……
查一下回调函数
【百度】这是个链接哈

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

找个资源帖参考下:
https://blog.csdn.net/l527719041/article/details/77461328

哦!原来可以这么操作!

先把const char *解决,这是要转换成String 【待】

再来解决回调函数的参数问题!
【先做这么多,下回分解】
第二篇的链接:手把手的操作——用java调用科大讯飞的离线语音识别dll实现离线识别(JNA实现)(二)

2014-10-13 21:56:14 u011747781 阅读数 4509

最近做项目,用到离线语音识别,整了好久,查了好多方法,终于完成,网上资料有点乱,而且大部分就是那几个人写的,一群人转!下面我总结一下,也为后来人行个方便。


关于环境配置我就不多说了,我就是按照这个教程一步步来的,绝对是可行的。http://gaebolg.blog.163.com/blog/static/19826906820136232810723/



下面重点讲解一下demo的运行和语音库的配置(注意:上面那个教程的运行demo最后写的一塌糊涂,可以从拷贝声学模型和语音库那里开始看我的!)


首先,demo运行需要以下文件:pocketsphinx/model/en_US lm文件夹( .dic文件, .lm文件),以及hmm文件夹。如果觉得麻烦可以下载我提供的文件。http://download.csdn.net/detail/u011747781/8034061


下面进入重头戏,就是如何设置属于自己的中文语音库:

1、编写自己的命令集:

新建一个txt文件,输入命令,如:


百度
谷歌

点击文件,另存为,注意将编码改为UTF-8格式!(正下方编码选项)保存为txt文件。

2、利用在线工具http://www.speech.cs.cmu.edu/tools/lmtool.html将写好的txt文件生成文件。下载tgz文件即可(里面有所有文件),复制tgz压缩包中的lm文件,因为只有这个有用(如果是英语的话,dic文件可以直接用,就不用我下面介绍的方法生成dic文件了!!)


3、新建一个txt文件。在我给的data文件夹里,有个叫做standard.dic的文件,那个是标准语音库,ctrl+F 查找你需要的发音,复制到你新建的txt文件中。

格式如下:

百度 b ai d u

完事后存为UTF-8格式,改名为 .dic文件。


4、这样属于你的语音库就建好了,只需覆盖我的data文件夹中相应的dic , lm文件 即可!


最后,奉上亲测可用的完整demo  http://download.csdn.net/detail/u011747781/8034195


2020-05-12 17:07:53 qcmy980 阅读数 56

文字转语音函数介绍

 

接口采用C语言编写,支持各种语言调用。

其他详细文档联系QQ :1481662712

2019-07-05 11:16:50 feiyunjs 阅读数 836
 //此代码由飞云脚本圈整理提供(www.feiyunjs.com)
importPackage(android.speech.tts);
importClass(java.util.Locale);

auto();

var tts = new TextToSpeech(context, function(status){
    if(status != tts.SUCCESS){
        toast("初始化TTS识别: " + status);
        exit();
    }
    var r = tts.setLanguage(Locale.CHINA);
    if(r < 0){
        toast("不支持该语言: " + r);
        exit();
    }
    toast("TTS初始化成功");
});
tts.setOnUtteranceProgressListener(new UtteranceProgressListener({
    onDone: function(id){
        //stopQQVoiceRecord();
        //voiceConverting = false;
    }
}));

function 文本记录(text){
    开始录音();
    sleep(1000);
    (text);
    voiceConverting = false;
}

function 开始录音(){
     toast("请开始录音!");
     sleep(2000);
}

function (text){
    tts.speak(text, tts.QUEUE_ADD, null);
}

events.on("exit", function(){
    if(tts){
        tts.shutdown();
        tts = null;
    }
});



var window = floaty.window(
    <frame>
        <linear>
            <button id="action" text="TTS" w="40" h="40" color="#ffffff" bg="#66000000" />
        </linear>
    </frame>
);

var voiceConverting = null;

//记录按键被按下时的触摸坐标
var x = 0, y = 0;
//记录按键被按下时的悬浮窗位置
var windowX, windowY;
//记录按键被按下的时间以便判断长按等动作
var downTime;
window.action.setOnTouchListener(function (view, event) {
    switch (event.getAction()) {
        case event.ACTION_DOWN:
            x = event.getRawX();
            y = event.getRawY();
            windowX = window.getX();
            windowY = window.getY();
            downTime = new Date().getTime();
            return true;
        case event.ACTION_MOVE:
            //移动手指时调整悬浮窗位置
            window.setPosition(windowX + (event.getRawX() - x),
                windowY + (event.getRawY() - y));
            //如果按下的时间超过1.5秒判断为长按,退出脚本
            if (new Date().getTime() - downTime > 1500) {
                exit();
            }
            return true;
        case event.ACTION_UP:
            //手指弹起时如果偏移很小则判断为点击
            if (Math.abs(event.getRawY() - y) < 5 && Math.abs(event.getRawX() - x) < 5) {
                点击();
            }
            return true;
    }
    return true;
});





var thread = threads.currentThread();

function 点击() {
    log("点击");
    thread.setTimeout(qqMessageToVoice, 0);
}

function qqMessageToVoice(){
    if(voiceConverting){
       return;
    }
    voiceConverting = true;
    var input = rawInput("请输入一段话");//id("input").className("EditText").findOne();
    log("开始转换: ", input);
    文本记录(input);
    //input.setText("");
}

setInterval(()=>{}, 1000);

说明

本文提供的代码仅供参考。
可能有些地方在最新版本的Auto.js上面需要做修改,才能运行。

Auto.js简介

Auto.js是利用安卓系统的“辅助功能”实现类似于按键精灵一样,可以通过代码模拟一系列界面动作的辅助工作。
与“按键精灵”不同的是,它的模拟动作并不是简单的使用在界面定坐标点来实现,而是类似与win一般,找窗口句柄来实现的。

Auto.js使用JavaScript作为脚本语言,目前使用Rhino 1.7.7.2作为脚本引擎,支持ES5与部分ES6特性。

开发文档

Auto.js Pro开发文档优化版
文档尚在完善中,可能有文档描述和代码实际行为有出入的情况。
模板、样式、generator来自Node.js。

为什么要使用Auto.js Pro开发脚本,有什么特点?

吸引我使用Auto.js Pro的原因有很多。最主要的几个原因是:

  • Auto.js Pro能开发免ROOT的安卓脚本
  • Auto.js Pro基于节点操作,能开发全分辨率的脚本,自动适配各种安卓机型
  • Auto.js Pro丰富的UI组件,能自定义各种样式的安卓界面
  • Auto.js Pro使用的javascript的语法比较优雅,代码可读性强
  • Auto.js Pro的命令库非常的丰富,接口比较多
  • Auto.js Pro脚本文件体积比较小。1000行的代码,打包后的apk文件只有3-5M,还没有广告

相关教程

Auto.js Pro安卓全分辨率免ROOT引流脚本开发教程

2013-08-26 19:11:13 wojiao555555 阅读数 3986

开始做这个的时候,从网上当了一段代码,但后来测试老是提示没有找到设备。。。非常烦人。。。

经过多方查找资料,发现需要装一个Google语音的插件,运行语音识别的时候要用到。如果没有就提示没有找到设备。

下载地址:http://download.csdn.net/detail/wojiao555555/6014985

代码如下:

public class RecognizerIntentActivity extends Activity {

	private Button btnReconizer;
	private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.reconizer);
		
		btnReconizer=(Button) this.findViewById(R.id.btnRecognizer);
		btnReconizer.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				try{
				//通过Intent传递语音识别的模式,开启语音
				Intent intent=new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
				//语言模式和自由模式的语音识别
				intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
				//提示语音开始
				intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "开始语音");
				//开始语音识别
				startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
				}catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
					Toast.makeText(getApplicationContext(), "找不到语音设备", 1).show();
				}
			}
		});
		
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		//回调获取从谷歌得到的数据 
		if(requestCode==VOICE_RECOGNITION_REQUEST_CODE && resultCode==RESULT_OK){
			//取得语音的字符
			ArrayList<String> results=data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
			
			String resultString="";
			for(int i=0;i<results.size();i++){
				resultString+=results.get(i);
			}
			Toast.makeText(this, resultString, 1).show();
		}
		super.onActivityResult(requestCode, resultCode, data);
	}
}


上边的那个需要连网,因为是把语音信号发送到google服务器上进行比对、识别的。所以这次打算弄个离线的demo,就是开着航班模式也能识别的。demo。

参考如下:

http://www.cnblogs.com/yin52133/archive/2012/07/12/2588201.html#2611619

代码可以从这里下载:

http://download.csdn.net/detail/wojiao555555/6015003