在线 K 歌
Android
动态与公告
更新日志
场景概览
场景概述
功能介绍
体验 Demo
术语
快速开始
开通能力
跑通示例项目
接入指引
实现流程(基于 K 歌组件)
实现流程(基于底层能力)
前期准备
加入和离开 RTC 房间
实现独唱
实现NTP实时合唱
实现串行合唱
实现智能调度
实现聊天消息
音效混响
正版曲库
曲库介绍
集成曲库 SDK
版权音乐
歌词逐字逐行
歌曲评分
API 参考
错误码和状态码
K 歌组件的错误码和状态码
曲库的错误码和状态码

歌曲评分

更新时间: 2022/12/06 16:40:24

网易云信正版曲库支持歌曲评分功能。您可以通过集成 NEPitchKit 组件快捷实现含 UI 的歌曲评分功能,您也可以通过 API 接口实现歌曲评分能力,并自行实现相关 UI 界面。

功能介绍

歌曲评分包括如下功能:

  • 歌曲播放时,同步回调对应的音高数据。
  • 单句歌词播放结束,返回实时得分数据。
  • 单首歌曲播放结束,返回整首歌曲的得分数据。
歌曲评分

前提条件

请确认您已完成以下操作:

实现歌曲评分(含UI)

功能原理

歌曲评分UI组件的架构示意图如下图所示。

歌曲评分组件的架构.png

注意事项

不需要执行 destory 操作,页面销毁的时候,NEPitchRecordComponentView 组件内部会进行销毁操作。

