全民K歌IOT开放平台
  1. KtvSDK3.0接入说明
全民K歌IOT开放平台
  • 厂商合作流程
  • 快速接入K歌开放平台流程
  • SDK bug提单规范
  • 如何在线调试接口
  • 常见问题FAQ
  • 开放平台API错误码说明
  • 开放平台接入指南
    • 登录鉴权方式介绍V2(推荐)
    • 如何申请接入
    • CDK权限申请流程
    • 暗账号绑定明账号对接文档
    • 获取应用级token
    • 获取登录二维码
    • 查询二维码的状态
    • 获取用户级token
    • 刷新用户级token
    • 暗账号解绑K歌uid
    • 获取暗账号绑定信息
  • KtvSDK3.0接入说明
    • 厂商合作流程
    • bug提单规范
    • KtvSDK-接入指南
    • KtvSDK-打分
    • KtvSDK-登录
    • KtvSDK-歌词
    • KtvSDK-播放
    • 多屏一起唱---歌词与打分适配
    • 3.0新打分样式及五维打分
    • KtvSDK-多屏渲染
    • KtvSDK-2.0升级到3.0版本迁移指南
    • KtvSDK-3.0版本新功能
    • KtvSDK-Android4.4设备G2证书兼容处理
    • KtvSDK-播放页实现示例
    • KtvSDK-常见问题FAQ
    • KtvSDK-低性能设备处理
    • KtvSDK-反馈
    • KtvSDK-缓存管理
    • KtvSDK-切换音频视频清晰度
    • KtvSDK-跳过前奏
    • Ktv支付-米大师支付
    • 播放失败错误码说明
    • 作品录音、合成与播放2.0版
  • 基础类
    • tagId对照表
    • 歌曲详情
    • 查询mv的播放地址
    • 搜索
    • 搜索联想
    • 查询歌手歌曲
    • 获取歌曲歌词文件
    • Q音歌曲mid映射K歌
    • 短剧播放链接
    • 查询应用限免配置
    • 转换Q音或酷狗歌曲ID
  • 运营类
    • 排行榜id说明
    • 获取城市id列表
    • 获取专题分类列表
    • 获取云端配置
    • 热门ugc
    • 热搜词
    • 排行榜
    • 获取专题下歌曲信息
    • 获取车联渠道映射
    • 热门推荐
    • (新)排行榜
    • 综合歌单列表查询
    • 设置缓存设备
    • TV版分类歌单列表
    • 获取用户协议
    • 综合歌单列表查询(海外)
    • 榜单列表查询(海外)
    • 自建歌单列表查询(海外)
    • 获取广告配置
    • 拉取短剧合集的列表
  • 用户类
    • 用户信息查询
    • 删除用户UGC作品
    • 获取推荐/翻唱作品
    • 获取同城作品
    • 用户作品列表
    • 获取好友作品
    • UGC作品详情
    • 更改作品访问权限
    • 用户个推歌单
  • 支付类
    • 支付接入流程
    • 订单发货使用简述
    • 开通设备会员限免简述
    • 订单发货中通用sign计算规则
    • 通用返回结构
    • 【CDK】CDK兑换
    • 【CDK】生成CDK
    • 【CDK】CDK召回
    • 【CDK】CDK状态查询
    • 【三方支付】订单发货
    • 【三方支付】手机号发货
    • 【三方支付】订单状态查询
    • 【米大师支付】获取会员商品列表
    • 【米大师支付】未登录-查询会员商品列表
    • 【米大师支付】支付下单
    • 【米大师支付】支付成功通知
    • 【米大师支付】查询用户支付成功订单记录
    • 查询设备以及用户是否有赠送资格
    • 查询设备限免剩余时长
    • 设备会员迁移
    • 查询会员赠送时长
    • 同步支付订单接口
    • 【三方支付】存量会员迁移领取查询
    • 【三方支付】存量会员迁移接口
    • 授权设备体验会员
    • 查询用户会员信息
    • 【三方支付】超会发货
    • 取消授权设备体验会员
  • 用户作品-文件类
    • callback_url说明
    • 上传音频源文件
    • (服务端)上传音频作品的链接
  • 通用类
    • 【厂商定制】匹配搜索
    • 获取kg的短链接
  1. KtvSDK3.0接入说明

