歌曲评分
更新时间: 2024/11/26 15:44:05
网易云信正版曲库支持歌曲评分功能。您可以通过集成 NEPitchKit 组件快捷实现含 UI 的歌曲评分功能,您也可以通过 API 接口实现歌曲评分能力,并自行实现相关 UI 界面。
功能介绍
歌曲评分包括如下功能:
- 歌曲播放时,同步回调对应的音高数据。
- 单句歌词播放结束,返回实时得分数据。
- 单首歌曲播放结束,返回整首歌曲的得分数据。
前提条件
请确认您已完成以下操作:
实现歌曲评分(含UI)
功能原理
歌曲评分UI组件的架构示意图如下图所示。
注意事项
不需要执行 destory
操作,页面销毁的时候,NEPitchRecordComponentView 组件内部会进行销毁操作。
集成组件
-
在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);
-
初始化相关数据。
基于版权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);
-
调用
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) {}
-
调用
pitchStart
接口启动打分功能,并且持续地调用update
接口输入播放时间戳。componentView.pitchStart(); componentView.update(long currentTimeMillis);
-
调用
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)
实现流程
实现方法
-
初始化组件
-
调用
NEPitchSongScore getInstance
接口创建打分引擎对象。NEPitchSongScore instance = NEPitchSongScore.getInstance();
-
调用
initialize
接口初始化打分引擎。//初始化打分引擎 NEPitchRecordSingInfo pitchRecordSingInfo = NEPitchRecordSingInfo.createInfoWithPitchContent( midiContent, separator, startTime, endTime, lyricContent, type); if (pitchRecordSingInfo != null) { instance.initialize(pitchRecordSingInfo); }
-
-
调用
addGradeListener
接口添加打分回调监听器。private NEKaraokeGradeListener gradeListener = new NEKaraokeGradeListener() { @Override public void onNote(@NotNull NEPitchItemModel itemModel) { // 实时音高回调 } @Override public void onGrade(@NotNull NEPitchRecordSingMarkModel markModel) { // 实时分数回调 } }; instance.addGradeListener(gradeListener);
-
调用
start
接口启动打分功能,并且持续地调用update
接口输入播放时间戳。instance.start(); // 不断的输入当前播放时间戳 instance.update(currentTimeMillis);
-
持续调用
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); }
-
通过
onNote
回调,获取实时音高数据。@Override public void onNote(@NotNull NEPitchItemModel itemModel) { // 实时音高回调 }
-
通过
onGrade
回调,获取实时打分数据。@Override public void onGrade(@NotNull NEPitchRecordSingMarkModel markModel) { // 实时分数回调 }
-
调用
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); } });
-
调用
destroy
接口销毁打分器。instance.destroy();
其他接口
//暂停打分
fun pause()
//录唱过程中seek,就是跳过一些句子或者重新从某个句子开始唱,需要刷新一下打分库。
fun resetPitch()