集成组件

  1. 在Activity、Fragment等 UI 界面上添加 NEPitchRecordComponentView 控件。

    <com.netease.yunxin.kit.karaokekit.pitch.ui.widget.NEPitchRecordComponentView
            android:id="@+id/componentView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
           componentView=findViewById(R.id.componentView); 
    
  2. 初始化相关数据。

    基于版权SDK获取当前歌曲对应的歌词内容和midi内容
    ///获取歌词资源内容:
        NECopyrightedMedia.getInstance()
            .preloadSongLyric(
                songId,
                new LyricCallback() {
    
                @Override
                public void success(@Nullable String content, @Nullable String type) {
                    lyricContent=content;
                    lyricType=type; //"yrc"、"lrc"
                }
    
    ///获取打分资源内容:
    String midiContent = NECopyrightedMedia.getInstance().getMidi(songId);
    
  3. 调用loadRecordDataWithPitchContent接口加载相关配置内容。

    ///separator 为打分内容的分割符 ;例如 打分内容为 xxx,xxx,xxx ... 则分割符为 " , "。
    /**
    * 数据初始化
    *
    * @param midiContent midi内容
    * @param separator 分隔符
    * @param startTime 开始时间
    * @param endTime 结束时间
    * @param lyricContent 歌词内容
    * @param type 歌词类型
    */
    public void loadRecordDataWithPitchContent(
        String midiContent,
        String separator,
        int startTime,
        int endTime,
        String lyricContent,
        NELyric.NELyricType type,
        NEPitchLayoutBuilder pitchLayoutBuilder) {}
    
  4. 调用 pitchStart接口启动打分功能,并且持续地调用update接口输入播放时间戳。

    componentView.pitchStart();
    componentView.update(long currentTimeMillis);
    
  5. 调用 pushAudioData接口推送打分数据。

    如果您使用的是网易云信的 NEKaraokeKit,采集音频裸数据的示例代码如下:

    @Override
    public void onRecordingAudioFrame(@NonNull NEKaraokeAudioFrame frame) {
        // 音频数据
        NEPitchAudioData audioData =
            new NEPitchAudioData(
                frame.data,
                frame.format.samplesPerChannel,
                (int) (currentPosition - 10),
                true,
                frame.format.sampleRate,
                frame.format.channels);
        componentView.pushAudioData(audioData);
    }
    

    如果您使用的是云信NERoom SDK,采集音频裸数据的示例代码如下:

    
       @Override
          public void onRecordFrame(@NonNull NERoomRtcAudioFrame frame) {
              NEPitchAudioData audioData =
                  new NEPitchAudioData(
                      frame.data,
                      frame.format.samplesPerChannel,
                      (int) (currentPosition - 10),
                      true,
                      frame.format.sampleRate,
                      frame.format.channels);
              componentView.pushAudioData(audioData);
          }
    

    如果您使用的是网易云信的 NERTC,采集音频裸数据的示例代码如下:

           NERtcEx.getInstance().setAudioFrameObserver(new NERtcAudioFrameObserver() {
            @Override
            public void onRecordFrame(NERtcAudioFrame neRtcAudioFrame) {
    
                NEPitchAudioData audioData =
                        new NEPitchAudioData(
                                neRtcAudioFrame.getData(),
                                neRtcAudioFrame.getFormat().getSamplesPerChannel(),
                                (int) (currentPosition - 10),
                                true,
                                neRtcAudioFrame.getFormat().getSampleRate(),
                                neRtcAudioFrame.getFormat().getChannels());
                 componentView.pushAudioData(audioData);
            }
        });
    

定制 UI 界面

UI Kit 支持自定义界面的元素,包括颜色、线形状、分数蹦出效果、分数格式等。

在步骤 3 加载相关配置内容中,可以通过设置 builder相关属性,实现自定义歌曲评分的 UI 界面,示例代码如下:

private val pitchLayoutBuilder: NEPitchLayoutBuilder = NEPitchLayoutBuilder()
    private fun configPitchLayoutBuilder() {
    pitchLayoutBuilder.lineHeight = LINE_HEIGHT
    pitchLayoutBuilder.bottomColor = BOTTOM_COLOR
    pitchLayoutBuilder.drawColor = DRAW_COLOR
    pitchLayoutBuilder.linearGradientStartColor = LINEAR_GRADIENT_START_COLOR
    pitchLayoutBuilder.linearGradientEndColor = LINEAR_GRADIENT_END_COLOR
}
        componentView.loadRecordDataWithPitchContent(
            midiContent,
            separator,
            0,
            LyricUtil.getEndTimeMillis(lyric),
            lyricContent,
            lyricType,
            pitchLayoutBuilder
        )       

相关属性及规则示例代码如下所示:

public class NEPitchLayoutBuilder {
  /** 白条高度,默认7px */
  public float lineHeight;
  /** 音调重合渲染颜色 */
  public int drawColor;
  /** 基础底色渲染 */
  public int bottomColor;
  /** 遮罩层颜色 开始颜色 */
  public int linearGradientStartColor;
  /** 遮罩层颜色 结束颜色 */
  public int linearGradientEndColor;
}

可参考karaokekit-sample src/main/res/drawable-xxhdpi中前缀为pitch_ui的图片完成以下自定义UI的设置
//自定义箭头样式
在app模块下面的drawable-xxhdpi添加文件名为pitch_ui_sing_indicator的图片

//自定义气泡样式
在app模块下面的drawable-xxhdpi添加文件名为pitch_ui_bubble_1和pitch_ui_bubble_2的图片

//自定义最终打分动画(s、ss、sss webp动画),//尺寸大小建议 628 × 540
在app模块下面的drawable-xxhdpi添加文件名为pitch_ui_anims、pitch_ui_animss、pitch_ui_animsss的图片

//自定义单次评分lottie动画
在app模块下面的assets目录下添加目录名分别为pitch_cool、pitch_nice、pitch_perfect的文件夹

//自定义演唱perfect时 追加的 x1 到 x9 到 xn图片,尺寸大小为 60 x 60
在app模块下面的drawable-xxhdpi添加命名为pitch_ui_sing_score_pic_0、pitch_ui_sing_score_pic_1、...pitch_ui_sing_score_pic_9、pitch_ui_sing_score_pic_x的图片

实现歌曲评分(不含UI)

实现流程

uml diagram

实现方法

  1. 初始化组件

    1. 调用 NEPitchSongScore getInstance 接口创建打分引擎对象。

       NEPitchSongScore instance = NEPitchSongScore.getInstance();
      
      
    2. 调用 initialize 接口初始化打分引擎。

       //初始化打分引擎
         NEPitchRecordSingInfo pitchRecordSingInfo =
       NEPitchRecordSingInfo.createInfoWithPitchContent(
           midiContent, separator, startTime, endTime, lyricContent, type);
           if (pitchRecordSingInfo != null) {
           instance.initialize(pitchRecordSingInfo);
           }
      
      
      
  2. 调用 addGradeListener 接口添加打分回调监听器。

    private NEKaraokeGradeListener gradeListener =
      new NEKaraokeGradeListener() {
        @Override
        public void onNote(@NotNull NEPitchItemModel itemModel) {
          // 实时音高回调
    
        }
    
        @Override
        public void onGrade(@NotNull NEPitchRecordSingMarkModel markModel) {
          // 实时分数回调
    
        }
      };
       
            instance.addGradeListener(gradeListener);
    
    
    
  3. 调用 start接口启动打分功能,并且持续地调用update接口输入播放时间戳。

        instance.start();
        // 不断的输入当前播放时间戳
        instance.update(currentTimeMillis);
    
  4. 持续调用 pushAudioData 接口进行数据推送,驱动打分功能运行。

    // 如果您使用的是云信NEKaraokeKit SDK,对应的RTC音频回调为
        @Override
          public void onRecordingAudioFrame(@NonNull NEKaraokeAudioFrame frame) {
               NEPitchAudioData audioData =
                  new NEPitchAudioData(
                      frame.data,
                      frame.format.samplesPerChannel,
                      (int) (currentPosition - 10),
                      true,
                      frame.format.sampleRate,
                      frame.format.channels);
              instance.pushAudioData(audioData);
          }
    
    // 如果您使用的是云信NERoom SDK,对应的RTC音频回调为
       @Override
          public void onRecordFrame(@NonNull NERoomRtcAudioFrame frame) {
              NEPitchAudioData audioData =
                  new NEPitchAudioData(
                      frame.data,
                      frame.format.samplesPerChannel,
                      (int) (currentPosition - 10),
                      true,
                      frame.format.sampleRate,
                      frame.format.channels);
              instance.pushAudioData(audioData);
          }
    
     // 如果您使用的是云信NERTC SDK,对应的RTC音频回调为
    @Override
          public void onRecordFrame(@NonNull NERtcAudioFrame frame) {
              NEPitchAudioData audioData =
                  new NEPitchAudioData(
                      frame.data,
                      frame.format.samplesPerChannel,
                      (int) (currentPosition - 10),
                      true,
                      frame.format.sampleRate,
                      frame.format.channels);
              instance.pushAudioData(audioData);
          }
    
  5. 通过 onNote 回调,获取实时音高数据。

        @Override
        public void onNote(@NotNull NEPitchItemModel itemModel) {
          // 实时音高回调
    
        }
    
  6. 通过 onGrade 回调,获取实时打分数据。

        @Override
        public void onGrade(@NotNull NEPitchRecordSingMarkModel markModel) {
          // 实时分数回调
    
        }
    
  7. 调用 getFinalScore 接口计算最终分数。

          NEPitchSongScore instance = NEPitchSongScore.getInstance();
    if (instance == null) {
      return;
    }
    instance.getFinalScore(
        new NECopyrightedMedia.Callback<NEPitchRecordSingInfo>() {
          @Override
          public void success(@Nullable NEPitchRecordSingInfo info) {
             // 获取最终得分
          }
    
          @Override
          public void error(int code, @Nullable String msg) {
            Log.e(TAG, "打分失败,errorCode:" + code);
          }
        });
    
  8. 调用 destroy 接口销毁打分器。

      instance.destroy();
    

其他接口

//暂停打分
  fun pause()

//录唱过程中seek,就是跳过一些句子或者重新从某个句子开始唱,需要刷新一下打分库。
  fun resetPitch()

此文档是否对你有帮助?
有帮助
我要吐槽
  • 功能介绍
  • 前提条件
  • 实现歌曲评分(含UI)
  • 功能原理
  • 注意事项
  • 集成组件
  • 定制 UI 界面
  • 实现歌曲评分(不含UI)
  • 实现流程
  • 实现方法
  • 其他接口