KtvSDK-打分

KTV打分组件接入文档#

1. 总览和功能#

KTV打分组件为K歌应用提供实时打分功能,支持两种样式:
2.0版本(旧样式):基于MidiScoreView的传统打分界面
3.0版本(新样式):基于SingIntonationViewer的现代化打分界面,支持更炫的效果
打分功能分为两种模式:
普通打分:提供总分和单句分数
五维打分:提供总分、音准、节奏、技巧、气息、情感五个维度的分数

2. 2.0版本打分组件(旧样式)#

2.1 布局中添加MidiScoreView#

在播放页布局中添加MidiScoreView组件:
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <com.tme.ktv.midi.MidiScoreView
        android:id="@+id/midi_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="130dp"/>
</FrameLayout>

2.2 初始化配置Activity#

在Activity中初始化MidiScoreView并设置Activity:

2.3 回调事件中MidiScoreView响应#

2.3.1 实现打分回调监听器#

2.3.2 实现播放器回调监听器#

2.3.3 添加监听器到播放器#

2.4 MidiView修改配置#

2.4.1 打分条配置#

1.
自定义打分条布局:
打分条可以根据 KaraokePlayer 的打分回调 OnScoreListener自定义实现
ScoreBarView.setLayoutResId 支持应用传入layout, layout 布局参考 layout_karaoke_score_level.xml,可以在这个layout 基础上修改,只支持修改布局属性,控件ID 需要保持不变。
2.
获取ScoreBarView并修改属性:

2.4.2 音高数据配置#

修改音高数据的背景和画笔风格:

2.5 打分开关#

判断歌曲是否支持五维打分:

3. 3.0版本打分组件(新样式)#

3.1 布局中添加打分View#

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/intonation_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:clipToPadding="false"
    android:clipChildren="false">
    
    <com.tme.ktv.intonation.view.PerfectAnimView
        android:id="@+id/karaoke_perfect_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
        
    <com.tme.ktv.intonation.view.SimpleScoreBar
        android:id="@+id/pk_score_bar"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_marginStart="@dimen/pk_score_layout_margin_left"
        android:layout_marginTop="160dp" />
        
    <com.tme.ktv.intonation.SingIntonationViewer
        android:id="@+id/player_float_intonation_viewer"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_gravity="bottom"
        android:layout_marginStart="30dp"
        android:layout_marginEnd="30dp"
        android:layout_marginBottom="130dp" />
</FrameLayout>

3.2 初始化打分辅助类#

3.3 设置打分回调#

3.3.1 实现打分回调监听器#

3.3.2 实现播放器回调监听器#

3.3.3 添加监听器到播放器#

4. 五维打分功能#

五维打分提供更丰富的评分维度,包括:
音准分数:lastStableScore / finalStableScore
节奏分数:lastRhythmScore / finalRhythmScore
技巧分数:skillScore / finalSkillScore
气息分数:lastLongToneScore / finalLongToneScore
情感分数:dynamicScore / finalDynamicScore

4.1 使用五维打分#

1.
确保已开启五维打分:
2.
在onDoingMultiScore回调中处理五维分数数据
3.
在onMultiScoreFinish回调中处理最终五维分数

4.2 分数等级计算规则#

分数等级按照单句平均分来定级:
注意:使用打分功能,需要把 songtype设置为SONG_TYPE_K_SONG 录唱模式,其他模式不支持打分

5.旧版打分文档补充#

5.1 初始化 配置Activity#

​ mMidiScoreView.setActivity(this) 这个Api 需要设置,不然影响动画
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mMidiScoreView = this.findViewById(R.id.midi_view);
    mMidiScoreView.setActivity(this);

