手把手教你用JAVA调用Websocket实现“声音转换”功能(变声)标贝科技


前言

什么是声音转换?
基于深度学习和迁移学习技术,精准将原说话人的声音转换为目标说话人,同时保留原说话人的风格特色。让声音有更多的表现形式。


一、内容太长不愿意看,直接使用系列

首先确认接口调用要求:
实现方式:Websocket
支持音频文件的编码格式及文件名的后缀: pcm
支持音频文件的采样率/位深: 16000Hz/16bit
支持的语言:中文普通话
音频有效时长:不超过180分钟
确认无误后,直接执行 2.2获取权限+2.3.5完整代码示例

二、用JAVA调用标贝科技“声音转换”接口使用流程

2.1.环境准备

java

2.2.获取权限

2.1.1.登录

地址:标贝科技智能语音开放平台

点击上方地址登录,支持短信、密码、微信三种登录方式。


2.1.2.创建应用

登录后,点击创建应用,填写相关信息(未实名认证只能创建一个应用)
(注:实名认证后可获得创建多个应用的权限)

进入应用,其中包含的技术产品有:语音识别、语音合成、声音复刻、声音转换
页面中功能主要包括:服务用量管理、购买服务量管理、开发者文档、授权管理、套餐管理

2.1.3.获取token
点击声音转换—>授权管理—>显示—>获取APISecret—>(获取访问令牌token)


2.3.代码实现

2.3.1.获取token

/*** 授权:需要在开放平台获取【https://ai.data-baker.com/#/?source=qaz123】*/private static final String clientId = "输入你的clientid";private static final String clientSecret = "输入你的clientsecret";/*** 获取token的地址信息*/public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";public static String getAccessToken() {String accessToken = "";OkHttpClient client = new OkHttpClient();// request 默认是get请求String url = String.format(tokenUrl, clientSecret, clientId);Request request = new Request.Builder().url(url).build();JSONObject jsonObject;try {Response response = client.newCall(request).execute();if (response.isSuccessful()) {// 解析String resultJson = response.body().string();jsonObject = JSON.parseObject(resultJson);accessToken = jsonObject.getString("access_token");}} catch (Exception e) {e.printStackTrace();}return accessToken;}

2.3.2.配置获取音频文件路径和声音转换后的保存路径

/*** 文件路径【开发者需要根据实际路径调整。支持的音频编码格式:PCM,采样率16K,位深16bit,中文普通话,时长不超过180分钟】*/private static final String pcmFile = "";/*** 文件夹路径【声音转换后文件存放地址,开发者需要根据实际路径调整。】*/private static final String dic = "";

2.3.3.创建webscoket连接,配置接口参数
参数:
“access_token”:2.1.3中已获取
“voice_name”:代码中已提供(平台提供五种音色供你测试)
“enable_vad”:true代表启动服务端vad功能,默认false。如果启动系统会根据输入音频进行检测,过 滤环境噪音。否则直接将原始输入音频进行转换。
“align_input”:true代表输出音频与输入音频进行对齐,默认false。即开启vad时会保留静音部分,false丢弃静音部分。
“lastpkg”:是否为最后一包,当时发送最后一包数据时设置为true 告诉系统输入完成

