admin管理员组

文章数量:1562652

上一篇的地址手把手的操作——用java调用科大讯飞的离线语音识别dll实现离线识别(JNA实现)(一)

上一篇讲到了最难的地方,参数的转换,这里单独写出来
**

三、参数的转换(难点)

**
注:本文是以讯飞提供的C语言例子作为模板改写,语音来源于文件
1、先分析提供的例子
本人使用的是VS2010
下载链接链接:https://pan.baidu/s/1CZX3k6nhsbLkuzB3mocyww 提取码:6r5g
2.45G大小,需要安装一段时间,因为用JNA只用看,这个版本够了
【为了给我一样对C/C++不了解的初阶,大神轻喷】

运行之后
【文件】–【打开】–【项目/解决方案】–自己找文件位置–【asr_offline_sample.vcxproj】

同样的方法打开头文件
【文件】–【打开】–【文件】–自己找文件位置–【头文件.h结尾的】

主要看例子asr_sample.c
在java中主要就是将这个文件进行改写,所以要先看懂
我自己看了很久,讲下结构吧:
上面几个是各项功能的函数,最下面是主函数main,跟java的结构很像吧
几大主要功能
【登录】
【建立语法】
【建立词典】
【语音识别】
【退出】

看上去很简单啊,接下来就是一个一个在java中实现
我先建立了一个lib接口,里面放调用的东西
(先把动态库加载进来)

public interface VoiceLib extends Library{
   
	VoiceLib instance = (VoiceLib)Native.loadLibrary("msc_x64", VoiceLib.class);
	}

#1登录
这个功能在(一)中已经有例子了,这里重写一遍就好

public interface VoiceLib extends Library{
   
	VoiceLib instance = (VoiceLib)Native.loadLibrary("msc_x64", VoiceLib.class);
	int MSPLogin(String usr, String pwd, String params);
	}

新建主类xMsc
改写登录功能

	public static void main(String[] args) {
   
		String login_config = "appid=5ba4***"; //登录参数
		UserData asr_data=null ;
		int ret             = 0;
		ret = VoiceLib.instance.MSPLogin(null, null, login_config); 
		//第一个参数为用户名,第二个参数为密码,传null即可,第三个参数是登录参数
		if (MSP_SUCCESS!= ret) {
   
			System.out.println("登录失败!");
			exit();
		}
		}

上面先改写下几个常量:

public class xMsc {
   

public static final int SAMPLE_RATE_16K = 16000;
	public static final int SAMPLE_RATE_8K = 8000;
	public static final int MAX_GRAMMARID_LEN = 32;
	public static final int MAX_PARAMS_LEN = 1024;

	public static final int MSP_SUCCESS = 0;
	public static final int MSP_FAILED = 1;
	private static int MSP_AUDIO_SAMPLE_FIRS = 1;
	private static int MSP_AUDIO_SAMPLE_CONTINUE = 2;
	private static int MSP_EP_LOOKING_FOR_SPEECH = 0;
	private static int MSP_REC_STATUS_INCOMPLETE = 2;
	private static int MSP_EP_AFTER_SPEECH = 3;
	private static int MSP_AUDIO_SAMPLE_LAST = 4;
	private static int MSP_REC_STATUS_COMPLETE = 5;
	
	private static File f_pcm 		 = null;
	private static byte[] pcm_data	 =null;
	private static int errcode		 = -1;
	private static String session_id = "";
	private static IntByReference ep_status  = new IntByReference(MSP_EP_LOOKING_FOR_SPEECH);
	private static IntByReference rec_status = new IntByReference(MSP_REC_STATUS_INCOMPLETE);
	private static IntByReference rss_status1 = new IntByReference(MSP_AUDIO_SAMPLE_FIRS);
	private static IntByReference err 		  = new IntByReference(errcode);

