• AI赋能音乐创作,人人都是音视频创作者


    华为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 bodyMap = new HashMap<>();
            Map dataMap = new HashMap<>();
            Map 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());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    使用预置曲目输入歌词:

       /**
         * 调用同步接口(流式)
         * @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 bodyMap = new HashMap<>();
            Map dataMap = new HashMap<>();
            Map 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());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    注意:

    上述代码中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 bodyMap = new HashMap<>();
            Map dataMap = new HashMap<>();
            Map 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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    使用预置曲目输入歌词:

    /**
         * 调用创建异步任务接口
         * @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 bodyMap = new HashMap<>();
            Map dataMap = new HashMap<>();
            Map 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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    注意:

    上述代码中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 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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    注意:

    上述代码中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 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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    注意:

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

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

    了解更多详情>>

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

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

  • 相关阅读:
    25、Mybatis查询功能总结(4种情况)
    MQ - 24 Pulsar集群架构设计与实现
    linux下的自旋锁、信号量、互斥、完成量
    CF461B Appleman and Tree题解
    c++——.类的访问限定符,类的定义,类/对象的大小计算,this指针
    基于JSP+Servlet的宠物养护网站
    禁止最近任务强杀app进程
    【码神之路】【Golang】博客网站的搭建【学习笔记整理 持续更新...】
    springboot基于点餐码 二维码在线点餐系统vue.js+java
    计算机毕业设计ssm+vue基本微信小程序的手机预约维修系统
  • 原文地址:https://blog.csdn.net/HUAWEI_HMSCore/article/details/128001425