利用百度API实现语音合成

【!最终呈现方式为jar包直接运行,实现原理等可供参考】

运行图
在这里插入图片描述
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓以下是正文↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

1.注册百度开发者

(1)语音合成的方式有很多,为了简洁,我们使用第三方语音合成API,这里选择百度语音。详细注册流程官方文档很详细,这里不做过多介绍。传送门,我们需要的是AppID,API Key和Secret Key 如下图
在这里插入图片描述
(2)我们要做java后台处理,所以使用java JDK即可,传送门
在这里插入图片描述

2使用Idea进行程序的编写

(1)创建普通maven工程即可,相信优秀的你一定都会了,这里不啰嗦了。
(2)引入依赖

		  <!-- lombok神器-->
		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
          <!-- 百度API -->
        <dependency>
            <groupId>com.baidu.aip</groupId>
            <artifactId>java-sdk</artifactId>
            <version>4.11.3</version>
        </dependency>

(3)创建百度语音合成工具类
ConstansHelper.java

import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.TtsResponse;
import com.baidu.aip.util.Util;
import lombok.Data;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
 * @Desc:
 * @Author: wangyafei
 * @Date: 2019/9/5 18:04
 * @Version 1.0
 */
@Data
public class ConstansHelper {
    //设置APPID/AK/SK 注册百度开发者会生成
    public static final String APP_ID = "APP_ID ";
    public static final String API_KEY = "API_KEY ";
    public static final String SECRET_KEY = "SECRET_KEY ";
     /**
     * @param spd 语速,取值0-15,默认为5中语速
     * @param pit 音调,取值0-15,默认为5中语调
     * @param vol 音量,取值0-15,默认为5中音量
     * @param per 发音人选择, 0为女声,1为男声,
     *            3为情感合成-度逍遥,
     *            4为情感合成-度丫丫,默认为普通女
     * @param txt 要转换的文本
     */
    public static String makeSpeech(String spd, String pit, String vol, String per, String txt) {
        // 初始化一个AipSpeech
        AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);

