Skip to content
This repository was archived by the owner on Nov 10, 2022. It is now read-only.

Commit d27448e

Browse files
committed
[FEAT] Add lrcEnableDrag attr; Score tuning done.
1 parent d5a31cb commit d27448e

File tree

4 files changed

+109
-57
lines changed

4 files changed

+109
-57
lines changed

lrcview/build.gradle

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ android {
88
defaultConfig {
99
minSdkVersion 16
1010
targetSdkVersion 31
11-
versionCode 3
12-
versionName "1.0.2"
11+
versionCode 6
12+
versionName "1.0.5"
1313

1414
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1515
consumerProguardFiles "consumer-rules.pro"
@@ -26,6 +26,13 @@ android {
2626
sourceCompatibility JavaVersion.VERSION_1_8
2727
targetCompatibility JavaVersion.VERSION_1_8
2828
}
29+
30+
libraryVariants.all { variant ->
31+
variant.outputs.all {
32+
outputFileName = "lrc_view_v" +
33+
defaultConfig.versionName + ".aar"
34+
}
35+
}
2936
}
3037

3138
dependencies {
@@ -35,14 +42,17 @@ dependencies {
3542

3643
afterEvaluate {
3744
publishing {
45+
repositories {
46+
it.mavenLocal()
47+
}
3848
publications {
3949
// Creates a Maven publication called "release".
4050
release(MavenPublication) {
4151
artifact sourceJar
4252
from components.release
4353
groupId = 'com.github.AgoraIO-Community'
4454
artifactId = 'LrcView-Android'
45-
version = '1.0.2'
55+
version = '1.0.5'
4656
}
4757
}
4858
}

lrcview/src/main/java/io/agora/lrcview/LrcView.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ private void init(AttributeSet attrs) {
125125
mDefaultLabel = TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.lrc_label) : mDefaultLabel;
126126
int lrcTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, 0);
127127
mTextGravity = io.agora.lrcview.LrcEntry.Gravity.parse(lrcTextGravity);
128+
enableDrag = ta.getBoolean(R.styleable.LrcView_lrcEnableDrag,true);
128129

129130
ta.recycle();
130131

lrcview/src/main/java/io/agora/lrcview/PitchView.java

Lines changed: 94 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
import android.os.Handler;
1313
import android.os.Looper;
1414
import android.util.AttributeSet;
15+
import android.util.Log;
1516
import android.util.TypedValue;
1617
import android.view.View;
1718

1819
import androidx.annotation.Nullable;
1920
import androidx.annotation.RequiresApi;
2021

21-
import java.util.ArrayList;
22+
import java.util.Iterator;
23+
import java.util.LinkedHashMap;
2224
import java.util.List;
2325

2426
import io.agora.lrcview.bean.LrcData;
@@ -48,15 +50,15 @@ public class PitchView extends View {
4850

4951
// 完成 PitchView.OnActionListener#onOriginalPitch的需求
5052
// 当前 Pitch 所在的字的开始时间
51-
private long currentPitchStartTime = 0;
53+
private long currentPitchStartTime = -1;
5254
// 当前 Pitch 所在的字的结束时间
53-
private long currentPitchEndTime = 0;
55+
private long currentPitchEndTime = -1;
5456
// 当前 Pitch 所在的句的结束时间
55-
private long currentEntryEndTime = 0;
56-
// 当前在打分的所在句的结束时间
57-
private long currentScoreEntryEndTime = 0;
57+
private long currentEntryEndTime = -1;
5858
// 当前在打分的所在句的结束时间
5959
private long lrcEndTime = 0;
60+
// 当前 时间的 Pitch
61+
private float currentPitch = 0f;
6062

6163
// 音调指示器的半径
6264
private int indicatorRadius;
@@ -65,7 +67,7 @@ public class PitchView extends View {
6567
// 初始分数
6668
private float mInitialScore;
6769
// 每句歌词分数
68-
public List<Double> sentenceScoreList = new ArrayList<>();
70+
public LinkedHashMap<Long, Double> everyPitchList = new LinkedHashMap<>();
6971
// 累计分数
7072
public float cumulatedScore;
7173
// 歌曲总分数
@@ -152,6 +154,7 @@ protected void onDraw(Canvas canvas) {
152154
}
153155
//</editor-fold>
154156

157+
//<editor-fold desc="Draw Related">
155158
private void drawLocalPitch(Canvas canvas) {
156159
mPaint.setShader(null);
157160
mPaint.setColor(mNormalTextColor);
@@ -233,6 +236,7 @@ private void drawItems(Canvas canvas) {
233236
}
234237
}
235238
}
239+
//</editor-fold>
236240

237241
/**
238242
* 设置歌词信息
@@ -247,11 +251,14 @@ public void setLrcData(@Nullable LrcData data) {
247251
pitchMax = 0;
248252
pitchMin = 100;
249253

250-
currentPitchStartTime = 0;
251-
currentPitchEndTime = 0;
252-
currentEntryEndTime = 0;
253-
currentScoreEntryEndTime = 0;
254-
sentenceScoreList.clear();
254+
currentPitchStartTime = -1;
255+
currentPitchEndTime = -1;
256+
currentEntryEndTime = -1;
257+
everyPitchList.clear();
258+
259+
260+
cumulatedScore = mInitialScore;
261+
totalScore = 0;
255262

256263
if (lrcData != null && lrcData.entrys != null && !lrcData.entrys.isEmpty()) {
257264

@@ -267,6 +274,7 @@ public void setLrcData(@Nullable LrcData data) {
267274
}
268275
}
269276

277+
270278
invalidate();
271279
}
272280

@@ -279,22 +287,25 @@ private void setMLocalPitch(float mLocalPitch) {
279287
}
280288

281289
/**
282-
* 根据当前播放时间获取 Pitch
290+
* 根据当前播放时间获取 Pitch,并且更新
291+
* {@link this#currentPitchStartTime}
292+
* {@link this#currentPitchEndTime}
293+
* {@link this#currentEntryEndTime}
283294
*
284295
* @return 当前时间歌词的 Pitch
285296
*/
286-
private float findPitchByTime() {
297+
private float findPitchByTime(long time) {
287298
if (lrcData == null) return 0;
288299

289300
float resPitch = 0;
290301
int entryCount = lrcData.entrys.size();
291302
for (int i = 0; i < entryCount; i++) {
292303
LrcEntryData tempEntry = lrcData.entrys.get(i);
293-
if (mCurrentTime >= tempEntry.getStartTime()) { // 索引
304+
if (time >= tempEntry.getStartTime() && time <= tempEntry.getEndTime()) { // 索引
294305
int toneCount = tempEntry.tones.size();
295306
for (int j = 0; j < toneCount; j++) {
296307
LrcEntryData.Tone tempTone = tempEntry.tones.get(j);
297-
if (mCurrentTime <= tempTone.end) {
308+
if (time >= tempTone.begin && time <= tempTone.end) {
298309
resPitch = tempTone.pitch;
299310
currentPitchStartTime = tempTone.begin;
300311
currentPitchEndTime = tempTone.end;
@@ -307,10 +318,16 @@ private float findPitchByTime() {
307318
}
308319
}
309320
if (resPitch == 0) {
310-
currentPitchStartTime = 0;
311-
currentPitchEndTime = 0;
312-
currentEntryEndTime = 0;
321+
currentPitchStartTime = -1;
322+
currentPitchEndTime = -1;
323+
if(time > currentEntryEndTime)
324+
currentEntryEndTime = -1;
325+
}else{
326+
// 进入此行代码条件 : 所唱歌词句开始时间 <= 当前时间 >= 所唱歌词句结束时间
327+
// 强行加上一个 0 分 ,标识此为可打分句
328+
everyPitchList.put(time, 0d);
313329
}
330+
currentPitch = resPitch;
314331
return resPitch;
315332
}
316333

@@ -321,9 +338,9 @@ private float findPitchByTime() {
321338
*/
322339
public void updateLocalPitch(float pitch) {
323340
if (lrcData == null) return;
324-
float desiredPitch = findPitchByTime();
325-
if (desiredPitch != 0)
326-
updateScore(pitchToTone(pitch), pitchToTone(desiredPitch));
341+
float tempPitch = currentPitch;
342+
if (tempPitch != 0)
343+
calculateScore(mCurrentTime, pitchToTone(pitch), pitchToTone(tempPitch));
327344

328345
mHandler.removeCallbacksAndMessages(null);
329346
mHandler.postDelayed(() -> {
@@ -334,40 +351,60 @@ public void updateLocalPitch(float pitch) {
334351
ObjectAnimator.ofFloat(this, "mLocalPitch", this.mLocalPitch, pitch).setDuration(50).start();
335352
}
336353

337-
/**
338-
* 更新当前分数
339-
*
340-
* @param currentTone 演唱值
341-
* @param desiredTone 理想值
342-
*/
343-
private void updateScore(double currentTone, double desiredTone) {
354+
private void calculateScore(long currentTime, double currentTone, double desiredTone) {
344355
double score = 1 - Math.abs(desiredTone - currentTone) / desiredTone;
356+
// 得分线以下的分数归零
345357
score = score >= scoreCountLine ? score : 0f;
358+
// 百分制分数 * 每句固定分数
346359
score *= scorePerSentence;
360+
everyPitchList.put(currentTime, score);
361+
}
347362

348-
// 当前未在打分 <==> 定位打分句结束时间到当前句
349-
if (sentenceScoreList.isEmpty()) currentScoreEntryEndTime = currentEntryEndTime;
350-
351-
// 打分句结束时间已过 或者 最后一句已经结束
352-
if (mCurrentTime > currentScoreEntryEndTime || mCurrentTime > lrcEndTime) { // 已经到下一句了
353-
// 分数列表不为空
354-
if (!sentenceScoreList.isEmpty()) {
355-
363+
/**
364+
* 更新当前分数
365+
*
366+
* @param time 当前歌曲播放时间 毫秒
367+
*/
368+
private void updateScore(long time) {
369+
// 没有开始 || 在空档期
370+
boolean pushAll = currentEntryEndTime == -1;
371+
// 当前时间 >= 打分句结束时间
372+
boolean isThisSentenceOver = time >= currentEntryEndTime;
373+
// 当前时间 >= 歌词结束时间
374+
boolean isThisSongOver = time >= lrcEndTime;
375+
376+
if (pushAll || isThisSentenceOver || isThisSongOver) {
377+
if (!everyPitchList.isEmpty()) {
356378
// 计算歌词当前句的分数 = 所有打分/分数个数
357-
double tempScore = 0;
358-
for (Double toneScore : sentenceScoreList)
359-
tempScore += toneScore;
379+
double tempTotalScore = 0;
380+
int scoreCount = 0;
381+
382+
Double tempScore;
383+
// 两种情况 1. 到了空档期 2. 到了下一句
384+
Iterator<Long> iterator = everyPitchList.keySet().iterator();
385+
while (iterator.hasNext()){
386+
Long duration = iterator.next();
387+
if (pushAll || duration <= currentEntryEndTime) {
388+
tempScore = everyPitchList.get(duration);
389+
iterator.remove();
390+
everyPitchList.remove(duration);
391+
if (tempScore != null) {
392+
tempTotalScore += tempScore.floatValue();
393+
scoreCount++;
394+
}
395+
}
396+
}
360397

398+
// 获取歌词pitch时为了标记可打分句给每句加了1个0分
399+
scoreCount = Math.max(1, scoreCount - 1);
400+
401+
double scoreThisTime = tempTotalScore / scoreCount;
361402
// 统计到累计分数
362-
cumulatedScore += tempScore / sentenceScoreList.size();
403+
cumulatedScore += scoreThisTime;
363404
// 回调到上层
364-
dispatchScore(score);
365-
// 清除打分
366-
sentenceScoreList.clear();
405+
dispatchScore(scoreThisTime);
367406
}
368407
}
369-
370-
sentenceScoreList.add(score);
371408
}
372409

373410
/**
@@ -387,13 +424,15 @@ private void dispatchScore(double score) {
387424
* @param time 当前播放时间,毫秒
388425
*/
389426
public void updateTime(long time) {
390-
if (lrcData == null) {
391-
return;
392-
} else if (time < currentPitchStartTime || time > currentPitchEndTime) {
393-
onActionListener.onOriginalPitch(findPitchByTime(), totalPitch);
394-
}
395-
427+
if (lrcData == null) return;
396428
this.mCurrentTime = time;
429+
if (time < currentPitchStartTime || time > currentPitchEndTime) {
430+
float tempPitch = findPitchByTime(time);
431+
if (tempPitch > 0) {
432+
onActionListener.onOriginalPitch(tempPitch, totalPitch);
433+
}
434+
}
435+
updateScore(time);
397436

398437
invalidate();
399438
}
@@ -413,8 +452,9 @@ public static interface OnActionListener {
413452

414453
/**
415454
* 咪咕歌词原始参考pitch值回调, 用于开发者自行实现打分逻辑. 歌词每个tone回调一次
416-
* pitch: 当前tone的pitch值
417-
* totalCount: 整个xml的tone个数, 用于开发者方便自己在app层计算平均分.
455+
*
456+
* @param pitch 当前tone的pitch值
457+
* @param totalCount 整个xml的tone个数, 用于开发者方便自己在app层计算平均分.
418458
*/
419459
void onOriginalPitch(float pitch, int totalCount);
420460

lrcview/src/main/res/values/attrs.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<attr name="lrcFutureTextColor" format="reference|color" />
1111
<attr name="lrcCurrentTextColor" format="reference|color" />
1212
<attr name="lrcLabel" format="string" />
13+
<attr name="lrcEnableDrag" format="boolean" />
1314
<attr name="lrcTextGravity">
1415
<enum name="center" value="0" />
1516
<enum name="left" value="1" />

0 commit comments

Comments
 (0)