	public static final String ASR_RES_PATH = "fo|common.jet"; // 离线语法识别资源路径
	public static final String GRM_BUILD_PATH = "./msc/GrmBuilld_x64"; // 构建离线语法识别网络生成数据保存路径
	public static final String GRM_FILE = "./source/szx.bnf"; // 构建离线识别语法网络所用的语法文件
	public static final String LEX_NAME = "contact"; // 更新离线识别语法的contact槽(语法文件为此示例中使用的call.bnf)
	


里面的路径必须要跟我一样,尤其是 ASR_RES_PATH ,前面必须加"fo|"
有几个文件要拷贝过来啊,语法文件之类,我建立了一个source文件夹,都放里面了
现在的结构

【先一口气把main里面的全部改写完吧!】

public static void main(String[] args) {
   
		String login_config = "appid=5ba4*****"; //登录参数,要改成自己的
		asr_data = new UserData();
		int ret = 0;
		ret = VoiceLib.instance.MSPLogin(null, null, login_config); // 第一个参数为用户名,第二个参数为密码,传null即可,第三个参数是登录参数
		if (MSP_SUCCESS != ret) {
   
			System.out.println("登录失败!");
			exit();
		}
		System.out.println("登录成功!");
		System.out.println("构建离线识别语法网络...\n");
		ret = build_grammar(asr_data); // 第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建

		if (MSP_SUCCESS != ret) {
   
			System.out.println("构建语法调用失败!\n");
			exit();
		}
		while (MSP_FAILED != asr_data.build_fini) {
   
			try {
   
				Thread.sleep(1);
			} catch (InterruptedException e) {
   
				e.printStackTrace();
			}
		}

		if (MSP_SUCCESS != asr_data.errcode) {
   
			exit();
		}

		System.out.println("离线识别语法网络构建完成,开始识别...\n");
		ret = run_asr(asr_data);
		if (MSP_SUCCESS != ret) {
   
			System.out.println("离线语法识别出错: \n");
			exit();
		}
	}

【注】词典我删掉了,和构建语法一样,需要的自己写喽

¥¥¥¥¥退出功能先封装一下¥¥¥¥¥¥

public static void exit(){
		VoiceLib.instance.MSPLogout();
		System.out.println("请按任意键退出...\n");
		
	}

【再来一口气】把要用的函数全部封装到VoiceLib中,等下直接调用


import com.sun.jna.Library;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.szxinfo.recognizer.CallbackUtil.GrammarCallBack;



public interface VoiceLib extends Library{
   
	String filePath = "mscx64";
	VoiceLib instance = (VoiceLib)Native.loadLibrary(filePath, VoiceLib.class);
	
	int MSPLogin(String usr, String pwd, String params);
	
    int QISRBuildGrammar (String cs2, String grm_content, int grm_cnt_len, String grm_build_params, GrammarCallBack grammarCallBack, Pointer pointer);
    
    String QISRSessionBegin(String grammarList, String asr_params, IntByReference errcode);
    
    int QISRAudioWrite(String session_id, byte[] every, int waveLen, int audioStatus, IntByReference ep_status1, IntByReference rec_status1);
	
    String QISRGetResult(String session_id, IntByReference rss_status1, int waitTime, IntByReference err);
	
    int  QISRSessionEnd(String sessionID, String hints);
    
   // int GrammarCallBack(int ecode, String info, UserData udata);
    
	
    int  MSPLogout();

	



	
	

	
	
	
}

【这里的参数我都已经改好啦,等下到具体功能再解释】

然后写语法的

//重要分割线*********************************//
在讯飞提供的例子中,有一个回调函数和一个构建语法函数,都要改写,怎么办呢?
回调函数我封装到一个Util中(后面的词典回调一起了)

package com.xinzhi;


import com.sun.jna.Callback;
import com.sun.jna.Pointer;

public  class CallbackUtil {
   	

	//语法回调函数的接口
	 public static interface GrammarCallBack extends Callback{
   
		 
	    	int  build_grm_cb(int ecode, String info, Pointer udata);
	    }
	 //语法回调函数的实现
	 public static class GrammarCallBack_Realize implements GrammarCallBack{
   
		 
		@Override
		public int build_grm_cb(int ecode, String info,Pointer udata) {
   
			UserData g_udata=Util.fromPointer(udata

本文标签: 离线手把手科大语音识别操作