精华内容
下载资源
问答
  • 讯飞离线语音合成,需要本地下载一个语记APP实现,代码简单化了
  • 讯飞离线语音识别.zip

    2019-11-19 19:56:29
    基于android的离线语音识别,实现没有网络的情况下把语音转换成文字信息。 对程序内容进行了简化,内容简单明了,容易看懂... 包含了离线语音需要的所有离线包 speechapp.java文件第22行修改成自己在讯飞网站申请的id号
  • 讯飞支持的语言里面没有python,本实例参考《Linux下 python调用讯飞离线语音合成(tts)》基础上,实现了基于Python3.7的调用C语言封装的函数来间接的使用离线语音识别功能实例。
  • 包含文件 ToSpeech.cs Unity脚本文件 tts_offline_sample.c 讯飞发音...xunfei_speech 讯飞语音库模型等文件,测试时候放到C盘目录下 相关使用说明 https://blog.csdn.net/lijiefu123456/article/details/109568797
  • 基于android的离线语音识别,实现没有网络的情况下把语音转换成文字信息。 对程序内容进行了简化,内容简单明了,容易看懂。 包含了离线语音需要的所有离线包
  • csharp调用讯飞离线语音合成源码,体积不到20mb.语音清晰,接近真人,保证可用.
  • 讯飞离线语音合成,需要本地下载一个语记APP实现,代码简单化了
  • 讯飞离线语音

    2018-01-17 11:40:48
    讯飞离线语音讯飞离线语音讯飞离线语音讯飞离线语音
  • 讯飞离线语音命令识别测试, 做的DEMO测试, 想交流的可以联系我。
  • 基于android的离线语音识别,实现没有网络的情况下把语音转换成文字信息。 对程序内容进行了简化,内容简单明了,容易看懂。 包含了离线语音需要的所有离线包 speechapp.java文件第22行修改成自己在讯飞网站申请的id...
  • 讯飞离线语音合成(离线资源包)

    热门讨论 2015-08-30 15:11:01
    讯飞离线语音合成(离线资源包),博客演示示例Demo源码
  • 讯飞离线语音合成(语记|语音+),博客演示示例Demo源码
  • 讯飞离线语音听写

    2019-05-28 15:47:40
    实现讯离线语音听写,纯离线,不需要网络的语音听写,让用户在不需要网络的情况下实现语音听写的操作,
  • 讯飞离线语音合成

    2019-05-28 15:55:15
    科大讯飞的离线语音合成,让你的手机可以说话,把文字让手机用语音说出来,
  • 讯飞离线语音识别测试程序,能够根据bnf文件识别wav录音
  • JAVA JNA 讯飞离线语音合成SDK下载JNA MAVEN依赖JAVA代码 SDK下载 URL:https://www.xfyun.cn/sdk/dispatcher windows离线语音SDK包下载 JNA MAVEN依赖 <!-- ...

    JAVA JNA 讯飞离线语音合成

    SDK下载

    URL:https://www.xfyun.cn/sdk/dispatcher windows离线语音SDK包下载

    选择SDK

    JNA MAVEN依赖

            <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
            <dependency>
                <groupId>net.java.dev.jna</groupId>
                <artifactId>jna</artifactId>
                <version>5.5.0</version>
            </dependency>
    

    JAVA代码

    package com.xunfei.tts;
    
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    /**
     *@program: tts
     *@description:
     *@author: liqiaozong
     *@create: 2019-12-31 08:29
     */
    public class XunFeiSpeech {
    
        public interface MscLibrary extends Library {
    
            // DLL文件默认路径为项目根目录,若DLL文件存放在项目外,请使用绝对路径
            MscLibrary INSTANCE = Native.load("D:\\temp\\tts\\msc-lib\\msc_x64", MscLibrary.class);
    
            int MSPLogin(String username, String password, String param);
    
            int MSPLogout();
    
            String QTTSSessionBegin(String params, IntByReference errorCode);
    
            int QTTSTextPut(String sessionID, String textString, int textLen, String params);
    
            Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);
    
            int QTTSSessionEnd(String sessionID, String hints);
        }
    
        public static void main(String[] args) {
    
    		//登录参数,appid与msc库绑定,请勿随意改动
            String login_params = "appid = 5e0*****, work_dir = .";
            //合成参数:tts_res_path我这里用了绝对路径
            String session_begin_params = "engine_type = local, voice_name = xiaoyan, text_encoding = UTF-8, tts_res_path = fo|D:\\temp\\tts\\msc-lib\\msc\\res\\tts\\xiaoyan.jet;fo|D:\\temp\\tts\\msc-lib\\msc\\res\\tts\\common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2";
            //合成的语音文件名称
            String filename = "tts_sample.wav"; 
             //合成文本
            String text = "亲爱的用户,您好,这是一个语音合成示例,感谢您对科大讯飞语音技术的支持!科大讯飞是亚太地区最大的语音上市公司,股票代码:002230";
    
            String sessionId = null;
            RandomAccessFile raf = null;
            try {
                //登录
                int loginCode = MscLibrary.INSTANCE.MSPLogin(null, null, login_params);
    
                if (loginCode != 0) {
                    //登录失败
                    return;
                }
    
                //初始session
                IntByReference errCode = new IntByReference();
                sessionId = MscLibrary.INSTANCE.QTTSSessionBegin(session_begin_params, errCode);
    
                if (errCode.getValue() != 0) {
                    //会话失败
                    return;
                }
    
                //放入文本
                int textPutCode = MscLibrary.INSTANCE.QTTSTextPut(sessionId, text, text.getBytes().length, null);
    
                if (textPutCode != 0) {
                    //放入文本失败
                    return;
                }
    
                //写入空的头格式
                raf = new RandomAccessFile(filename, "rw");
                raf.write(new byte[44]);
                int dataSize = 0;
                IntByReference audioLen = new IntByReference();
                IntByReference synthStatus = new IntByReference();
                while (true) {
                    Pointer pointer = MscLibrary.INSTANCE.QTTSAudioGet(sessionId, audioLen, synthStatus, errCode);
                    if (pointer != null && audioLen.getValue() > 0) {
                        //写入合成内容
                        raf.write(pointer.getByteArray(0, audioLen.getValue()));
                        //记录数据长度
                        dataSize += audioLen.getValue();
                    }
                    //转换异常或转换结束跳出循环
                    if (errCode.getValue() != 0 || synthStatus.getValue() == 2) {
                        break;
                    }
                }
                if (textPutCode != 0) {
                    //获取转换数据失败
                    return;
                }
                //定位到文件起始位置
                raf.seek(0);
                //写入真实头格式
                raf.write(getWavHeader(dataSize, 16000, 32000, 1, 16));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (sessionId != null) {
                    MscLibrary.INSTANCE.QTTSSessionEnd(sessionId, "Normal");
                }
                MscLibrary.INSTANCE.MSPLogout();
                if (raf != null) {
                    try {
                        raf.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        /**
         * @param totalAudioLen 音频数据总大小
         * @param sampleRate    采样率
         * @param byteRate      位元(组)率(每秒的数据量 单位 字节/秒)   采样率(44100之类的) * 通道数(1,或者2)*每次采样得到的样本位数(16或者8) / 8;
         * @param nChannels     声道数量
         * @param weikuan       位宽
         */
        private static byte[] getWavHeader(int totalAudioLen, int sampleRate, int byteRate, int nChannels, int weikuan) {
            long totalDataLen = totalAudioLen + 36;
            byte[] header = new byte[44];
            header[0] = 'R'; // RIFF/WAVE header
            header[1] = 'I';
            header[2] = 'F';
            header[3] = 'F';
            header[4] = (byte) (totalDataLen & 0xff);
            header[5] = (byte) ((totalDataLen >> 8) & 0xff);
            header[6] = (byte) ((totalDataLen >> 16) & 0xff);
            header[7] = (byte) ((totalDataLen >> 24) & 0xff);
            header[8] = 'W';
            header[9] = 'A';
            header[10] = 'V';
            header[11] = 'E';
            header[12] = 'f'; // 'fmt ' chunk
            header[13] = 'm';
            header[14] = 't';
            header[15] = ' ';
            header[16] = 16; // 4 bytes: size of 'fmt ' chunk
            header[17] = 0;
            header[18] = 0;
            header[19] = 0;
            header[20] = 1; // format = 1
            header[21] = 0;
            header[22] = (byte) (nChannels & 0xff);
            header[23] = (byte) ((nChannels >> 8) & 0xff);
    
            header[24] = (byte) (sampleRate & 0xff);//采样率
            header[25] = (byte) ((sampleRate >> 8) & 0xff);
            header[26] = (byte) ((sampleRate >> 16) & 0xff);
            header[27] = (byte) ((sampleRate >> 24) & 0xff);
    
            header[28] = (byte) (byteRate & 0xff);//取八位
            header[29] = (byte) ((byteRate >> 8) & 0xff);
            header[30] = (byte) ((byteRate >> 16) & 0xff);
            header[31] = (byte) ((byteRate >> 24) & 0xff);
    
            int b = weikuan * nChannels / 8;//每次采样的大小
            header[32] = (byte) (b & 0xff); // block align
            header[33] = (byte) ((b >> 8) & 0xff);
    
            header[34] = (byte) (weikuan & 0xff);//位宽
            header[35] = (byte) ((weikuan >> 8) & 0xff);
    
            header[36] = 'd';//data
            header[37] = 'a';
            header[38] = 't';
            header[39] = 'a';
            header[40] = (byte) (totalAudioLen & 0xff);
            header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
            header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
            header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
            return header;
        }
    }
    
    
    
    展开全文
  • 讯飞离线语音合成接入

    千次阅读 2019-05-23 20:23:00
    讯飞离线语音合成接入: 文字转语音的方法 1.Google TextToSpeech + 中文语音引擎 Google提供了原生的方法TextToSpeech,但是不支持中文,sad… 不过可以用第三方的语音引擎,eg,讯飞,百度… 详情参考: Android ...

    讯飞离线语音合成接入:

    文字转语音的方法

    1.Google TextToSpeech + 中文语音引擎

    Google提供了原生的方法TextToSpeech,但是不支持中文,sad…

    不过可以用第三方的语音引擎,eg,讯飞,百度…

    详情参考:

    Android 文字转语音(中文) TextToSpeech+科大讯飞语音引擎3.0

    Android文字转语音引擎(TTS)简单比较及下载

    个人项目可以尝试用,如果上线项目总不能让用户去下载语音引擎吧

    2.第三方语音服务商(讯飞,百度)

    接入的是讯飞离线语音SDK

    ​ 创建新应用-SDK下载-选择你需要的功能/服务

    • SDK下载/导入
      在这里插入图片描述
      有readme文件,这个必须要读,

    sample文件夹里,就是Demo代码,主要包含以下功能

    在这里插入图片描述

    因为他的demo缺少了很多配置文件,并不能跑起来,所以不仅要配置app目录,project的build.gradle等,还要按照readme提示,添加文件

    从讯飞下载的Demo中,是自带APPID的,没有的话需要自己添加

    讯飞初始化的地方放在了应用的Application的onCreate中

    StringBuffer param = new StringBuffer();
    param.append("appid="+getString(R.string.app_id));
    param.append(",");
    // 设置使用v5+
    param.append(SpeechConstant.ENGINE_MODE+"="+SpeechConstant.MODE_MSC);
    SpeechUtility.createUtility(SpeechApp.this, param.toString());
    

    我们需要的功能是离线语音合成,点击体验语音合成进入页面
    在这里插入图片描述

    就可以操作了

    封装了一个类处理SpeechSynthesizer

    public class TtsManager {
        private SpeechSynthesizer mTts;
        private static final String TAG = TtsManager.class.getSimpleName();
        // 默认云端发音人
        public static String voicerCloud="xiaoyan";
        // 默认本地发音人
        public static String voicerLocal="xiaoyan";
        private Context mContext;
        public TtsManager(Context context) {
            mContext = context;
            Log.d(TAG,mTtsInitListener+"");
            mTts = SpeechSynthesizer.createSynthesizer(mContext, mTtsInitListener);
            Log.d(TAG,"SUCCESS");
        }
    
    
        // 初始化成功,之后可以调用startSpeaking方法
        // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成,
        // 正确的做法是将onCreate中的startSpeaking调用移至这里
        InitListener mTtsInitListener = new InitListener() {
            @Override
            public void onInit(int code) {
                Log.d(TAG, "InitListener init() code = " + code);
                if (code != ErrorCode.SUCCESS) {
                    if (onTtsInitListener != null) {
                        onTtsInitListener.initError();
                    }
                    Log.d(TAG, "初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
                } else {
                    // 初始化成功,之后可以调用startSpeaking方法
                    // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成,
                    // 正确的做法是将onCreate中的startSpeaking调用移至这里
                    if (onTtsInitListener != null) {
                        Log.d(TAG, "开始播放");
                        onTtsInitListener.initSpeak();
                    }
                    Log.d(TAG, "初始化成功,开始播放");
                }
            }
        };
    
    
       private OnTtsInitListener onTtsInitListener;
        public void setOnTtsInitListener(OnTtsInitListener ttsInitListener){
              this.onTtsInitListener = ttsInitListener;
        }
        public interface OnTtsInitListener{
    
           void initError();
           void initSpeak();
    
        }
        private SynthesizerListener mTtsListener = new SynthesizerListener() {
            @Override
            public void onSpeakBegin() { //开始播放
    
            }
    
    
    
            @Override
            public void onSpeakPaused() { //暂停播放
    
            }
    
            @Override
            public void onSpeakResumed() { //继续播放
    
            }
            @Override
            public void onBufferProgress(int i, int i1, int i2, String s) {
              //合成进度
            }
            @Override
            public void onSpeakProgress(int i, int i1, int i2) {
              //播放进度
            }
    
            @Override
            public void onCompleted(SpeechError speechError) {
             //播放完成
            }
    
            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {
            // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因
                // 若使用本地能力,会话id为null
                // if (SpeechEvent.EVENT_SESSION_ID == eventType) {
                //    String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
                //    Log.d(TAG, "session id =" + sid);
                // }
    
                //实时音频流输出参考
             /*if (SpeechEvent.EVENT_TTS_BUFFER == eventType) {
                byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER);
                Log.e("MscSpeechLog", "buf is =" + buf);
             }*/
            }
        };
    
        /**
         * 默认本地
         * @param text
         * @return
         */
        public int startLocalSpeaking(String text){
            setParam(SpeechConstant.TYPE_LOCAL,voicerLocal);
            return  mTts.startSpeaking(text,mTtsListener);
        }
    
        //开始合成/播放
        public int startSpeaking(String text,String type,String voicer){
            setParam(type,voicer);
          return  mTts.startSpeaking(text,mTtsListener);
        }
       //停止播放
       public void stopSpeaking(){
           if( null != mTts ) {
               mTts.stopSpeaking();
           }
        }
        //暂停播放
        public void pauseSpeaking(){
            mTts.pauseSpeaking();
        }
    
        public void destroySpeaking(){
            if( null != mTts ){
                mTts.stopSpeaking();
                // 退出时释放连接
                mTts.destroy();
            }
        }
    
        //继续播放
        private void resumeSpeaking(){
            mTts.resumeSpeaking();
        }
    
    
    
        private HashMap<String,String> getTtsParam(){
            HashMap<String,String> hashMap = new HashMap();
            hashMap.put(SpeechConstant.SPEED,"50");设置合成语速
            hashMap.put(SpeechConstant.PITCH,"50");//   //设置合成音调
            hashMap.put(SpeechConstant.VOLUME,"50");//   //设置合成音量
            hashMap.put(SpeechConstant.STREAM_TYPE,"3");//   //  //设置播放器音频流类型
            hashMap.put(SpeechConstant.KEY_REQUEST_FOCUS,"50");//   设置播放合成音频打断音乐播放,默认为true
            hashMap.put(SpeechConstant.AUDIO_FORMAT,"wav");//  设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
            hashMap.put(SpeechConstant.TTS_AUDIO_PATH,Environment.getExternalStorageDirectory()+"/msc/tts.wav");
           return hashMap;
           /* //设置合成音调
            mTts.setParameter(SpeechConstant.PITCH, TtsSpUtils.getInstance().getString("pitch_preference", "50"));
            //设置合成音量
            mTts.setParameter(SpeechConstant.VOLUME, TtsSpUtils.getInstance().getString("volume_preference", "50"));
            //设置播放器音频流类型
            mTts.setParameter(SpeechConstant.STREAM_TYPE, TtsSpUtils.getInstance().getString("stream_preference", "3"));
            // 设置播放合成音频打断音乐播放,默认为true
            mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");
            // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
            mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
            mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/tts.wav");*/
    
        }
        private void setTtsParam(String key,String value){
            HashMap<String,String> hashMap = getTtsParam();
            if (key!= null) {
                hashMap.put(key, value);
            }
            for (String mkey:hashMap.keySet()) {
                mTts.setParameter(mkey,hashMap.get(mkey));
            }
        }
        private void setLocalParam(){
            // 清空参数
            mTts.setParameter(SpeechConstant.PARAMS, null);
            //设置使用本地引擎
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
            //设置发音人资源路径
            mTts.setParameter(ResourceUtil.TTS_RES_PATH,getResourcePath());
            //设置发音人
            mTts.setParameter(SpeechConstant.VOICE_NAME,voicerLocal);
        //mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY,"1");//支持实时音频流抛出,仅在synthesizeToUri条件下支持
        //设置合成语速
            mTts.setParameter(SpeechConstant.SPEED, TtsSpUtils.getInstance().getString("speed_preference", "50"));
    
    
        }
    
        private void setParam(String mEngineType,String voicer){
            // 清空参数
            mTts.setParameter(SpeechConstant.PARAMS, null);
            //设置合成
            if(mEngineType.equals(SpeechConstant.TYPE_CLOUD))
            {
                //设置使用云端引擎
                mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
                //设置发音人
                mTts.setParameter(SpeechConstant.VOICE_NAME,   voicer == null?voicerCloud:voicer);
            }else {
                //设置使用本地引擎
                mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
                //设置发音人资源路径
                mTts.setParameter(ResourceUtil.TTS_RES_PATH,getResourcePath());
                //设置发音人
                mTts.setParameter(SpeechConstant.VOICE_NAME,voicer == null?voicerLocal:voicer);
            }
            //mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY,"1");//支持实时音频流抛出,仅在synthesizeToUri条件下支持
            //设置合成语速
            mTts.setParameter(SpeechConstant.SPEED, TtsSpUtils.getInstance().getString("speed_preference", "50"));
            //设置合成音调
            mTts.setParameter(SpeechConstant.PITCH, TtsSpUtils.getInstance().getString("pitch_preference", "50"));
            //设置合成音量
            mTts.setParameter(SpeechConstant.VOLUME, TtsSpUtils.getInstance().getString("volume_preference", "50"));
            //设置播放器音频流类型
            mTts.setParameter(SpeechConstant.STREAM_TYPE, TtsSpUtils.getInstance().getString("stream_preference", "3"));
            // 设置播放合成音频打断音乐播放,默认为true
            mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");
            // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
            mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
            mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/tts.wav");
    
    
        }
        //获取发音人资源路径
        private String getResourcePath(){
            StringBuffer tempBuffer = new StringBuffer();
            //合成通用资源
            tempBuffer.append(ResourceUtil.generateResourcePath(mContext, ResourceUtil.RESOURCE_TYPE.assets, "tts/common.jet"));
            tempBuffer.append(";");
            //发音人资源
            tempBuffer.append(ResourceUtil.generateResourcePath(mContext, ResourceUtil.RESOURCE_TYPE.assets, "tts/"+voicerLocal+".jet"));
            return tempBuffer.toString();
        }
    
    
    
    
    }
    

    还有一个SharedPreferences工具类:

    public class TtsSpUtils {
    
        private static final String NAME = "Tts";
        private static TtsSpUtils instance = null;
        private SharedPreferences sp;
    
        public static TtsSpUtils getInstance() {
            synchronized (TtsSpUtils.class) {
                if (null == instance) {
                    instance = new TtsSpUtils();
                }
            }
            return instance;
        }
    
        private TtsSpUtils() {
    
        }
        public void init(Context context){
            init(context,NAME);
        }
        public void init(Context context,String spName){
            sp = context.getApplicationContext().getSharedPreferences(spName,Context.MODE_PRIVATE);
        }
        /**
         * SP 中写入 String
         *
         * @param key   键
         * @param value 值
         */
        public void put(@NonNull final String key, @NonNull final String value) {
            put(key, value, false);
        }
    
        /**
         * SP 中写入 String
         *
         * @param key      键
         * @param value    值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, @NonNull final String value, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putString(key, value).commit();
            } else {
                sp.edit().putString(key, value).apply();
            }
        }
    
        /**
         * SP 中读取 String
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值{@code ""}
         */
        public String getString(@NonNull final String key) {
            return getString(key, "");
        }
    
        /**
         * SP 中读取 String
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public String getString(@NonNull final String key, @NonNull final String defaultValue) {
            return sp.getString(key, defaultValue);
        }
    
        /**
         * SP 中写入 int
         *
         * @param key   键
         * @param value 值
         */
        public void put(@NonNull final String key, final int value) {
            put(key, value, false);
        }
    
        /**
         * SP 中写入 int
         *
         * @param key      键
         * @param value    值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, final int value, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putInt(key, value).commit();
            } else {
                sp.edit().putInt(key, value).apply();
            }
        }
    
        /**
         * SP 中读取 int
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值-1
         */
        public int getInt(@NonNull final String key) {
            return getInt(key, -1);
        }
    
        /**
         * SP 中读取 int
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public int getInt(@NonNull final String key, final int defaultValue) {
            return sp.getInt(key, defaultValue);
        }
    
        /**
         * SP 中写入 long
         *
         * @param key   键
         * @param value 值
         */
        public void put(@NonNull final String key, final long value) {
            put(key, value, false);
        }
    
        /**
         * SP 中写入 long
         *
         * @param key      键
         * @param value    值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, final long value, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putLong(key, value).commit();
            } else {
                sp.edit().putLong(key, value).apply();
            }
        }
    
        /**
         * SP 中读取 long
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值-1
         */
        public long getLong(@NonNull final String key) {
            return getLong(key, -1L);
        }
    
        /**
         * SP 中读取 long
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public long getLong(@NonNull final String key, final long defaultValue) {
            return sp.getLong(key, defaultValue);
        }
    
        /**
         * SP 中写入 float
         *
         * @param key   键
         * @param value 值
         */
        public void put(@NonNull final String key, final float value) {
            put(key, value, false);
        }
    
        /**
         * SP 中写入 float
         *
         * @param key      键
         * @param value    值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, final float value, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putFloat(key, value).commit();
            } else {
                sp.edit().putFloat(key, value).apply();
            }
        }
    
        /**
         * SP 中读取 float
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值-1
         */
        public float getFloat(@NonNull final String key) {
            return getFloat(key, -1f);
        }
    
        /**
         * SP 中读取 float
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public float getFloat(@NonNull final String key, final float defaultValue) {
            return sp.getFloat(key, defaultValue);
        }
    
        /**
         * SP 中写入 boolean
         *
         * @param key   键
         * @param value 值
         */
        public void put(@NonNull final String key, final boolean value) {
            put(key, value, false);
        }
    
        /**
         * SP 中写入 boolean
         *
         * @param key      键
         * @param value    值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, final boolean value, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putBoolean(key, value).commit();
            } else {
                sp.edit().putBoolean(key, value).apply();
            }
        }
    
        /**
         * SP 中读取 boolean
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值{@code false}
         */
        public boolean getBoolean(@NonNull final String key) {
            return getBoolean(key, false);
        }
    
        /**
         * SP 中读取 boolean
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public boolean getBoolean(@NonNull final String key, final boolean defaultValue) {
            return sp.getBoolean(key, defaultValue);
        }
    
        /**
         * SP 中写入 String 集合
         *
         * @param key    键
         * @param values 值
         */
        public void put(@NonNull final String key, @NonNull final Set<String> values) {
            put(key, values, false);
        }
    
        /**
         * SP 中写入 String 集合
         *
         * @param key      键
         * @param values   值
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void put(@NonNull final String key, @NonNull final Set<String> values, final boolean isCommit) {
            if (isCommit) {
                sp.edit().putStringSet(key, values).commit();
            } else {
                sp.edit().putStringSet(key, values).apply();
            }
        }
    
        /**
         * SP 中读取 StringSet
         *
         * @param key 键
         * @return 存在返回对应值,不存在返回默认值{@code Collections.<String>emptySet()}
         */
        public Set<String> getStringSet(@NonNull final String key) {
            return getStringSet(key, Collections.<String>emptySet());
        }
    
        /**
         * SP 中读取 StringSet
         *
         * @param key          键
         * @param defaultValue 默认值
         * @return 存在返回对应值,不存在返回默认值{@code defaultValue}
         */
        public Set<String> getStringSet(@NonNull final String key, @NonNull final Set<String> defaultValue) {
            return sp.getStringSet(key, defaultValue);
        }
    
        /**
         * SP 中获取所有键值对
         *
         * @return Map 对象
         */
        public Map<String, ?> getAll() {
            return sp.getAll();
        }
    
        /**
         * SP 中是否存在该 key
         *
         * @param key 键
         * @return {@code true}: 存在<br>{@code false}: 不存在
         */
        public boolean contains(@NonNull final String key) {
            return sp.contains(key);
        }
    
        /**
         * SP 中移除该 key
         *
         * @param key 键
         */
        public void remove(@NonNull final String key) {
            remove(key, false);
        }
    
        /**
         * SP 中移除该 key
         *
         * @param key      键
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void remove(@NonNull final String key, final boolean isCommit) {
            if (isCommit) {
                sp.edit().remove(key).commit();
            } else {
                sp.edit().remove(key).apply();
            }
        }
    
        /**
         * SP 中清除所有数据
         */
        public void clear() {
            clear(false);
        }
    
        /**
         * SP 中清除所有数据
         *
         * @param isCommit {@code true}: {@link SharedPreferences.Editor#commit()}<br>
         *                 {@code false}: {@link SharedPreferences.Editor#apply()}
         */
        public void clear(final boolean isCommit) {
            if (isCommit) {
                sp.edit().clear().commit();
            } else {
                sp.edit().clear().apply();
            }
        }
    
        private static boolean isSpace(final String s) {
            if (s == null) return true;
            for (int i = 0, len = s.length(); i < len; ++i) {
                if (!Character.isWhitespace(s.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    
    }
    

    使用方式:

    ​ Application中的onCreate()中

      TtsSpUtils.getInstance().init(this);
    

    在需要用的的Activity或者BaseActivity中

    private TtsManager ttsManager;
    /**
     * 开始语音播放.必须调该方法
     */
    public  void initSpeech(String speakText){
      initSpeech(speakText,true);
    }
    public void initSpeech(String speakText,boolean isSpeak){
        if (!isSpeak) return;
        ttsManager = new TtsManager(this);
        ttsManager.setOnTtsInitListener(new TtsManager.OnTtsInitListener() {
            @Override
            public void initError() {
            }
            @Override
            public void initSpeak() {
                ttsManager.startLocalSpeaking(speakText);
            }
        });
    
    }
    

    Note: APPID 和 资源文件必须匹配,否则Log会提示错误

    DEMO/Lib下载地址

    1.使用下载的Demo,需要替换libs和assets的所有资源文件以及appid,考虑layout中的文件是否替换

    2.如果依赖module,和上面一样需要替换资源文件,必须把libs中的libmsc.so文件放入 主项目的src/main/jniLibs/armeabi-v7a中

    如果放在libs中,你必须sourceSet指明libs文件夹

    把下面的maven地址放在Project的build.gradle里

     allprojects {
            repositories {
    		
    			// Msc.jar线上maven地址
    		    maven{
                    url 'http://libmsc.xfyun.cn/repository/maven-releases/'
                }
                jcenter()
                mavenCentral()
            }
        }
    

    别忘了Application中的讯飞初始化

    题外:目前讯飞1137版本在rk3399平台上初始化不成功,卡在初始方法上
    参考:
    科大讯飞在线语音合成
    科大讯飞语音合成实例

    展开全文
  • 1、离线语音合成调用主函数(离线语音合成调用属于简单的,无回调函数) package com.iflytek; import com.iflytek.util.Step2_tts_thread; import com.iflytek.util.Step3_audioFormat; import java.util.Scanner...

    1、离线语音合成调用主函数(离线语音合成调用属于简单的,无回调函数)

    package com.iflytek;
    import com.iflytek.util.Step2_tts_thread;
    import com.iflytek.util.Step3_audioFormat;
    import java.util.Scanner;
    import javax.sound.sampled.*;
    
    /**
     * 请注意!!!
     * 1.首选到控制台https://console.xfyun.cn/services/aisound下载普通离线语音合成的Windows MSC。
     * 2.普通离线语音合成Windows MSC解压后,把bin目录下msc文件夹与dll文件拷贝到res目录下。
     * 3.最后请替换Step2_tts_thread中的appid值,appid值在下载页面控制台可以看到。
     */
    
    public class OfflineTtsMain {
    	//录音相关参数
    	public static AudioFormat audioFormat;
    	public static SourceDataLine sourceDataLine;
    	public static void main(String[] args) throws Exception {
    		System.out.println("输入y开始体验普通离线语音合成...");
    		Scanner myScanner = new Scanner(System.in);
    		String userCommand = myScanner.next();
    		long startTime = System.currentTimeMillis();
    		if(userCommand.equals("y")){
    			audioFormat = Step3_audioFormat.getAudioFormat(audioFormat);//构造具有线性 PCM 编码和给定参数的 AudioFormat。
    			DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class,audioFormat, AudioSystem.NOT_SPECIFIED);
    			sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
    			Step2_tts_thread myThread=new Step2_tts_thread();
    			myThread.start();
    		}
    	}
    }

    2、根据MSC文档用JAVA重写方法

    package com.iflytek.service;
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    public interface Step1_tts_dll extends Library {
        /**
         * 重点:
         * 1.char *   对应  String
         * 2.int *    对应  IntByReference
         * 3.void *   对应  byte[]/Pointer,回调函数里此类型需用String来对应。
         * 4.int      对应  int
         * 5.无参     对应  void
         * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback,离线语音合成无回调
         */
        //加载dll动态库并实例化,从而使用其内部的方法
        Step1_tts_dll INSTANCE = (Step1_tts_dll) Native.loadLibrary("res/msc_x64.dll", Step1_tts_dll.class);
    
        //定义登录方法
        public int MSPLogin(String usr, String pwd, String params);
    
        //开始一次普通离线语音合成
        public String QTTSSessionBegin(String params, IntByReference errorCode);
    
        //写入需要合成的文本
        public int QTTSTextPut(String sessionID,String textString,int textLen,String params);
    
        //获取离线合成的音频
        public Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);
    
        //结束本次普通离线语音合成
        public int QTTSSessionEnd(String sessionID, String hints);
    
        //定义退出方法
        public int MSPLogout();
    }
    

    3、把调用步骤依次写进线程类 

    package com.iflytek.util;
    import com.iflytek.OfflineTtsMain;
    import com.iflytek.service.Step1_tts_dll;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    import java.io.ByteArrayOutputStream;
    import java.util.Scanner;
    
    public class Step2_tts_thread extends Thread{
    	public static int total_audio_length=0;
    	public static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    	public void run() {
    		while (true) {
    			//登录参数
    			String login_params = "appid = 替换你的appid, work_dir = ./res";
    			//第一个参数为用户名,第二个参数为密码,传null即可
    			int ret = Step1_tts_dll.INSTANCE.MSPLogin(null, null, login_params);
    			if (ret != 0) {//登录成功标志ret为0
    				System.out.println("登录失败...请检查");
    				System.exit(1);
    			} else {
    				//System.out.println("登录成功...");
    			}
    			//请让一让,A02-02-03
    			//开始一次普通离线语音合成会话
    			String session_begin_params = "engine_type = local, voice_name = xiaoyan, text_encoding = UTF8, tts_res_path = fo|res/tts/xiaoyan.jet;fo|res/tts/common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2";
    			IntByReference errorCode = new IntByReference(-100);
    			String session_id = Step1_tts_dll.INSTANCE.QTTSSessionBegin(session_begin_params,errorCode);
    			if(errorCode.getValue()==0){
    				//System.out.println("开启普通离线语音合成成功,session_id是:"+session_id);
    			}else{
    				System.out.println("开启普通离线语音合成失败:"+errorCode.getValue());
    			}
    
    			//写入需要合成的文本
    			System.out.println("\033[43;34;4m"+"请输入你要合成的文本并回车"+"\033[0m");
    			Scanner myScanner = new Scanner(System.in);
    			String tts_text =myScanner.nextLine();
    			//System.out.println(tts_text);//注意获取的文本是否完整
    			ret= Step1_tts_dll.INSTANCE.QTTSTextPut(session_id, tts_text, tts_text.getBytes().length,null);
    			if(ret==0){
    				//System.out.println("写入合成文本成功...");
    			}else{
    				System.out.println("写入合成文本失败:"+ret);
    			}
    
    			//循环获取离线合成的音频,并实时进行播放
    			IntByReference audio_len=new IntByReference(-100);
    			IntByReference synth_status=new IntByReference(-100);
    			errorCode=new IntByReference(-100);
    			try{
    				//实时播放
    				OfflineTtsMain.sourceDataLine.open(OfflineTtsMain.audioFormat);
    				OfflineTtsMain.sourceDataLine.start();
    			}catch (Exception e){
    				e.printStackTrace();
    			}
    			//int i=0;
    			while (true) {
    				Pointer audioPointer = Step1_tts_dll.INSTANCE.QTTSAudioGet(session_id,audio_len,synth_status,errorCode);
    				byte[] audioDataByteArray=null;
    				if(audioPointer!=null){
    					audioDataByteArray=audioPointer.getByteArray(0,audio_len.getValue());
    				}
    				if (errorCode.getValue()==0){
    					//System.out.println("正常获取音频中...");
    				}else{
    					System.out.println("获取音频发生错误:"+errorCode);
    					break;
    				}
    				if (audioDataByteArray!=null ){
    					try{
    						//实时播放
    						OfflineTtsMain.sourceDataLine.write(audioDataByteArray, 0, audio_len.getValue());
    						/*i=i+1;//实现暂停的效果
    						System.out.println(i);
    						if(i==5){
    							OfflineTtsMain.sourceDataLine.stop();
    							Thread.sleep(5000);
    						}
    						if(i==6){
    							OfflineTtsMain.sourceDataLine.start();
    						}*/
    						//将数据写入字节数组的输出流,用来生成音频文件
    						byteArrayOutputStream.write(audioDataByteArray, 0, audio_len.getValue());
    					}catch(Exception e){
    						e.printStackTrace();
    					}
    					//计算总音频长度,用来生成音频文件
    					total_audio_length=total_audio_length+audio_len.getValue();
    				}
    				if (synth_status.getValue()==2){
    					//说明音频已经取完,退出本次循环
    					try{
    						OfflineTtsMain.sourceDataLine.drain();
    						OfflineTtsMain.sourceDataLine.close();
    						byteArrayOutputStream.flush();
    						byteArrayOutputStream.close();
    					}catch (Exception e){
    						e.printStackTrace();
    					}
    					break;
    				}
    			}
    
    			//把合成的音频存放为wav格式
    			String dateAsFileName= String.valueOf(System.currentTimeMillis());//用当前时间标记文件名
    			Boolean waveProductFlag=Step4_wave_product.waveProduct(total_audio_length,byteArrayOutputStream,"./res/"+dateAsFileName+".wav");
    			if(waveProductFlag){
    				System.out.println("生成音频文件成功:"+dateAsFileName+".wav");
    			}else{
    				System.out.println("生成音频文件失败...");
    			}
    
    			//结束本次普通离线语音合成
    			ret=Step1_tts_dll.INSTANCE.QTTSSessionEnd(session_id, "正常退出");
    			if(ret==0){
    				//System.out.println("离线语音合成正常退出...");
    			}else{
    				System.out.println("离线语音合成退出异常:"+ret);
    			}
    
    			//执行最终退出
    			ret = Step1_tts_dll.INSTANCE.MSPLogout();
    			if (ret == 0) {
    				//System.out.println("正常退出...");
    			} else {
    				System.out.println("异常退出:"+ret);
    			}
    
    			//是否退出Java程序
    			System.out.println("\33[43;31;4m"+"结束合成:输入n,继续合成:输入其他内容"+"\33[0m");
    			Scanner myScanner2 = new Scanner(System.in);
    			String userCommand = myScanner2.nextLine();
    			if(userCommand.equals("n")){
    				OfflineTtsMain.sourceDataLine.stop();
    				OfflineTtsMain.sourceDataLine.close();
    				System.exit(0);
    			}
    		}
    	}
    }

    4、生成16K、16BIT单声道音频流

    package com.iflytek.util;
    import javax.sound.sampled.AudioFormat;
    
    public class Step3_audioFormat {
        //构造线程参数
        //16k采样率的16bit音频,一帧的大小为640B, 时长20ms
        /**
         sampleRate - 每秒样品数
         sampleSizeInBits - 每个样本中的位数
         channels - 通道数(1为mono,2为立体声等)
         signed - 表示数据是签名还是无符号
         bigEndian - 指示单个样本的数据是否以大字节顺序存储( false表示小端)
         */
        public static AudioFormat getAudioFormat(AudioFormat audioFormat) {
            audioFormat=new AudioFormat(16000F, 16, 1,true,false);
            // true,false 指示是以 big-endian 顺序还是以 little-endian 顺序存储音频数据。
            return audioFormat;//构造具有线性 PCM 编码和给定参数的 AudioFormat。
        }
    }

    5、生成WAV音频所需的文件头

    package com.iflytek.util;
    
    import java.io.BufferedOutputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    
    public class Step4_wave_product {
        public static byte[] RIFF = "RIFF".getBytes();
        public static byte[] RIFF_SIZE = new byte[8];
        public static byte[] RIFF_TYPE = "WAVE".getBytes();
        public static byte[] FORMAT = "fmt ".getBytes();
        public static byte[] FORMAT_SIZE = new byte[4];
        public static byte[] FORMAT_TAG = new byte[2];
        public static byte[] CHANNELS = new byte[2];
        public static byte[] SamplesPerSec = new byte[4];
        public static byte[] AvgBytesPerSec = new byte[4];
        public static byte[] BlockAlign = new byte[2];
        public static byte[] BitsPerSample = new byte[2];
        public static byte[] Data = "data".getBytes();
        public static byte[] DataSize = new byte[4];
        public static boolean waveProduct(int audioLength, ByteArrayOutputStream byteArrayOutputStream, String outputFilePath){
            Step4_wave_product.DataSize = Step4_wave_product.revers(Step4_wave_product.intToBytes(audioLength));
            Step4_wave_product.RIFF_SIZE = Step4_wave_product.revers(Step4_wave_product.intToBytes(audioLength + 36 - 8));
            File waveFile = new File(outputFilePath);
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(waveFile);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                init();
                bufferedOutputStream.write(RIFF);
                bufferedOutputStream.write(RIFF_SIZE);
                bufferedOutputStream.write(RIFF_TYPE);
                bufferedOutputStream.write(FORMAT);
                bufferedOutputStream.write(FORMAT_SIZE);
                bufferedOutputStream.write(FORMAT_TAG);
                bufferedOutputStream.write(CHANNELS);
                bufferedOutputStream.write(SamplesPerSec);
                bufferedOutputStream.write(AvgBytesPerSec);
                bufferedOutputStream.write(BlockAlign);
                bufferedOutputStream.write(BitsPerSample);
                bufferedOutputStream.write(Data);
                bufferedOutputStream.write(DataSize);
                bufferedOutputStream.write(byteArrayOutputStream.toByteArray());
                bufferedOutputStream.flush();
                bufferedOutputStream.close();
                return true;
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return false;
            }
        }
        public static void init() {
            FORMAT_SIZE = new byte[]{(byte) 16, (byte) 0, (byte) 0, (byte) 0};
            byte[] tmp = revers(intToBytes(1));
            FORMAT_TAG = new byte[]{tmp[0], tmp[1]};
            CHANNELS = new byte[]{tmp[0], tmp[1]};
            SamplesPerSec = revers(intToBytes(16000));
            AvgBytesPerSec = revers(intToBytes(32000));
            tmp = revers(intToBytes(2));
            BlockAlign = new byte[]{tmp[0], tmp[1]};
            tmp = revers(intToBytes(16));
            BitsPerSample = new byte[]{tmp[0], tmp[1]};
        }
        public static byte[] revers(byte[] tmp) {
            byte[] reversed = new byte[tmp.length];
            for (int i = 0; i < tmp.length; i++) {
                reversed[i] = tmp[tmp.length - i - 1];
            }
            return reversed;
        }
        public static byte[] intToBytes(int num) {
            byte[] bytes = new byte[4];
            bytes[0] = (byte) (num >> 24);
            bytes[1] = (byte) ((num >> 16) & 0x000000FF);
            bytes[2] = (byte) ((num >> 8) & 0x000000FF);
            bytes[3] = (byte) (num & 0x000000FF);
            return bytes;
        }
    }

    6、放置讯飞开放平台下载Linux/Windows中所带的资源

    7、Linux代码基本类似,离线合成普通版,注意资源放置

    package com.iflytek.service;
    import com.iflytek.OfflineTtsMain;
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    public interface Step1_tts_so extends Library {
        /**
         * 重点:
         * 1.char *   对应  String
         * 2.int *    对应  IntByReference
         * 3.void *   对应  byte[]/Pointer,回调函数里此类型需用String来对应。
         * 4.int      对应  int
         * 5.无参     对应  void
         * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback,离线语音合成无回调
         */
        //加载dll动态库并实例化,从而使用其内部的方法
        Step1_tts_so INSTANCE = (Step1_tts_so) Native.loadLibrary(OfflineTtsMain.userPath+"res/libmsc.so", Step1_tts_so.class);
    
        //定义登录方法
        public int MSPLogin(String usr, String pwd, String params);
    
        //开始一次普通离线语音合成
        public String QTTSSessionBegin(String params, IntByReference errorCode);
    
        //写入需要合成的文本
        public int QTTSTextPut(String sessionID,String textString,int textLen,String params);
    
        //获取离线合成的音频
        public Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);
    
        //结束本次普通离线语音合成
        public int QTTSSessionEnd(String sessionID, String hints);
    
        //定义退出方法
        public int MSPLogout();
    }

    8、Linux代码基本类似,离线合成高品质,注意资源放置

    package com.iflytek.service;
    import com.iflytek.OfflineHighQualityTtsMain;
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.ptr.IntByReference;
    
    public interface Step1_tts_so extends Library {
        /**
         * 重点:
         * 1.char *   对应  String
         * 2.int *    对应  IntByReference
         * 3.void *   对应  byte[]/Pointer,回调函数里此类型需用String来对应。
         * 4.int      对应  int
         * 5.无参     对应  void
         * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback,离线语音合成无回调
         */
        //加载so动态库并实例化,从而使用其内部的方法
        Step1_tts_so INSTANCE = (Step1_tts_so) Native.loadLibrary(OfflineHighQualityTtsMain.userPath+"res/libmsc.so", Step1_tts_so.class);
    
        //定义登录方法
        public int MSPLogin(String usr, String pwd, String params);
    
        //开始一次高品质离线语音合成
        public String QTTSSessionBegin(String params, IntByReference errorCode);
    
        //写入需要合成的文本
        public int QTTSTextPut(String sessionID,String textString,int textLen,String params);
    
        //获取离线合成的音频
        public Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);
    
        //结束本次高品质离线语音合成
        public int QTTSSessionEnd(String sessionID, String hints);
    
        //定义退出方法
        public int MSPLogout();
    }

    9、普通版与高品质版对内存的消耗也不同,请根据实际所需进行选择

    展开全文
  • 说明:讯飞离线语音听写目前只有Android平台,当前时间是2020年03月06号,本博客介绍使用Unity来搭建这个demo作为测试 Unity导出离线语音听写apk第一步:你得注册一个账号用来下载SDK第二步:在Android Studio上的...

    说明:讯飞离线语音听写目前只有Android平台,当前时间是2020年03月06号,本博客介绍使用Unity来搭建这个demo作为测试

    描述:采用讯飞的离线语音SDK在unity上进行导出
    条件:需要注册讯飞开放平台账号,Android Studio,Unity
    原理:使用Android Studio导出AAR包给Unity,在Unity上进行操作控制

    第一步:你得注册一个账号用来下载SDK

    默认你已经注册好了,你需要注意免费试用是有时间限制的。
    在这里插入图片描述
    现在看看它下载下来的样子:
    在这里插入图片描述

    第二步:在Android Studio上的处理

    1. 建立一个工程

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    下面不使用布局文件,Generate Layout File 不勾选
    在这里插入图片描述
    很好,接下来调成Project模式,你的结构如下
    在这里插入图片描述

    2. 新增一个模块

    在这里插入图片描述
    在这里插入图片描述
    填写库名,模块名,这里也有一个包名,记住它,接下来所有的操作都将在这个模块里完成
    在这里插入图片描述
    在这里插入图片描述

    3. 添加第三方资源

    找到从讯飞下载下来的文件夹,找到libs,选择这两项,添加到模块iatlibrary/libs
    里面
    在这里插入图片描述
    在Unity安装目录下找到这个jar包,同样的添加到模块iatlibrary/libs.
    在这里插入图片描述
    然后再去sample里找到JsonParse这个文件,添加到iatlibrary/src/main/java/你的包名 下面
    在这里插入图片描述
    现在你的项目里是这样的
    在这里插入图片描述
    接下来把classes.jar和Msc.jar以库文件的形式进行添加
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    这是完成后的样子
    在这里插入图片描述
    AndroidStudio要添加的东西完成了,接下来是写东西和导出AAR包

    4. 写代码(活动)

    在这里插入图片描述
    代码如下:

    package com.zy.iatlibrary;
    
    import android.os.Bundle;
    import android.widget.Toast;
    
    import com.iflytek.cloud.ErrorCode;
    import com.iflytek.cloud.InitListener;
    import com.iflytek.cloud.RecognizerListener;
    import com.iflytek.cloud.RecognizerResult;
    import com.iflytek.cloud.SpeechConstant;
    import com.iflytek.cloud.SpeechError;
    import com.iflytek.cloud.SpeechRecognizer;
    import com.iflytek.cloud.SpeechUtility;
    import com.iflytek.cloud.util.ResourceUtil;
    import com.unity3d.player.UnityPlayer;
    import com.unity3d.player.UnityPlayerActivity;
    
    /**
     * Created by zy on 2020/3/6.
     */
    
    public class Iat extends UnityPlayerActivity{
        private SpeechRecognizer mIat;
        private String result= "";
        private String mEngineType = SpeechConstant.TYPE_LOCAL;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            SpeechUtility.createUtility(this, SpeechConstant.APPID + "=9y35h930h");
            mIat = SpeechRecognizer.createRecognizer(this, mTtsInitListener);
            if(mIat==null)
            {
                Toast.makeText(Iat.this,"对象为空,检查是否有jet资源",Toast.LENGTH_LONG).show();
                return;
            }
            else
            {
                mIat.setParameter(SpeechConstant.PARAMS,null);
                mIat.setParameter(SpeechConstant.ENGINE_TYPE,mEngineType);
                if (mEngineType.equals(SpeechConstant.TYPE_LOCAL))
                {
                    mIat.setParameter(ResourceUtil.ASR_RES_PATH,getResourcePath());
                }
                mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
                mIat.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, "20000"); //语音输入超时时间 设置录取音频的最长时间
                mIat.setParameter(SpeechConstant.VAD_BOS,"3000"); //开始录入音频后,音频前面部分最长静音时长
                mIat.setParameter(SpeechConstant.VAD_EOS, "2000"); //开始录入音频后,音频后面部分最长静音时长
            }
        }
    
        //Unity调用这个方法
        public void StartListening(String str)
        {
            Toast.makeText(Iat.this,str,Toast.LENGTH_LONG).show();
            int ret = mIat.startListening(mRecognizerListener);
            UnityPlayer.UnitySendMessage("GameObject","OnStartListening",String.valueOf(ret));
        }
    
    
        /**初始化监听**/
        private InitListener mTtsInitListener = new InitListener()
        {
            @Override
            public void onInit(int i)
            {
                if (i!= ErrorCode.SUCCESS)
                {
                    Toast.makeText(Iat.this,"初始化失败,错误码:" + i+",请点击网址https://www.xfyun.cn/document/error-code查询解决方案",Toast.LENGTH_LONG).show();
                }
                UnityPlayer.UnitySendMessage("GameObject","OnStartListening",String.valueOf(i));
            }
        };
    
        private RecognizerListener mRecognizerListener =new RecognizerListener() {
            @Override
            public void onVolumeChanged(int i, byte[] bytes) {
    
            }
    
            @Override
            public void onBeginOfSpeech()
            {
                UnityPlayer.UnitySendMessage("GameObject","OnBeginOfSpeech","");
            }
    
            @Override
            public void onEndOfSpeech()
            {
                UnityPlayer.UnitySendMessage("GameObject","OnEndOfSpeech","");
            }
    
            @Override
            public void onResult(RecognizerResult recognizerResult, boolean b)
            {
                result+= JsonParser.parseIatResult(recognizerResult.getResultString());
                if(b)
                {
                    UnityPlayer.UnitySendMessage("GameObject","OnResult",result);
                    result = "";
                    mIat.stopListening();
                }
            }
    
            @Override
            public void onError(SpeechError speechError)
            {
                UnityPlayer.UnitySendMessage("GameObject","OnError",speechError.getErrorCode()+"");
            }
    
            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {
    
            }
        };
    
        private String getResourcePath()
        {
            StringBuffer tempBuffer = new StringBuffer();
            tempBuffer.append(ResourceUtil.generateResourcePath(this,ResourceUtil.RESOURCE_TYPE.assets,"iat/common.jet"));
            tempBuffer.append(";");
            tempBuffer.append(ResourceUtil.generateResourcePath(this,ResourceUtil.RESOURCE_TYPE.assets,"iat/sms_16k.jet"));
            return tempBuffer.toString();
        }
    }
    

    不懂的查API:http://mscdoc.xfyun.cn/android/api/
    如果之后报了出错码到这里查:https://www.xfyun.cn/document/error-code
    代码很简单,有面向对象语言基础的都能看懂,说明一下:
    这一条后面的9y35h930h是指你的appid,第一部分就圈了,你的换成自己的。

    SpeechUtility.createUtility(this, SpeechConstant.APPID + "=9y35h930h");
    
    UnityPlayer.UnitySendMessage(unity中对象名称,挂在对象上面脚本的方法,要传递的参数,没有就不写);
    

    还有一点,JsonParse里的包名记得换成你的模块里的包名:
    在这里插入图片描述

    5. 修改AndroidManifest.xml

    在这里插入图片描述
    懂的自然懂,不懂的以后会懂

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.zy.iatlibrary"
              android:versionCode="1"
              android:versionName="1.0" >
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-sdk
            android:minSdkVersion="19"
            android:targetSdkVersion="24" />
    
        <application android:allowBackup="true"
                     android:supportsRtl="true">
                     <activity
                         android:name=".Iat">
                         <intent-filter>
                         <action android:name="android.intent.action.MAIN"/>
                         <category android:name="android.intent.category.LAUNCHER" />
                         </intent-filter>
                         <meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
                      </activity>
        </application>
    </manifest>
    

    6.导出AAR

    在这里插入图片描述
    等待重构完成,再点击这个
    在这里插入图片描述
    我们看到建立的aar包已经完成了
    在这里插入图片描述
    在文件夹中打开
    在这里插入图片描述
    libs里面有classes.jar包,删除它,把外面这个classes.jar放进去,你发现libs里面没有armeabi-v7a,在你项目里找到它拷贝进去完成后进行下一步
    在这里插入图片描述
    留下这四个文件,待会要拷贝到Unity里面。
    在这里插入图片描述

    第三步:Unity中要做的事

    1. 搭界面

    建立工程搭建界面:
    在这里插入图片描述

    2. 放资源

    建立一个文件夹Plugins/Android,刚刚的文件放进去
    在这里插入图片描述

    在之前下载的讯飞包里找到这两个文件然后放入Unity Assets/Android/Plugins/assets/iat里
    在这里插入图片描述
    补充一下:
    打开Unity里刚刚导入的AndroidMainfest.xml,添加这两行,不然待会你在Unity里设置的名称和图标会无用
    在这里插入图片描述

    3.敲代码

    新建一个脚本:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Iatdemo : MonoBehaviour
    {
        private AndroidJavaClass ajc;
        private AndroidJavaObject ajo;
    
        public Button startBtn;
        public Button exitBtn;
        public Text resultText;
    
        private void Awake()
        {
            startBtn = GameObject.Find("Canvas/Button").GetComponent<Button>();
            exitBtn = GameObject.Find("Canvas/Button_2").GetComponent<Button>();   
            resultText = GameObject.Find("Canvas/Text").GetComponent<Text>();
            
        }
    
        // Use this for initialization
        void Start ()
        {
            ajc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            ajo = ajc.GetStatic<AndroidJavaObject>("currentActivity");
            if (startBtn)
            {
                startBtn.onClick.AddListener(()=> { StartListening(); } );
            }
            if (exitBtn)
            {
                exitBtn.onClick.AddListener(()=> { Quit(); });
            }
     
    	}
    
        public void StartListening()
        {        
            ajo.Call("StartListening", "点击了监听");
        }
      
        public void OnStartListening(string ret)
        {
            int result = int.Parse(ret);
            startBtn.interactable = result == 0;
        }
    
        public void OnResult(string result)
        {
            resultText.text = result;
        }
    
        public void OnError(string errorMessage)
        {
            resultText.text = errorMessage;
        }
    
        public void OnEndOfSpeech()
        {
            startBtn.GetComponentInChildren<Text>().text = "点击倾听";
            startBtn.interactable = true;
        }
    
        public void OnBeginOfSpeech()
        {
            startBtn.GetComponentInChildren<Text>().text = "倾听中";
            startBtn.interactable = false;
        }
    
    
        public void Quit()
        {
            Application.Quit();
        }
    }
    

    将这个脚本挂载在GameObject上

    4.导出apk

    这里的包名记得和之前AS里面的模块里的包名是一致的,这里的应用名称和应用图标也填一下,之前在xml里如果没有新增那两条的话,这里填了也没有用
    在这里插入图片描述
    接下来点击Build然后把apk安装在android上

    展开全文
  • 讯飞离线语音命令词+TTS离线发音,实现命令词交互(windows dll for unity插件) 步骤一 登录讯飞平台注册并创建自己的应用 https://www.xfyun.cn 步骤二 下载离线命令词识别SDK windows MSC ,注意下载...
  • 讯飞输入法安卓版离线语音包V5高配版。 解压出Speech文件夹,放置到SD卡的Iflyime目录里即可。 注意事项: 下载了离线语音包仍然不能用的亲看过来 1、文件放到指定目录下“Iflyime”,如果软件是装在机身存储卡的那...
  • Unity 接讯飞离线语音识别

    千次阅读 2019-12-04 15:38:43
    Unity 接入讯飞离线SDK , 有一些坑记录一下。 在开发者平台注册之后,申请应用,下载SDK包。这个sdk包和你的appid是对应的,不能使用别人的sdk包,然后用自己的appid 这是SDK文件夹,sample是一个示例工程,将...
  • fzcjfcSpeechRecognition_讯飞离线语音词识别vs2010_语音识别.zip
  • fzcjfcSpeechRecognition_讯飞离线语音词识别vs2010_语音识别_源码.zip
  • Linux下,使用Python调用讯飞TTS离线SDK,源代码: https://github.com/cch96/iflytek_tts 具体使用方法参照readme 解决过程 Windows Windows的SDK有编译好的可以直接被python用ctypes模块调用的动态链接库。可以...
  • 讯飞离线语音命令词识别

    万次阅读 2017-12-28 17:58:50
    讯飞离线语音命令词识别 1、注册并下载sdk 2、创建工程 3、权限 4、拷贝jar包 5、初始化引擎 6、功能代码 7、打赏1、注册并下载sdk讯飞官网地址:http://www.xfyun.cn/*选择立即开通并登录* 弹出对话框,选择创建...
  • 原因是并未使用 SpeechUtility.createUtility(this, param.toString());函数来初始化sdk权限,在使用听写功能之前调用该函数即可。
  • 测试通过的C#讯飞语音识别离线命令词demo,适用于用C#和unity接入讯飞语音的开发者
  • 讯飞离线语音合成(语记)

    万次阅读 2016-12-22 17:59:41
    讯飞语音的合成有三种方式: 1.在线语音合成(免费) 2.离线使用讯飞语记合成(免费,需要在本地下载语记APP) 3.使用离线合成SDK(收费) 公司这次的需求是做一个听书的功能,就是将文字合成语音播放出来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,001
精华内容 400
关键字:

讯飞离线语音