使用腾讯语音合成技术生成有声书

摘要:
“您的钥匙”);“ap beijing”);TextToVoiceResponsetextToVoiceResponse=aaiClient.TextToVoice(请求);StringUtils.isEmpty(音频)){System.out.println(音频);BASE64Decoderder=newBASE64Decode();

  背景:不知是否在博客园看到的腾讯云平台广告,被AI接口几个项目吸引住了,其中有个   语音合成  接口在这里安利一下,还挺好玩。这个接口提供将一段文字转换成语音的功能,支持中文、英文,遗憾的是暂时无法通过自己的声音进行训练,推出自己独有声音的音频文件:) 不过总体来说,还是相当不错啦,附件中是我用这个接口转换的样例音频文件。

DEMO实测,代码案例简单概述:

首先,调用接口肯定得申请appkey,secrect等一堆东西,在这里申请

申请,完成后会获得公共请求参数必须的信息,然后接口调用分为直接http请求与使用官方版本的sdk调用2种方式,建议使用sdk调用的方式,避免还得自己加sign。sdk调用的方式很简单,测试demo如下:

 @Test
    public void testAi() throws TencentCloudSDKException, IOException, UnsupportedAudioFileException, LineUnavailableException {
        Credential cred = new Credential("你的ID", "你的key");

        AaiClient aaiClient = new AaiClient(cred, "ap-beijing");
        TextToVoiceRequest request = new TextToVoiceRequest();
        request.setProjectId(10144947);
        request.setModelType(1);
        request.setPrimaryLanguage(1);
//        request.setSampleRate();
        request.setSessionId("testsessionid");
        request.setSpeed(1F);
        request.setText("你好啊,你爱我么");
        request.setVoiceType(1);
        request.setVolume(1F);
        TextToVoiceResponse textToVoiceResponse = aaiClient.TextToVoice(request);
        String audio = textToVoiceResponse.getAudio();

        if (!StringUtils.isEmpty(audio)) {
            System.out.println(audio);


            BASE64Decoder decoder = new BASE64Decoder();
            try {
                byte[] data = decoder.decodeBuffer(audio);
                OutputStream out = new FileOutputStream("d://test1.wav");
                out.write(data);
                out.flush();
                out.close();
            } catch (Exception ex) {

            }
        }
    }

本人喜欢在喜马拉雅上听书,也听小说。看到有很多连普通话都不甚标准的作者有了大量的粉丝,还有打赏。在此我有了一个大胆的想法,在不涉及版权问题的前提下,我是否可以上传一大堆小说的音频内容,以量取胜,。实际测试中发现腾讯语音合成接口默认只支持300个字符,且生成的音频文件为BASE64的String字符串,需要进行拼接转换。当然拼接并不是说把api返回的string直接通过一个stringbuilder拼起来就行,因为wav文件结构中是有头尾标示的,拼接过程当中需要去头尾,拼接转换部分源码如下:

 @Scheduled(fixedDelay = 1000 * 60 * 60)
    public void toVoice() {
        String textFilePath="D://work/mywork/txt/孙子兵法/计篇.txt";
        String outputPath="D://work/mywork/voice/孙子兵法/计篇.wav";
        try {
            File output=new File(outputPath);
            logger.info("开始获取文件内文本数据");
            List<String> stringArray = fileManService.getStringArray(textFilePath, 100);
            if (stringArray != null) {
                List<String> voiceWaves=new ArrayList<String>();
                for(String tmpText :stringArray)
                {
                    voiceWaves.add(voiceManService.getWavString(tmpText));
                }
                WavBaseStringMergeUtil wavBaseStringMergeUtil=new WavBaseStringMergeUtil();
                File file=new File(outputPath);
                wavBaseStringMergeUtil.mergeWav(voiceWaves,file);
                logger.info("完成");
            } else {
                logger.info("获取到的文本内容为空");
            }

        } catch (Exception e) {
            logger.error("转换出现异常", e);
        }
    }
private static Header resolveHeader(byte[] Basebytes) throws IOException {
        InputStream fis = new ByteArrayInputStream(Basebytes);
        byte[] byte4 = new byte[4];
        byte[] buffer = new byte[2048];
        int readCount = 0;
        Header header = new Header();
        fis.read(byte4);//RIFF
        fis.read(byte4);
        readCount += 8;
        header.fileSizeOffset = 4;
        header.fileSize = byteArrayToInt(byte4);
        fis.read(byte4);//WAVE
        fis.read(byte4);//fmt
        fis.read(byte4);
        readCount += 12;
        int fmtLen = byteArrayToInt(byte4);
        fis.read(buffer, 0, fmtLen);
        readCount += fmtLen;
        fis.read(byte4);//data or fact
        readCount += 4;
        if (isFmt(byte4, 0)) {//包含fmt段
            fis.read(byte4);
            int factLen = byteArrayToInt(byte4);
            fis.read(buffer, 0, factLen);
            fis.read(byte4);//data
            readCount += 8 + factLen;
        }
        fis.read(byte4);// data size
        int dataLen = byteArrayToInt(byte4);
        header.dataSize = dataLen;
        header.dataSizeOffset = readCount;
        readCount += 4;
        header.dataOffset = readCount;
        header.dataInputStream = fis;
        return header;
    }

 至此,基本可以满足咱们转换小说的需要啦!!!今天也上传了第一套专辑《孙子兵法》 到喜马拉雅试试水,大家有感兴趣的可以去听一下语音合成的效果,如果给您带来帮助,请不要吝惜动下手指 帮忙点赞哟!

