华为HMS Core​​音频编辑服务​​(Audio Editor Kit)依托自身AI技术的研发优势,上线全新的歌声合成音色及伴奏,给音视频创作者提供更多的创作可能。在短视频场景中,用户自定义歌词的歌声结合视频让用户感受到身临其境,自由表达自己的情绪;在虚拟偶像场景中,歌声合成功能赋予虚拟歌手们演唱风格各异的歌曲,带来创意无限。

HMS Core​​音频编辑服务​​歌声合成的AI Singer模型能力通过字级别输入歌词进行音素转换,就可以为用户创作音乐,也可预置曲目合成歌声。通过自研音高模型,让音高曲线在保持输入曲谱的音高精准度的同时改善自然度,更接近人的真实演唱。使用最新的生成式模型,带来更好的音色还原度、建模更多的演唱细节,同时高清声码器能够真实还原48k高清音质。

另外,用户通过自由调整颤音、滑音、呼吸音等功能,可根据情感需求调整歌声演唱技巧。当前歌声合成服务已开放了情流行女声、国风女声和民谣男声音色,未来会持续更新更多音色。

可点击试听音色效果:​https://developer.huawei.com/consumer/cn/doc/development/Media-Guides/synthesis_timbre_audition-0000001336283673#section15944442132920?ha_source=hms1​

华为HMS Core​​音频编辑服务​​(Audio Editor Kit)让机器“演唱”出真实度的歌声,仅需简单的集成获得,以下是开发者应用集成音频编辑服务歌声合成能力的具体步骤。

开发步骤

1. 开发准备

1.1注册成为开发者

在开发应用前需要在华为​​开发者联盟网站​​​上注册成为开发者并完成实名认证,具体方法请参见​​帐号注册认证。​

1.2创建项目及应用

参见​​创建项目​​​,然后在项目下​​创建应用​​完成应用的创建,特殊配置如下:

选择平台:选择“Web”。

1.3打开相关服务

使用Audio Editor Kit服务需要您在AppGallery Connect上打开Audio Editor Kit服务开关,具体操作步骤请参见打开服务开关。

2.歌声合成功能集成

2.1同步接口(流式)

2.1.1获取access_token鉴权信息

使用开发者联盟界面获得的客户端ID以及对应密钥,发送HTTPS POST请求,获取查询access_token。获取方式请​​参见客户端模式​​(Client Credentials)。

2.1.2调用同步接口(流式)

通过以上步骤获取的access_token信息,发送HTTPS POST调用同步接口(流式)。

示例代码(Java)如下所示:

其中requestUrl = "​​https://audioeditor-api-drcn.cloud.huawei.com/v1/audioeditor/gateway/ai/ttsing/sync​​"。

请点击下载MusicXML文件,并上传:

/**
* 调用同步接口(流式)
* @throws Exception IO异常
*/
private static void syncTask() throws Exception {
// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
Map<String, Object> dataMap = new HashMap<>();
Map<String, Object> configMap = new HashMap<>();
// filePath是MusicXML文件路径(含文件名、后缀)
String lyricFilePath = "filePath";
dataMap.put("lyric", FileUtils.readFileToString(new File(lyricFilePath), "UTF-8"));
dataMap.put("language", "chinese");
configMap.put("type", 1);
configMap.put("outputEncoderFormat", 0);
configMap.put("wordDurationForceAlign", "false");
bodyMap.put("data", dataMap);
bodyMap.put("config", configMap);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
if (ret == 200) {
Header responseHeader = postMethod.getResponseHeader("content-type");
if ("application/octet-stream".equals(responseHeader.getValue())) {
InputStream rpsContent = postMethod.getResponseBodyAsStream();
// filePath是要保存文件的路径(含文件名、PCM文件后缀)
String filePath = "filePath";
FileUtils.copyInputStreamToFile(rpsContent, new File(filePath));
} else {
String errorString = postMethod.getResponseBodyAsString();
System.out.println(errorString);
}
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + postMethod.getResponseBodyAsString());
}
}