5.2 Callback 事件中 MidiScoreView 响应#

private class ScoreListenerImpl extends KaraokePlayer.OnScoreListener{

    @Override
    protected void onPrepareScore(SingCompetitor competitor, int nums) {
        //获取到节拍数据,设置给midiView,其中 nums是打分的总句子数,不一定等于歌词行数
        mMidiScoreView.initData(competitor);
    }
   //普通打分单句回调
    @Override
    protected void onDoingScore(int score, String level, int timeStamp) {
        //普通打分的单句实时打分结果,数值和等级
        mIntonationDelegate?.postUpdateScore(score,timeStamp.toFloat(),null)
    }
//普通打分回调
    @Override
    protected void onFinishScore(int totalScore, String level) {
       //普通打分演唱结束后的总分结果
    }
   
       /** 
         *五维打分回调
         * 每唱完一句出一次分数,上一句就是刚唱完的那一句
         * @param lastScore 上一句的分数
         * @param timeStamp 时间戳
         * @param lastLongToneScore 上一句的气息分数
         * @param lastRhythmScore 上一句的节奏分数
         * @param lastStableScore 上一句的音准分数
         * @param dynamicScore 上一句的情感分数
         * @param skillScore 上一句的技巧分数
         * @param lastSkillTrillCount 上一句命中的颤音个数
         * @param lastSkillGlintCount 上一句命中的滑音个数
         * @param lastSkillTransliterationCount 上一句命中的转音个数
         */
        public void onDoingMultiScore(int lastScore, long timeStamp, int lastLongToneScore, int lastRhythmScore,
                                      int lastStableScore, int dynamicScore, int skillScore,
                                      int lastSkillTrillCount, int lastSkillGlintCount,
                                      int lastSkillTransliterationCount) {
                        //五维打分实时回调
                        multiScoreResultInfo.resetLastScore()
                        multiScoreResultInfo.lastLongToneScore = lastLongToneScore
                        multiScoreResultInfo.lastRhythmScore = lastRhythmScore
                        multiScoreResultInfo.lastStableScore = lastStableScore
                        multiScoreResultInfo.lastDynamicScore = dynamicScore
                        multiScoreResultInfo.lastSkillScore = skillScore
                        multiScoreResultInfo.lastSkillTrillCount = lastSkillTrillCount
                        multiScoreResultInfo.lastSkillTransliterationCount = lastSkillGlintCount
                        mIntonationDelegate?.postUpdateScore(lastScore, timeStamp.toFloat(), multiScoreResultInfo)
        }