代码、文字文本交流可以私信也可以评论中留言,

想听书的再也不用担心没书可听了,有想听书的朋友可以私信我有版权的文本内容,帮你转换哦。走路、吃饭、开车,想听就听……

百度语音合成SDK

接着上次的内容,又找了下百度和阿里的语音合成sdk,发现百度和阿里的相对腾讯的语音合成貌似更加成熟,使用方法什么的就不赘述了,直接上API地址,懂的自然懂。

不论是百度的还是腾讯的语音合成接口单次请求的字符数是有限制的,而我们的小说文档都很长,在之前的处理当中我是定长100处理的。会造成明明连着的一个成语或者词组,比如 “你好啊,我亲爱的朋友”,如果按照定长2个字符来处理,就会变成“你好”、“啊,我”等等,在生成音频文件合成后,连续的读起来时会发现这种断句有明显的停顿,体验很不好,因此增加如下方式,默认按照定长字符处理,但是会智能化的去寻找离定长最近的逗号、或者句号来进行断句。这样就不会出现生硬的分开本应连在一起读的词语了

处理代码如下:

  /**
     * 按照给定的字符串长度在指定文本中查找最接近指定长度的逗号或者句号的endindex。若找不到则以指定长度作为endindex
     * @param inputString
     * @param length
     * @return
     */
    private int getEndIndex(String inputString,int length)
    {
        if(length>inputString.length())
        {
            return inputString.length();
        }
        int retIndex= length;
        for(int i=retIndex-1;i>0;i--)
        {
            if(inputString.charAt(i)=='.' || inputString.charAt(i)=='。' || inputString.charAt(i)==',' || inputString.charAt(i)==',')
            {
                retIndex =i;
                break;
            }
        }
        return retIndex;
    }

    /**
     * 智能拆分文本
     * @param inputString
     * @param length
     * @return
     */
    private List<String> getStrListIntelligence(String inputString,int length)
    {
        List<String> StrList=new ArrayList<String>();
        int indexStart=0;
        while (indexStart<inputString.length())
        {
            //查找endIndex
            int endIndex = this.getEndIndex(inputString.substring(indexStart,indexStart+length<inputString.length()?indexStart+length:inputString.length()),length);
            String tmpString = inputString.substring(indexStart,indexStart+ endIndex);
            StrList.add(tmpString);
            indexStart+=endIndex;
        }
        return  StrList;
    }

免责声明:文章转载自《使用腾讯语音合成技术生成有声书》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇python(leetcode)-350两个数组的交集HIBERNATE锁机制下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

BTC_ETH_USDT_自动充提币API接口,钱包对接交易所教程!

 以目前市面上用的最多的优盾钱包开放平台为例。 详细的接口文档如下: 官方接口文档链接:https://www.uduncloud.com/gateway-interface 1、目录 1.1、生成地址 1.2、提币 1.3、代付 1.4、交易回调 1.5、校验地址合法性 1.6、获取商户支持币种信息 2、接口明细 1、生成地址 1.1 场景说明 请求指...

DOM,javascript,Web API之间的关系——onclick 引起的思考与调研

平时习惯了用js操作dom树来与html页面进行交互,基本都是通过web API接口实现的,最近看闭包和原生js的知识点比较多,昨天无意中看到了onclick中的this指向问题,遂用native js方式模拟了onclick再html标签里的this和js事件里的this,详见上一篇博客:用js的eval函数模拟Web API中的onclick事件 下文...

【苏勇老师Linux 入门笔记】网络基础

IP 地址   IP 编制时一个双层编制方案,一个 IP 地址标示一个主机 (或一个网卡接口)。 一个 IP 地址分为两个部分:网络部分(所属区域)和主机部分(标示区域中的哪个主机)。IPv4 共32位,通常用点分十进制表示。 子网掩码用于将网络部分和主机部分区分开来,子网掩码为1(二进制)的部分为网络部分。   MAC地址主要用于同网络间主机的通信...

linux/windows 双平台csv文件生成方法

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。 1、linux/windows 可移植 #include <stdio.h> int main() { FILE *fp; char const *fileTit...

解决微信公众平台接口配置信息配置失败问题

填写好URL及TOKEN后,点“提交”时,总是提示“配置失败”或其他错误 确认URL指向的后台页面代码没有问题 确认TOKEN配置没有问题 这时请察看一下你的INDEX页面的编码格式,改成GB2312试试吧,也许会令你的问题迎刃而解。 谨以此文献给浮躁的自己。...

03生成微博授权的url接口(再也没有你了)

生成微博授权url接口 (再也没有你了) 相信朋友们对微博开放平台的使用以及有了进一步的了解,那么接下来我们来看看怎么使用微博开放平台: 1.创建apps/oauth模块进行oauth认证 '''1.1在apps文件夹下新建应用: oauth''' cd syl/apps python ../manage.py startapp oauth # 切换到a...