使用预置曲目输入歌词:

/**
* 调用同步接口(流式)
* @throws Exception IO异常
*/
private static void syncTask() throws Exception {

// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
Map<String, Object> dataMap = new HashMap<>();
Map<String, Object> configMap = new HashMap<>();
String[] lyrics = {"跟随心跳的节拍", "感受自由的畅快", "把烦恼通通抛开", "我们一起嗨", "调整呼吸的节拍", "保持最好的状态", "奔向耀眼的未来", "哦康忙北北"};
dataMap.put("lyrics", lyrics);
dataMap.put("accompanimentId", "1");
dataMap.put("isAutoFill", "false");
dataMap.put("language", "chinese");
configMap.put("type", 1);
configMap.put("outputEncoderFormat", 0);
configMap.put("wordDurationForceAlign", "false");
bodyMap.put("data", dataMap);
bodyMap.put("config", configMap);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
if (ret == 200) {
Header responseHeader = postMethod.getResponseHeader("content-type");
if ("application/octet-stream".equals(responseHeader.getValue())) {
InputStream rpsContent = postMethod.getResponseBodyAsStream();
// filePath是要保存文件的路径(含文件名、PCM文件后缀)
String filePath = "filePath";
FileUtils.copyInputStreamToFile(rpsContent, new File(filePath));
} else {
String errorString = postMethod.getResponseBodyAsString();
System.out.println(errorString);
}
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + postMethod.getResponseBodyAsString());
}
}

注意:

上述代码中xxxxx对应的值请根据实际情况填写,具体取值请参见​​同步接口(流式)​​。

2.2异步接口

2.2.1创建异步任务

通过access_token信息,发送HTTPS POST创建歌声合成异步任务。

示例代码(Java)如下所示:

其中requestUrl = "​​https://audioeditor-api-drcn.cloud.huawei.com/v1/audioeditor/gateway/ai/ttsing/async/task/create​​"。

请点击下载MusicXML文件,并上传:

/**
* 调用创建异步任务接口
* @throws Exception IO异常
*/
private static void creatAsyncTask() throws Exception {

// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
Map<String, Object> dataMap = new HashMap<>();
Map<String, Object> configMap = new HashMap<>();
// filePath是MusicXML文件路径(含文件名、后缀)
String lyricFilePath = "filePath";
dataMap.put("lyric", FileUtils.readFileToString(new File(lyricFilePath), "UTF-8"));
dataMap.put("language", "chinese");
configMap.put("type", 1);
configMap.put("outputEncoderFormat", 0);
configMap.put("wordDurationForceAlign", "false");
bodyMap.put("data", dataMap);
bodyMap.put("config", configMap);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
String rpsContent = postMethod.getResponseBodyAsString();
if (ret == 200) {
System.out.println(rpsContent);
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + rpsContent);
}
}

使用预置曲目输入歌词:

/**
* 调用创建异步任务接口
* @throws Exception IO异常
*/
private static void creatAsyncTask() throws Exception {

// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
Map<String, Object> dataMap = new HashMap<>();
Map<String, Object> configMap = new HashMap<>();
String[] lyrics = {"跟随心跳的节拍", "感受自由的畅快", "把烦恼通通抛开", "我们一起嗨", "调整呼吸的节拍", "保持最好的状态", "奔向耀眼的未来", "哦康忙北北"};
dataMap.put("lyrics", lyrics);
dataMap.put("accompanimentId", "1");
dataMap.put("isAutoFill", "false");
dataMap.put("language", "chinese");
configMap.put("type", 1);
configMap.put("outputEncoderFormat", 0);
configMap.put("wordDurationForceAlign", "false");
bodyMap.put("data", dataMap);
bodyMap.put("config", configMap);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
String rpsContent = postMethod.getResponseBodyAsString();
if (ret == 200) {
System.out.println(rpsContent);
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + rpsContent);
}
}

注意:

上述代码中xxxxx对应的值请根据实际情况填写,具体取值请参见​​创建异步任务​​。