       /** 
         * 五维打分结束回调
         * @param finalLongToneScore 气息分数
         * @param finalRhythmScore 节奏分数
         * @param finalStableScore 音准分数
         * @param finalDynamicScore 情感分数
         * @param finalSkillScore 技巧分数
         * @param lastSentenceIndex 最后一句歌词的索引
         * @param totalSentences 这首歌的句子数
         */
        public void onMultiScoreFinish(int finalLongToneScore, int finalRhythmScore, int finalStableScore,
                                       int finalDynamicScore, int finalSkillScore, int lastSentenceIndex,
                                       int totalSentences) {
        }
}
    inner class KtvMidiCallbackImpl : KaraokePlayerListener() {

        private fun startMidiView() {
            if (KtvPlayerConfig.getInstance().isEnableScore) {
                log("startMidiView")
                midiView.startMidi(viewModel.currPlayer()?.timeLineTime ?: 0)
            }
        }

        private fun stopMidiView() {
            midiView.stopMidi()
        }

        override fun onPlayStart(request: KaraokePlayRequest) {
            log("onPlayStart:$request")
            if (request.songInfoObject.mNoteBytes == null && request.songInfoObject.songType == SongType.SONG_TYPE_K_SONG) {
                log("current song has no noteBytes, close score")
                if (MediaProperties.get().isEnableScore) {
                    PlayConsole.get().setScoreOpen(false)
                    KGToast.show("该歌曲不支持打分,已为您关闭打分")
                }
            }
        }

        override fun onLyricResourceChanged(request: KaraokePlayRequest) {
            super.onLyricResourceChanged(request)
            stopMidiView()
            startMidiView()
        }

        override fun onResume(mKtvPlayRequest: KaraokePlayRequest) {
            log("call onResume")
            startMidiView()
        }

        override fun onPause(mKtvPlayRequest: KaraokePlayRequest) {
            log("onPause")
            stopMidiView()
        }

        override fun onPlayEnd(request: KaraokePlayRequest, endInfo: PlayEndInfo) {
            Log.e(TAG, "onPlayEnd")
            mHandler.post {
                stopMidiView()
                midiView.releaseMidi()

                val openScore =
                    viewModel.currSongInfo().value?.mNoteBytes != null && viewModel.currSongInfo().value?.songType == SongType.SONG_TYPE_K_SONG
                if (!openScore && endInfo.isPlayFinish) {
                    playNextIfNeed()
                }
            }
        }

        override fun onSeekComplete(request: KaraokePlayRequest, position: Long) {
            log("onPlayPositionChange currentTime $position ")
            midiView.seekMidi(position)
        }

        override fun onBufferingStart(request: KaraokePlayRequest?) {
            stopMidiView()
        }

        override fun onBufferingEnd(request: KaraokePlayRequest?) {
            startMidiView()
        }
    }


 需要把两个实现添加到播放器中
 karaokePlayer.addCallback(CallbackImpl())  
 karaokePlayer.addOnScoreListener(ScoreListenerImpl())
上面为sdk2.0的打分样式,3.0新增了一种打分样式,具体样式与回调的设置参照此文档《3.0新打分样式》

5.3 MidiView 修改配置#

音高数据#

音高数据支持修改 背景和画笔风格
MidiScoreView.getIntonationViewGroup().getIntonationView().getIntonationViewerParam();
IntonationViewerParam 画笔如下
更改midiView的高度 背景色 打分条的画笔颜色 粗细
例如:在midiView的界面内,获取到MidiScoreView后:
        val intonationViewerParam = midiView.intonationViewGroup.intonationView.intonationViewerParam

        midiView.midiViewHeight = DisplayUtil.dp2px(140f)
        midiView.midiViewBackgroundColor = getActivity()?.resources?.getColor(R.color.ktv_brown) ?: -1

        val missPaint = Paint()
        missPaint.color = Color.parseColor("#234512")
        missPaint.strokeWidth = DisplayUtil.dp2px(8.0F).toFloat()
        intonationViewerParam.noteMissPaint = missPaint

        val hitPaint = Paint()
        hitPaint.color = Color.parseColor("#666666")
        hitPaint.strokeWidth = DisplayUtil.dp2px(8.0F).toFloat()
        intonationViewerParam.noteHitPaint = hitPaint

6. 重要注意事项#

1.
歌曲类型设置:使用打分功能必须将songType设置为SONG_TYPE_K_SONG(录唱模式),其他模式不支持打分。
2.
歌词配置:确保正确设置歌词信息,否则无法打分:
3.
轮询模式:3.0版本支持轮询模式(isPollMode),用于多屏一起唱的场景。在轮询模式下,需要实现ScoreResultRequester接口来获取打分数据。
4.
兼容性处理:即使设置了开启五维打分,也要同时设置普通打分的回调,因为部分歌曲支持打分但不支持五维打分,此时会自动回落到普通打分。
5.
Activity设置:2.0版本中必须调用MidiScoreView.setActivity(this),否则会影响动画效果。
6.
资源释放:在播放结束或Activity销毁时,确保调用releaseMidi()释放资源。
7.
歌曲支持判断:通过songInfoObject.mNoteBytes是否为null判断歌曲是否支持打分,通过songInfoObject.mOriginalMultiScoreContent是否为null判断歌曲是否支持五维打分。
修改于 2025-09-01 07:13:14
上一页
KtvSDK-接入指南
下一页
KtvSDK-登录
Built with