        // 可选:设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        // 设置可选参数
        HashMap<String, Object> options = new HashMap<String, Object>();
        if (!"请选择".equals(spd)) {
            options.put("spd", spd);
        }
        if (!"请选择".equals(pit)) {
            options.put("pit", pit);
        }
        if (!"请选择".equals(vol)) {
            options.put("vol", vol);
        }
        if (!"请选择".equals(per)) {
            switch (per){
                case "女声":
                    options.put("per", 0);
                    break;
                case "男声":
                    options.put("per", 1);
                    break;
                case "情感合成-度逍遥":
                    options.put("per", 3);
                    break;
                case "情感合成-度丫丫":
                    options.put("per", 4);
                    break;
            }
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dirName = sdf.format(new Date());
        isChartPathExist("D:\\音频合成\\" + dirName);

        // 调用接口
        //合成文本长度必须小于1024字节,如果本文长度较长,可以采用多次请求的方式。文本长度不可超过限制
        List<String> txtList = splitFunction(txt, 1024);
        byte[] all =null;
        for (String s : txtList) {
            TtsResponse res = client.synthesis(s, "zh", 1, options);
            byte[] data = res.getData();
            if(data != null){
                all = byteMerger(all,data);
            }
        }
        //存储位置,自己决定放到哪里,我放到了D盘
        String fileName  ="D:\\音频合成\\" + dirName + "\\" + (txt.length()>15?txt.substring(0, 15):txt) + "-"+System.currentTimeMillis() + "output.mp3";
        if (all != null) {
            try {
                Util.writeBytesToFileSystem(all, fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        File file = new File(fileName);
        return fileName;

    }


    /**
     * 文件夹磁盘路径 文件夹不存在创建文件夹
     * @param dirPath
     */
    private static void isChartPathExist(String dirPath) {

        File file = new File(dirPath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 根据字节长度进行切割
     * 中文在不同编码中占用的字节数是不同的,GBK编码中,一个汉字占两个字节,UTF-8编码格式中,一个汉字占3个字节
     * @param src
     * @param bytes
     * @return
     */
    public static List<String> splitFunction(String src, int bytes){
        try {
            if(src == null){
                return null;
            }
            List<String> splitList = new ArrayList<String>();
            int startIndex = 0;    //字符串截取起始位置
            int endIndex = bytes > src.length() ? src.length() : bytes;  //字符串截取结束位置
            while(startIndex < src.length()){
                String subString = src.substring(startIndex,endIndex);
                //截取的字符串的字节长度大于需要截取的长度时,说明包含中文字符
                //在GBK编码中,一个中文字符占2个字节,UTF-8编码格式,一个中文字符占3个字节。
                while (subString.getBytes("GBK").length > bytes) {
                    --endIndex;
                    subString = src.substring(startIndex,endIndex);
                }
                splitList.add(src.substring(startIndex,endIndex));
                startIndex = endIndex;
                //判断结束位置时要与字符串长度比较(src.length()),之前与字符串的bytes长度比较了,导致越界异常。
                endIndex = (startIndex + bytes) > src.length() ?
                        src.length()  : startIndex+bytes ;

            }
            return splitList;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 合并两个byte数组
      * @param byte_1
     * @param byte_2
     * @return
     */
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){
        if(byte_1 == null){
            return byte_2;
        }
        byte[] byte_3 = new byte[byte_1.length+byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }
}

(4)创建GUI文件
网上大多数是,直接创建一个Test.form页面的教程, 感觉也不是很方便,这里采用直接写代码的方式。
Container.java


import org.springframework.util.StringUtils;
import org.wyf.yuyindemo.utils.ConstansHelper;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;


/**
 * @Desc:
 * @Author: wangyafei
 * @Date: 2019/9/6 10:47
 * @Version 1.0
 */
public class Container extends Thread implements ActionListener, WindowListener {

    private static int totalTime = 40;
    private static float totalDiff = 0.0f;
    private TextField txt;
    private TextArea taLog;         //日志输出区域 不可以设置颜色相关
    private JButton jbtStart,jbtReset;       //开始按钮;重置按钮
    private JComboBox spd,pit,vol,per;//语速,语调。音量,角色
    private JLabel tips;

    @Override
    public void run() {
        //画页面
        //父窗体
        JFrame jFrame = new JFrame("语音生成小工具");
        // 创建按钮
        jbtStart = new JButton("生成");
        jbtReset = new JButton("重置");

        jbtStart.addActionListener(this);
        jbtReset.addActionListener(this);

        // 创建相关的文本域
        txt = new TextField("我是文本");

        spd = new JComboBox();
        pit = new JComboBox();
        vol = new JComboBox();
        per = new JComboBox();
        spd.addItem("请选择");
        pit.addItem("请选择");
        vol.addItem("请选择");
        for (int i = 0; i <15 ; i++) {
            spd.addItem(i);
            pit.addItem(i);
            vol.addItem(i);
        }
        per.addItem("请选择");
        per.addItem("女声");
        per.addItem("男声");
        per.addItem("情感合成-度逍遥");
        per.addItem("情感合成-度丫丫");

        JLabel jb1 = new JLabel("   语速");
        JLabel jb2 = new JLabel("   语调");
        JLabel jb3 = new JLabel("   音量");
        JLabel jb4 = new JLabel("   角色");

        JPanel sel = new JPanel(new GridLayout(4,2));
        sel.add(jb1);
        sel.add(spd);
        sel.add(jb2);
        sel.add(pit);
        sel.add(jb3);
        sel.add(vol);
        sel.add(jb4);
        sel.add(per);

        taLog = new TextArea();
        taLog.setColumns(30);
        taLog.setRows(150);
        taLog.setBackground(Color.CYAN);
        taLog.setFont(new Font("宋体",Font.BOLD,16));
        taLog.setEditable(false);

        // 创建相关的Label标签
        JLabel labelStart = new JLabel("请输入文本:");
        JLabel labelTip1 = new JLabel("<html>仅供测试<br>如有问题请联系<br>QQ772173722</html>");

        //提示输入文本
        JPanel inputTxt = new JPanel(new GridLayout(2, 1));
        inputTxt.add(labelStart,BorderLayout.CENTER);
        inputTxt.add(txt,BorderLayout.CENTER);

        //开始按钮及左右信息
        JPanel panel4 = new JPanel(new GridLayout(1, 3));
        panel4.add(labelTip1);
        panel4.add(jbtStart);
        panel4.add(jbtReset);

        JPanel log = new JPanel(new GridLayout(1,1));
        tips = new JLabel();
        log.add(tips);


        //上级布局
        JPanel panel22 = new JPanel(new GridLayout(4,1));
        panel22.add(sel);
        panel22.add(inputTxt);
        panel22.add(panel4);
        panel22.add(tips);

        jFrame.setLayout(new BorderLayout());
        jFrame.add(panel22, BorderLayout.CENTER);

        // 初始化JFrame窗口
        jFrame.setLocation(800, 300);
        jFrame.setSize(600, 500);
        jFrame.setBackground(Color.darkGray);
        jFrame.setResizable(true);
        jFrame.setVisible(true);

    }

    /**
     * 点击监听器
     * @param view
     */
    @Override
    public void actionPerformed(ActionEvent view) {
        if (view.getSource() == jbtStart) {
            String spdStr =spd.getSelectedItem().toString();
            String pitStr = pit.getSelectedItem().toString();
            String volStr = vol.getSelectedItem().toString();
            String perStr = per.getSelectedItem().toString();
            String txtStr =txt.getText() ;

            if (!StringUtils.isEmpty(spdStr) && !StringUtils.isEmpty(pitStr) && !StringUtils.isEmpty(volStr) && !StringUtils.isEmpty(perStr) && !StringUtils.isEmpty(txtStr)) {
                makeSpeech(spdStr,pitStr,volStr,perStr,txtStr);
            }
        }else if(view.getSource() == jbtReset){
            //重置组件内容
            tips.setText(null);
            txt.setText("我是文本");
            spd.setSelectedIndex(0);
            per.setSelectedIndex(0);
            pit.setSelectedIndex(0);
            vol.setSelectedIndex(0);
        }
    }

    /**
     * 合成语音
     * @param spdStr
     * @param pitStr
     * @param volStr
     * @param perStr
     * @param txtStr
     */
    private void makeSpeech(String spdStr, String pitStr, String volStr, String perStr, String txtStr) {
        String fileName = ConstansHelper.makeSpeech(spdStr, pitStr, volStr, perStr, txtStr);
        if(!StringUtils.isEmpty(fileName)){
            //返回值 ,0=是,1=否,2=取消
            int dialog = JOptionPane.showConfirmDialog(null, "合成成功!是否打开文件所在位置?");
            tips.setText("文件位置: "+fileName);

            if(dialog == 0) {
                try {
                    String open = fileName.substring(0, fileName.lastIndexOf("\\"));
                    //打开文件所在位置
                    Runtime.getRuntime().exec("explorer.exe " + open);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    @Override
    public void windowOpened(WindowEvent e) {

    }

    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    @Override
    public void windowClosed(WindowEvent e) {
        System.exit(0);
    }

    @Override
    public void windowIconified(WindowEvent e) {

    }

    @Override
    public void windowDeiconified(WindowEvent e) {

    }

    @Override
    public void windowActivated(WindowEvent e) {

    }

    @Override
    public void windowDeactivated(WindowEvent e) {

    }

    public static void main(String[] args) {
        Container container = new Container();
        container.run();
    }
}

3.生成Jar包

(1)默认情况下项目设置project structure(快捷键ctrl+alt+shift+S)里是没有artifacts的,我们新增一个
在这里插入图片描述
(2)选择main方法所在的类
在这里插入图片描述
注:如果出现"点击jar包没有反应,没有清单文件主函数"的问题,修改目录到src下即可
修改前:在这里插入图片描述
修改后:在这里插入图片描述
(3)此时build一下就可以啦
在这里插入图片描述
在这里插入图片描述

### 回答1: 百度API语音合成 C是指通过使用百度提供的API接口,使用C语言进行语音合成操作。百度API语音合成是一项人机交互技术,通过将文字转换为语音,使计算机能够更加贴近人类的交流方式。 在使用百度API语音合成 C时,我们可以通过简单的代码编写,实现文字转语音的功能。首先,我们需要调用相应的API接口,传入要合成的文字内容,然后选择合适的语音风格和音频格式等参数,最后将合成的语音保存或播放出来。 百度API语音合成 C主要应用于语音交互系统、智能客服、语音朗读器等场景。例如,我们可以将其应用于机器人的语音对话系统中,使机器人能够通过语音与用户进行交流;或者将其应用于智能客服系统中,让客服机器人通过语音与用户沟通,提供更加便捷和人性化的服务。 此外,百度API语音合成 C还可以根据不同的语音风格,实现不同的语音合成效果。例如,我们可以选择男声或女声,选择语速、音调、音量等参数,以更好地满足不同场景和用户的需求。 总之,百度API语音合成 C是一个强大而灵活的工具,它通过将文字转换为语音,实现了人机交互的目标。无论是应用于智能设备还是语音交互系统,都能够提供更加便捷和便于理解的交流方式。 ### 回答2: 百度API语音合成C 是指基于百度语音技术平台开发的语音合成程序,使用C语言进行开发和调用。百度语音合成是一种将文字转换为语音的人工智能技术,能够将输入的文字信息转化为自然流畅的人声音频。通过百度API语音合成C,开发者可以将其集成到自己的应用程序中,实现文字转语音的功能。 百度API语音合成C 的开发和调用相对简单,只需按照相应的开发文档,调用相关接口即可。首先,开发者需要在百度开放平台上申请一个开发者账号,并创建一个应用,获取相应的API Key和Secret Key进行身份验证。然后,通过调用百度语音合成API的接口,将输入的文字信息发送给API进行语音合成API会将合成的音频文件返回给开发者。开发者可以根据自己的需要,设置合成语音的声音、速度、音调等参数。 百度API语音合成C 可以应用于多个领域,如智能助理、语音导航、教育培训、无障碍应用等。开发者可以根据具体需求,将语音合成功能集成到自己的应用程序中,从而提供更加友好、便捷的用户体验。 综上所述,百度API语音合成C 是一种基于百度语音技术平台开发的语音合成程序,使用C语言进行开发和调用,可以将文字信息转化为自然流畅的人声音频。通过百度API语音合成C,开发者可以快速集成语音合成功能,并应用于各种应用场景中。 ### 回答3: 百度API语音合成是一项人工智能技术,它利用百度自然语言处理的技术,将文字合成为自然流畅的语音。这项技术可以应用于多个领域,如智能语音助手、有声读物、智能客服等。 百度API语音合成 C 是其中的一种版本,它是基于C语言进行开发和使用的。使用C语言进行开发可以有效地提高语音合成的效率和性能,并且可以适应不同的操作系统和平台。通过百度API语音合成 C,开发者可以方便地集成语音合成功能到自己的软件或应用中。 百度API语音合成 C 提供了丰富的功能和接口,开发者可以通过调用相应的API实现文字到语音的转换。开发者可以自定义语音的参数,如语速、音量、声音类型等,以实现更好的效果。此外,百度API语音合成 C 还支持多种语言的文字合成,包括中文、英文、日文等。 对于开发者来说,使用百度API语音合成 C 只需要简单的几步操作。首先,需要进行开发者身份认证并获取API密钥。然后,通过API调用接口实现文字合成。最后,将合成的语音保存或输出到需要的地方。 总的来说,百度API语音合成 C 是一项方便、高效的技术,可以帮助开发者实现语音合成功能,提升应用的交互体验和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值