2.2.2查询异步任务状态

用户创建异步任务后,可以通过调用该接口,获取任务处理状态等信息。任务处理完成后,会返回任务的下载地址,直接访问该地址即可下载文件。

通过access_token信息,和创建异步任务获取到的taskId发送HTTPS POST查询歌声合成异步任务状态。

示例代码(Java)如下所示:

其中requestUrl = "​​https://audioeditor-api-drcn.cloud.huawei.com/v1/audioeditor/gateway/ai/ttsing/async/task/status​​"。

/**
* 调用查询异步任务状态接口
* @param taskId 创建异步任务获取的taskId
* @throws Exception IO异常
*/
private static void queryAsyncTaskInfo(String taskId) throws Exception {

// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
// taskId对应的值是创建异步任务时返回的任务ID(taskId)
bodyMap.put("taskId", taskId);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
String rpsContent = postMethod.getResponseBodyAsString();
if (ret == 200) {
System.out.println(rpsContent);
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + rpsContent);
}
}

注意:

上述代码中xxxxx对应的值请根据实际情况填写,具体取值请参见​​查询异步任务状态​​。

2.2.3取消异步任务

用户创建歌声合成异步任务后,可以通过调用此接口,取消指定异步任务并删除相应任务数据。

通过access_token信息和创建异步任务获取到的taskId,发送HTTPS POST取消异步任务。

示例代码(Java)如下所示:

其中requestUrl = "​​https://audioeditor-api-drcn.cloud.huawei.com/v1/audioeditor/gateway/ai/ttsing/async/task/cancel​​"。

/**
* 调用取消异步任务接口
* @param taskId 创建异步任务获取的taskId
* @throws Exception IO异常
*/
private static void cancelAsyncTask(String taskId) throws Exception {

// 设置请求header
PostMethod postMethod = new PostMethod(requestUrl);
// 设置文本类型(String),例:"application/json;charset=utf-8"
postMethod.setRequestHeader("Content-Type", contentType);
// 设置请求ID(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("X-Request-ID", requestId);
// 设置App包名(String),例:"com.huawei.demo"
postMethod.setRequestHeader("X-Package-Name", pacageName);
// 设置App所在国家(String),例:"cn"
postMethod.setRequestHeader("X-Country-Code", countryCode);
// 设置App标识(String),例:"9af1aeda-531b-407a-80b4-65b40ef77bd6"
postMethod.setRequestHeader("HMS-APPLICATION-ID", applicationId);
// 设置证书指纹(String),例:"xxxxxxxxxxxxxxx"
postMethod.setRequestHeader("certFingerprint", certFingerprint);
// 设置动态获取的AccessToken(String)
postMethod.setRequestHeader("Authorization","Bearer " + accessToken);
// 设置请求body
Map<String, Object> bodyMap = new HashMap<>();
// taskId对应的值是创建异步任务时返回的任务ID(taskId)
bodyMap.put("taskId", taskId);
RequestEntity requestEntity = new StringRequestEntity(JSONObject.toJSONString(bodyMap),"application/json" ,"UTF-8");
postMethod.setRequestEntity(requestEntity);

HttpClient httpClient = new HttpClient();
int ret = httpClient.executeMethod(postMethod);
String rpsContent = postMethod.getResponseBodyAsString();
if (ret == 200) {
System.out.println(rpsContent);
} else {
System.out.println("callApi failed: ret =" + ret + " rsp=" + rpsContent);
}
}

注意:

上述代码中xxxxx对应的值请根据实际情况填写,具体取值请参见​​取消异步任务​​。

除了歌声合成能力,音频编辑服务还提供音频基础剪辑、AI配音、音源分离、空间渲染、变声降噪等音频处理能力,更多信息可以​​访问官网获得​​。

了解更多详情>>

访问​​华为开发者联盟官网​​​ 获取​​​开发指导文档​​​ 华为移动服务开源仓库地址:​​GitHub​​、​​Gitee​

关注我们,第一时间了解 HMS Core 最新技术资讯~