@Overridepublic void onOpen(WebSocket webSocket, Response response) {super.onOpen(webSocket, response);this.startTime = timeBegin.get();// 该demo直接从文件中读取音频流【实际场景可能是实时从麦克风获取音频流,开发者自行修改获取音频流的逻辑即可】new Thread(() -> {File file = new File(pcmFile);// 连接成功,开始发送数据// 第二部分是一个JSON的字符串JSONObject jsonObject = new JSONObject();jsonObject.put("access_token", accessToken);jsonObject.put("voice_name", voiceName);jsonObject.put("enable_vad", true);jsonObject.put("align_input", true);jsonObject.put("lastpkg", false);int length = jsonObject.toJSONString().getBytes().length;// 第一部分byte[] b = new byte[4];b[0] = (byte) (length >> 24 & 0xFF);b[1] = (byte) (length >> 16 & 0xFF);b[2] = (byte) (length >> 8 & 0xFF);b[3] = (byte) (length & 0xFF);FileInputStream fileInputStream = null;ByteArrayOutputStream byteOut = null;try {fileInputStream = new FileInputStream(file);byteOut = new ByteArrayOutputStream();int size = 32000;byte[] byteArray = new byte[size];int totalLength = 0;int read = 0;// 发送音频while ((read = fileInputStream.read(byteArray, 0, size)) > 0) {totalLength += read;System.out.println();if (read == size && totalLength < file.length()) {byte[] bytes = ArrayUtils.addAll(ArrayUtils.addAll(b, jsonObject.toJSONString().getBytes()), byteArray);webSocket.send(new ByteString(bytes));Thread.sleep(40);} else {// 最后一包jsonObject.put("lastpkg", true);length = jsonObject.toJSONString().getBytes().length;b[0] = (byte) (length >> 24 & 0xFF);b[1] = (byte) (length >> 16 & 0xFF);b[2] = (byte) (length >> 8 & 0xFF);b[3] = (byte) (length & 0xFF);byte[] subarray = ArrayUtils.subarray(byteArray, 0, read);byte[] bytes = ArrayUtils.addAll(ArrayUtils.addAll(b, jsonObject.toJSONString().getBytes()), subarray);webSocket.send(new ByteString(bytes));}}System.out.println("all data is send");} catch (Exception e) {e.printStackTrace();} finally {if (fileInputStream != null) {try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if (byteOut != null) {try {byteOut.close();} catch (IOException e) {e.printStackTrace();}}}}).start();}

2.3.4.接收返回的语音流并写入文件

@Overridepublic void onMessage(WebSocket webSocket, ByteString bytes) {super.onMessage(webSocket, bytes);byte[] byteArray = bytes.toByteArray();// byte[]转lengthint length = (byteArray[0] << 24) + (byteArray[1] << 16) + (byteArray[2] << 8) + byteArray[3];byte[] jsonArray = ArrayUtils.subarray(byteArray, 4, 4 + length);String jsonStr = new String(jsonArray);JSONObject jsonObject = JSONObject.parseObject(jsonStr);byte[] subarray = ArrayUtils.subarray(byteArray, 4 + length, byteArray.length);File resultPcmFile = new File(dic, new File(pcmFile).getName().replace(".pcm", "_result.pcm"));if (!resultPcmFile.exists()) {try {resultPcmFile.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {// 写入文件FileOutputStream outputStream = new FileOutputStream(resultPcmFile, true);IOUtils.write(subarray, outputStream);IOUtils.closeQuietly(outputStream);if ((int) jsonObject.get("errcode") == 0) {if (jsonObject.getBoolean("lastpkg")) {//说明数据全部返回完毕,可以关闭连接,释放资源System.out.println("session end ");System.out.println(sdf.format(startTime) + "开始");System.out.println(sdf.format(timeEnd.get()) + "结束");System.out.println("耗时:" + (timeEnd.get().getTime() - startTime.getTime()) + "ms");System.out.println("本次识别traceId ==》" + jsonObject.getString("traceid"));webSocket.close(1000, "");}} else {System.out.println("errCode=>" + jsonObject.getInteger("errcode") + " errMsg=>" + jsonObject.getString("errmsg") + " traceId=" + jsonObject.getString("traceid"));// 关闭连接webSocket.close(1000, "");System.out.println("发生错误,关闭连接");return;}} catch (Exception e) {e.printStackTrace();}}

2.3.5.完整代码示例

package ......import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import okio.ByteString;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;/*** 声音转换WebSocket API接口调用示例* 附:声音转换Websocket API文档 【https://www.data-baker.com/specs/file/vc_api_websocket】* <p>* 注意:仅作为demo示例,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成** @author data-baker*/
public class VcWebSocketDemo extends WebSocketListener {/*** 授权:需要在开放平台获取【https://ai.data-baker.com/#/?source=qaz123】*/private static final String clientId = "输入你的clientid";private static final String clientSecret = "输入你的clientSecret";/*** 获取token的地址信息*/public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";private static final String hostUrl = "wss://openapi.data-baker.com/ws/voice_conversion";/*** 文件路径【开发者需要根据实际路径调整。支持的音频编码格式:PCM,采样率16K,位深16bit,中文普通话,时长不超过180分钟】*/private static final String pcmFile = "";/*** 文件夹路径【声音转换后文件存放地址,开发者需要根据实际路径调整。】*/private static final String dic = "";private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");// 开始时间private static ThreadLocal<Date> timeBegin = ThreadLocal.withInitial(() -> new Date());// 结束时间private static ThreadLocal<Date> timeEnd = ThreadLocal.withInitial(() -> new Date());// 发音人private String voiceName = "Vc_baklong";private Date startTime;private String accessToken = getAccessToken();@Overridepublic void onOpen(WebSocket webSocket, Response response) {super.onOpen(webSocket, response);this.startTime = timeBegin.get();// 该demo直接从文件中读取音频流【实际场景可能是实时从麦克风获取音频流,开发者自行修改获取音频流的逻辑即可】new Thread(() -> {File file = new File(pcmFile);// 连接成功,开始发送数据// 第二部分是一个JSON的字符串JSONObject jsonObject = new JSONObject();jsonObject.put("access_token", accessToken);jsonObject.put("voice_name", voiceName);jsonObject.put("enable_vad", true);jsonObject.put("align_input", true);jsonObject.put("lastpkg", false);int length = jsonObject.toJSONString().getBytes().length;// 第一部分byte[] b = new byte[4];b[0] = (byte) (length >> 24 & 0xFF);b[1] = (byte) (length >> 16 & 0xFF);b[2] = (byte) (length >> 8 & 0xFF);b[3] = (byte) (length & 0xFF);FileInputStream fileInputStream = null;ByteArrayOutputStream byteOut = null;try {fileInputStream = new FileInputStream(file);byteOut = new ByteArrayOutputStream();int size = 32000;byte[] byteArray = new byte[size];int totalLength = 0;int read = 0;// 发送音频while ((read = fileInputStream.read(byteArray, 0, size)) > 0) {totalLength += read;System.out.println();if (read == size && totalLength < file.length()) {byte[] bytes = ArrayUtils.addAll(ArrayUtils.addAll(b, jsonObject.toJSONString().getBytes()), byteArray);webSocket.send(new ByteString(bytes));Thread.sleep(40);} else {// 最后一包jsonObject.put("lastpkg", true);length = jsonObject.toJSONString().getBytes().length;b[0] = (byte) (length >> 24 & 0xFF);b[1] = (byte) (length >> 16 & 0xFF);b[2] = (byte) (length >> 8 & 0xFF);b[3] = (byte) (length & 0xFF);byte[] subarray = ArrayUtils.subarray(byteArray, 0, read);byte[] bytes = ArrayUtils.addAll(ArrayUtils.addAll(b, jsonObject.toJSONString().getBytes()), subarray);webSocket.send(new ByteString(bytes));}}System.out.println("all data is send");} catch (Exception e) {e.printStackTrace();} finally {if (fileInputStream != null) {try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if (byteOut != null) {try {byteOut.close();} catch (IOException e) {e.printStackTrace();}}}}).start();}@Overridepublic void onMessage(WebSocket webSocket, String text) {super.onMessage(webSocket, text);}@Overridepublic void onMessage(WebSocket webSocket, ByteString bytes) {super.onMessage(webSocket, bytes);byte[] byteArray = bytes.toByteArray();// byte[]转lengthint length = (byteArray[0] << 24) + (byteArray[1] << 16) + (byteArray[2] << 8) + byteArray[3];byte[] jsonArray = ArrayUtils.subarray(byteArray, 4, 4 + length);String jsonStr = new String(jsonArray);JSONObject jsonObject = JSONObject.parseObject(jsonStr);byte[] subarray = ArrayUtils.subarray(byteArray, 4 + length, byteArray.length);File resultPcmFile = new File(dic, new File(pcmFile).getName().replace(".pcm", "_result.pcm"));if (!resultPcmFile.exists()) {try {resultPcmFile.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {// 写入文件FileOutputStream outputStream = new FileOutputStream(resultPcmFile, true);IOUtils.write(subarray, outputStream);IOUtils.closeQuietly(outputStream);if ((int) jsonObject.get("errcode") == 0) {if (jsonObject.getBoolean("lastpkg")) {//说明数据全部返回完毕,可以关闭连接,释放资源System.out.println("session end ");System.out.println(sdf.format(startTime) + "开始");System.out.println(sdf.format(timeEnd.get()) + "结束");System.out.println("耗时:" + (timeEnd.get().getTime() - startTime.getTime()) + "ms");System.out.println("本次识别traceId ==》" + jsonObject.getString("traceid"));webSocket.close(1000, "");}} else {System.out.println("errCode=>" + jsonObject.getInteger("errcode") + " errMsg=>" + jsonObject.getString("errmsg") + " traceId=" + jsonObject.getString("traceid"));// 关闭连接webSocket.close(1000, "");System.out.println("发生错误,关闭连接");return;}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onFailure(WebSocket webSocket, Throwable t, Response response) {super.onFailure(webSocket, t, response);try {if (null != response) {int code = response.code();System.out.println("onFailure code:" + code);System.out.println("onFailure body:" + response.body().string());}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) {OkHttpClient client = new OkHttpClient.Builder().build();Request request = new Request.Builder().url(hostUrl).build();client.newWebSocket(request, new VcWebSocketDemo());}public static String getAccessToken() {String accessToken = "";OkHttpClient client = new OkHttpClient();// request 默认是get请求String url = String.format(tokenUrl, clientSecret, clientId);Request request = new Request.Builder().url(url).build();JSONObject jsonObject;try {Response response = client.newCall(request).execute();if (response.isSuccessful()) {// 解析String resultJson = response.body().string();jsonObject = JSON.parseObject(resultJson);accessToken = jsonObject.getString("access_token");}} catch (Exception e) {e.printStackTrace();}return accessToken;}
}

手把手教你用JAVA调用Websocket实现“声音转换”功能(变声)标贝科技相关推荐

  1. android调用相机与相册的方法,手把手教你:android调用系统相机、相册功能,适配6.0权限获取以及7.0之后获取URI(兼容多版本)...

    Android中调用系统相机来拍摄照片的代码,以下:html 一.首先设置Uri获取判断以及相机请求Codejava public final int TYPE_TAKE_PHOTO = 1;//Ur ...

  2. 手把手教你用JAVA实现“语音合成”功能(文字转声音)标贝科技

    手把手教你用JAVA实现"语音合成"功能(文字转声音)标贝科技 前言 什么是语音合成? 将文本转换成自然流畅的语音,本篇文章将介绍"实时在线合成"(文本长度不得 ...

  3. 手把手教你用JAVA实现“声音复刻”功能(复刻你的声音)标贝科技

    手把手教你用JAVA实现"声音复刻"功能(复刻你的声音)标贝科技 前言 什么是声音复刻? 使用少量的用户声音,短时间内快速为用户量身打造个人定制音色 一.内容太长不愿意看,直接使用 ...

  4. 手把手教你用JAVA实现“语音识别”功能(声音转文字)标贝科技

    手把手教你用JAVA实现"语音识别"功能(声音转文字)标贝科技 前言 什么是语音识别? 将自然语音转换为文本信息,本篇文章将介绍"一句话识别"(对60秒以内的语 ...

  5. 手把手教你搭建java接口自动化测试框架(四):断言、生成测试报告

    手把手教你搭建java接口自动化测试框架(四):断言.生成测试报告 上一集说到post和Get请求,请求后得到的响应(即接口返回值)是我们想要的吗 比如网站上get接口文档说明 : "dat ...

  6. 手把手教你用java发送邮件

    手把手教你用java发送邮件 一.学习目的 1.学会用jmail发送邮件 2.学会自动发送邮件需要的一些设置 二.准备内容(以163邮箱示范) 1.个人邮箱 首先登录163个人邮箱,然后在个人页面-设 ...

  7. 培训讲师的自我修养——《手把手教你学Java》

    当前,人才是困扰IT企业发展的第一大问题,企业间竞争的本质就是人才的竞争.然而人才却有"结构性过剩"的问题,就是因为有高深的理论.尖端的技术.耀眼的学位的"人材" ...

  8. 手把手的操作——用java调用科大讯飞的离线语音识别dll实现离线识别(JNA实现)(二)

    上一篇的地址手把手的操作--用java调用科大讯飞的离线语音识别dll实现离线识别(JNA实现)(一) 上一篇讲到了最难的地方,参数的转换,这里单独写出来 ** 三.参数的转换(难点) ** 注:本文 ...

  9. 手把手教你用Python调用SCIP求解最优化模型

    手把手教你用Python调用SCIP求解最优化模型 一个简单的例子 Python调用SCIP求解最优化模型的一般步骤 创建模型对象 创建决策变量 设置目标函数 创建约束 创建一般约束 创建广义约束 求 ...

最新文章

  1. 2.Azure资源组迁移
  2. build-helper-maven-plugin 配置多 source resource 文件
  3. scanf函数详解(下)
  4. 第五十三期:公司如何选择数据库?DynamoDB、Hadoop和MongoDB 大比拼
  5. js正则表达式匹配字符串与优化过程
  6. YOLO V1,V2, V3的记录
  7. 未来20年美国AI研究路线图
  8. php元换成万元,1000元怎么换算成万元(元怎么换成万元)
  9. 有哪些公共管理或行政管理学习帮助较大的外文期刊?
  10. 立体匹配 -- PSM-Net 网络模型代码剖析
  11. 大数据去重解决方案总结
  12. 简单学JAVA-Java学习方法-费曼学习法
  13. HTTP请求偶尔失败(21秒后超时) - 问题排查
  14. 1:Web开发入门-Java Web
  15. 《阿里云服务器搭建》------ 安装MySql
  16. 【无标题】C#上位机与三菱PLC FX2NC通讯方法
  17. SMART目标定义原则
  18. 提取四位数的千位,百位,十位,个位
  19. 7.15亿元转让债转股 内蒙古建行拟退出包钢集团
  20. 刘一男词汇课(从affiliate到fringe):书上有路勤为径,学海无涯“懂“作舟

热门文章

  1. v-show会预先渲染_预先进行Big Design的利弊-我该怎么做
  2. 连续词袋模型(Continous bag of words, CBOW)
  3. 2022年沈阳市施工员(装修装饰)考试练习题及答案
  4. html页面数据的维护
  5. STM32——TIM1的TIM1_CH1N通道PWM初始化
  6. UI设计师常用什么工具 怎么用AE导出GIF动画
  7. ubuntu16.04编译obmc
  8. 优秀自律的人手机上都装了些什么app?看完你就懂了!
  9. There is no 'root'@'%' registered解决
  10. 火焰识别python_五行属火的字大全