语音合成


发音人

发音人列表

合成分类

  • 代码主动合成推荐):开发者主动调用合成接口。

  • 语义后合成:AIUI云端自动调用语音合成(取语义理解的answer字段的text值)。开启后,所有技能回复都会自动合成,无法控制单个技能不合成

主动合成

免费发音人:小娟、聆小樱、聆小璇(在AIUI应用配置页面,开启语音合成能力并选择对应发音人进行保存来激活)

主动合成集成示例:在线TTS

注:一次请求最多合成2000字

// 获取待合成文本
String ttsStr = "我是要合成的文本";
// 转为二进制数据
byte[] ttsData = ttsStr.getBytes("utf-8");
// 构建合成参数,一般包含发音人、语速、音调、音量
StringBuffer params = new StringBuffer();
// 发音人,发音人列表:https://aiui-doc.xf-yun.com/project-1/doc-93/
params.append("vcn=x2_xiaojuan");
// 语速,取值范围[0,100]
params.append(",speed=50");
// 音调,取值范围[0,100]
params.append(",pitch=50");
// 音量,取值范围[0,100]
params.append(",volume=50");

//开始合成
AIUIMessage startTTS = new AIUIMessage(AIUIConstant.CMD_TTS,AIUIConstant.START, 0, params.toString(), ttsData);
mAIUIAgent.sendMessage(startTTS);

//取消合成
AIUIMessage cancelTTS = new AIUIMessage(AIUIConstant.CMD_TTS,AIUIConstant.CANCEL, 0, params.toString(), ttsData);
mAIUIAgent.sendMessage(cancelTTS);

//暂停播放
AIUIMessage pauseTTS = new AIUIMessage(AIUIConstant.CMD_TTS,AIUIConstant.PAUSE, 0, params.toString(), ttsData);
mAIUIAgent.sendMessage(pauseTTS);

//恢复播放
AIUIMessage resumeTTS = new AIUIMessage(AIUIConstant.CMD_TTS,AIUIConstant.RESUME, 0, params.toString(), ttsData);
mAIUIAgent.sendMessage(resumeTTS);

主动合成集成示例:离线TTS

将合成发音人资源(联系商务)放到本地加载,修改aiui.cfg配置。合成接口与在线TTS一样。

资源说明

  • xtts_common.jet,离线tts通用配置
  • xtts_xiaoxue.jet,发音人xiaoxue的资源文件

发音人文件放到 assets 目录下,aiui.cfg配置相对路径。多个发音人用 ; 分割。

离线合成配置参考

aiui.cfg 配置:

"tts":{
    // 使用xtts
    "ent": "xtts",
    // 离线引擎
    "engine_type": "local",
    // 资源类型
    "res_type": "assets",
    //配置发音人
    "res_path": "xtts/xtts_common.jet;xtts/xtts_xiaoxue.jet"
},

离线发音人

联系讯飞确认

语义后合成

AIUI平台打开语音合成开启。异常情况不会合成音频,如nlp语义理解未命中(rc=4)。

可在应用配置中开启:

音频结果解析

SDK在EVENT_RESULT回调抛出合成音频和缓存进度,格式为16k 16bit pcm,解析示例:

private AIUIListener mAIUIListener = new AIUIListener() {

    @Override
    public void onEvent(AIUIEvent event) {
        
            case AIUIConstant.EVENT_RESULT: {
                try {
                    JSONObject bizParamJson = new JSONObject(event.info);
                    JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
                    JSONObject params = data.getJSONObject("params");
                    JSONObject content = data.getJSONArray("content").getJSONObject(0);
                    
                    String sub = params.optString("sub");
                    if ("tts".equals(sub)) {
                        if (content.has("cnt_id")) {
                            String sid = event.data.getString("sid");
                            String cnt_id = content.getString("cnt_id");
                            byte[] audio = event.data.getByteArray(cnt_id); //合成音频数据
                            /**
                            *
                            * dts:音频块进度信息,取值:
                            * - 0(音频开始)
                            * - 1(音频中间块,可出现多次)
                            * - 2(音频结束)
                            * - 3(独立音频,合成短文本时出现)
                            * 
                            * 举例说明:
                            * 常规合成dts顺序:
                            *   0 1 1 1 ... 2
                            * 短文本合成dts顺序:
                            *   3
                            **/
                            int dts = content.getInt("dts"); 
                            int frameId = content.getInt("frame_id");// 音频段id,取值:1,2,3,...
                            
                            int percent = event.data.getInt("percent"); //合成进度
                        
                            boolean isCancel = "1".equals(content.getString("cancel"));  //合成过程中是否被取消
                        }
                    }
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            } breakdefault:
                break;
        }
    }
};

播放模式

1.SDK自动播放(默认)
2.使用第三方播放器
将aiui.cfg的play_mode配置为user(参考TTS音频播放),开发者在EVENT_RESULT事件中获取音频后自己播放(参考音频结果解析)。

音频播放控制

aiui.cfg配置示例:

{
    "tts": {
        // 播放模式:sdk(sdk播放,默认,只支持安卓),user(开发者自己播放)
        "play_mode": "sdk",
        // 音频缓冲时长:缓冲音频大于buffer_time才播放,默认0ms
        "buffer_time": "0",
        // 音频类型,取值参考AudioManager类,默认值:3
        "stream_type": "3",
        // 播放是否抢占焦点:1(抢占), 0(不抢占,默认)
        "audio_focus": "0"
    }
}

播放状态回调

只支持Android,且播放模式为SDK:

private AIUIListener mAIUIListener = new AIUIListener() {

    @Override
    public void onEvent(AIUIEvent event) {

            case AIUIConstant.EVENT_TTS: {
                switch (event.arg1) {
                    case AIUIConstant.TTS_SPEAK_BEGIN:
                        showTip("开始播放");
                        break;

                    case AIUIConstant.TTS_SPEAK_PROGRESS:
                        showTip("缓冲进度为" + mTtsBufferProgress +
                                ", 播放进度为" + event.data.getInt("percent"));     // 播放进度
                        break;

                    case AIUIConstant.TTS_SPEAK_PAUSED:
                        showTip("暂停播放");
                        break;

                    case AIUIConstant.TTS_SPEAK_RESUMED:
                        showTip("恢复播放");
                        break;

                    case AIUIConstant.TTS_SPEAK_COMPLETED:
                        showTip("播放完成");
                        break;

                    default:
                        break;
                }
            } break;

            default:
                break;
        }
    }
};

其他

部分技能返回播报文本包含[n1][k1]等TTS发音辅助标识,可参考以下方法进行过滤消除。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class TTSUtil {
    static String REPLACE_NULL = "";
    static String REGEX_TTS_ASSIST_TAG = "\\[[a-z]\\d\\]";
    public static void main(String[] args) {
        System.out.println(removeTTSAssistTag("The [a1] dog says meow."));
    }
    public static String removeTTSAssistTag(String text){

        Pattern regex = Pattern.compile(REGEX_TTS_ASSIST_TAG);
        Matcher input =  regex.matcher(text);
        text =  input.replaceAll(REPLACE_NULL);
        return text;
    }
}

admin 2024年8月18日 19:37 收藏文档