Unity實現卡拉OK歌詞過渡效果

這篇文章主要爲大家詳細介紹了Unity實現卡拉OK歌詞過渡效果,具有一定的參考價值,感興趣的小夥伴們可以參考一下

好長時間之前做過的一個項目 , 其中設計到用Unity模擬卡拉OK歌詞過渡的效果 , 如下圖所示 ↓ , 這裏簡單把原理部分分享一下.
文章目錄

  • 演示效果 ↓
  • 歌詞效果類 ↓
  • 配套資源下載

演示效果 ↓

  • 實現歌詞動態調整功能
  • 實現動態讀取歌詞文件功能
  • 實現歌曲快進快退功能
  • 實現歌曲單字時間匹配功能
  • 實現可動態更換歌詞前景色背景色功能

注:

這裏爲實現精準過渡效果使用的是KSC歌詞文件, 並不是LRC文件哦 .

這其中我認爲就是如何實現歌詞部分的前景色向後景色過渡的效果了, 開始的時候我想的也是很複雜 , 使用Shader的形式實現 ,網上找了一些相關代碼 , 發現不是特別理想 , 最終還是自己嘗試着用Mask來實現的, 發現效果還不錯 !
因爲今天下班就過年回家啦! 其他細節之後會完善的 , 今天把工程文件先上傳了 .

歌詞效果類 ↓

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using DG.Tweening;
using DG.Tweening.Core;

/// <summary>
/// 用於顯示歌詞過渡的效果
/// 1. 獲得路徑加載並解析歌詞文件信息
/// 2. 判斷當前歌曲是否播放( 歌曲暫停的時候歌詞效果也暫停 , 歌曲停止的時候歌詞效果消失 )
/// 3. 判斷歌曲快進或快退事件
/// </summary>
public class LayricPanelEffect : MonoSingleton<LayricPanelEffect>
{
 #region *********************************************************************字段

 //由外部傳入的聲音資源
 [HideInInspector,SerializeField]
 public AudioSource audioSource;
 //歌詞前景顏色;歌詞後景顏色
 [SerializeField]
 public Color32 frontTextColor = Color.white, backTextColor = Color.black, outlineColor = Color.white;
 //歌詞面板的前景部分和後景部分
 public RectTransform rectFrontLyricText, rectBackLyricMask;
 public Slider slider;
 //歌詞文件路徑
 [HideInInspector,SerializeField]
 public string lyricFilePath;

 //是否開始播放當前行歌詞內容
 public bool isStartLyricEffectTransition = true;
 //歌詞調整進度 ( 糾錯 )
 // [HideInInspector]
 public float lyricAdjust = -5f;

 //歌詞文本信息
 // [HideInInspector]
 [SerializeField,HideInInspector]
 public Text _lyricText;
 public Text _textContentLyric, _textLogMessage;

 private Vector2 tempFrontSizeDelta, tempBackSizeDelta;

 //用於訪問歌詞正文部分的內容在KscWord類中
 private KSC.KscWord kscword = new KSC.KscWord ();
 private KSC.KscWord curKscword = new KSC.KscWord ();

 //內部定時器( 由外部傳入參數來控制 , 用來記錄歌曲播放的當前時間軸 )
 private float _timer = 0.00f;

 #endregion

 /// <summary>
 /// 初始化一些變量
 /// </summary>
 void InitSomething ()
 {
 //堅持對歌詞文件進行賦值操作
 if (_lyricText == null || rectFrontLyricText.GetComponent <ContentSizeFitter> () == null) {
 if (rectFrontLyricText.GetComponent <Text> () == null) {
 _lyricText = rectFrontLyricText.gameObject.AddComponent <Text> ();
 }
 _lyricText = rectFrontLyricText.GetComponent <Text> ();

 //保持歌詞實現自適應
 rectFrontLyricText.GetComponent <ContentSizeFitter> ().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
 rectFrontLyricText.GetComponent <ContentSizeFitter> ().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
 }
 rectBackLyricMask.GetComponentInChildren <Text> ().text = _lyricText.text;

 //歌詞顏色的更改初始化
 rectBackLyricMask.GetComponentInChildren <Text> ().color = backTextColor;
 rectBackLyricMask.GetComponentInChildren <Outline> ().effectColor = outlineColor;
 rectFrontLyricText.GetComponent <Text> ().color = frontTextColor;

 //歌詞過渡的前景部分 ( 用於判斷過度遮罩的長度範圍 )
 tempFrontSizeDelta = rectFrontLyricText.sizeDelta;
 tempBackSizeDelta = rectBackLyricMask.sizeDelta;

 //是否開始當前歌詞行播放標誌位
 isStartLyricEffectTransition = true;
 }

 void Awake ()
 { 
 //初始化
 InitSomething ();
 }

 /// <summary>
 /// 控制歌詞面板的顯示
 /// 1. 僅僅顯示歌詞面板信息 , 沒有過渡效果!
 /// </summary>
 /// <param name="row">歌詞正文部分行號.</param>
 /// <param name="isPanelView">If set to <c>true</c> 顯示面板歌詞</param>
 public void LyricPanelControllerView (KSC.KscWord curRowInfo, bool isPanelView)
 {
// Debug.Log ("當前行是否開始=====>" + isPanelView.ToString ());
 _textLogMessage.text = isStartLyricEffectTransition.ToString ();

 rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y);

 rectBackLyricMask.GetComponentInChildren <Text> ().text = _lyricText.text = "";
 if (isPanelView) {
 //根據時間得到當前播放的是第i行的歌詞
 //處理歌詞面板信息 , 顯示歌詞
 foreach (var item in curRowInfo.PerLineLyrics) {
 _lyricText.text += item;
 rectBackLyricMask.GetComponentInChildren<Text> ().text = _lyricText.text;
 }
 StartCoroutine (LyricPanelControllerEffect (curRowInfo, isPanelView));
 } else {
 StopAllCoroutines ();
 rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y);
// StartCoroutine (LyricPanelControllerEffect (curRowInfo, isPanelView));
 //當前歌詞結束以後將歌詞框初始化成0
 rectBackLyricMask.GetComponentInChildren <Text> ().text = _lyricText.text = string.Empty;
 }
 }

 /// <summary>
 /// 開始實現歌此過渡效果, 僅僅效果實現
 /// 1. 使用Dotween的doSizedata實現
 /// 2. 動態調整蒙板的sizedata寬度
 /// 3. 根據歌曲當前播放的時間進度進行調整
 /// </summary>
 /// <returns>The panel controller effect.</returns>
 /// <param name="isPanelEffect">If set to <c>true</c> is panel effect.</param>
 public IEnumerator LyricPanelControllerEffect (KSC.KscWord curRowInfo, bool isPanelEffect)
 {
 //當前時間歌詞播放進度的百分比比例
 int curWordIndex = 0;
 if (isPanelEffect) {
 rectBackLyricMask.DORewind ();
 yield return null;
 rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y);
 //開始效果過渡
 if (audioSource.isPlaying) {
 for (int i = 0; i < curKscword.PerLinePerLyricTime.Length; i++) {
 rectBackLyricMask.DOSizeDelta (
 new Vector2 (((float)(i + 1) / curKscword.PerLinePerLyricTime.Length) * rectFrontLyricText.sizeDelta.x, rectFrontLyricText.sizeDelta.y)
 , curKscword.PerLinePerLyricTime [i] / 1000f
 , false).SetEase (Ease.Linear);
// Debug.Log ("第" + i + "個歌詞時間");
 yield return new WaitForSeconds (curKscword.PerLinePerLyricTime [i] / 1000f);
 }
 } else {
 Debug.LogError ("歌曲沒有播放 !!!!");
 }
 } else {
 yield return null;
 rectBackLyricMask.DOSizeDelta (new Vector2 (0f, rectFrontLyricText.sizeDelta.y), 0f, true);
 }
 }

 /// <summary>
 /// 開始播放音樂的時候調用
 /// </summary>
 /// <param name="lyricFilePath">歌詞文件路徑.</param>
 /// <param name="audioSource">Audiosource用於判斷播放狀態.</param>
 /// <param name="frontColor">前景色.</param>
 /// <param name="backColor">後景.</param>
 /// <param name="isIgronLyricColor">如果設置爲 <c>true</c> 則使用系統配置的默認顏色.</param>
 public void StartPlayMusic (string lyricFilePath, AudioSource audioSource, Color frontColor, Color backColor, Color outlineColor, bool isIgronLyricColor)
 {
 _timer = 0f;

 //初始化ksc文件
 KSC.InitKsc (lyricFilePath);

 this.lyricFilePath = lyricFilePath;
 this.audioSource = audioSource;

 _textContentLyric.text = string.Empty;

 if (!isIgronLyricColor) {
 //歌曲顏色信息
 this.frontTextColor = frontColor;
 this.backTextColor = backColor;
 this.outlineColor = outlineColor;
 }

 #region ****************************************************輸出歌詞文件信息
 //對初始化完成後的信息進行輸出
 if (KSC.Instance.SongName != null) {
 print ("歌名==========>" + KSC.Instance.SongName);
 }
 if (KSC.Instance.Singer != null) {
 print ("歌手==========>" + KSC.Instance.Singer);
 }
 if (KSC.Instance.Pinyin != null) {
 print ("拼音==========>" + KSC.Instance.Pinyin);
 }
 if (KSC.Instance.SongClass != null) {
 print ("歌類==========>" + KSC.Instance.SongClass);
 }
 if (KSC.Instance.InternalNumber > 0) {
 print ("歌曲編號=======>" + KSC.Instance.InternalNumber);
 }
 if (KSC.Instance.Mcolor != Color.clear) {
 print ("男唱顏色=======>" + KSC.Instance.Mcolor);
 }
 if (KSC.Instance.Mcolor != Color.clear) {
 print ("女唱顏色=======>" + KSC.Instance.Wcolor);
 }
 if (KSC.Instance.SongStyle != null) {
 print ("風格==========>" + KSC.Instance.SongStyle);
 }
 if (KSC.Instance.WordCount > 0) {
 print ("歌名字數=======>" + KSC.Instance.WordCount);
 }
 if (KSC.Instance.LangClass != null) {
 print ("語言種類=======>" + KSC.Instance.LangClass);
 }

 //一般是獨唱歌曲的時候使用全Tag標籤展現參數信息
 foreach (var item in KSC.Instance.listTags) {
 print (item);
 }
 #endregion

 //顯示整個歌詞內容
 for (int i = 0; i < KSC.Instance.Add.Values.Count; i++) {
 KSC.Instance.Add.TryGetValue (i, out kscword);
 for (int j = 0; j < kscword.PerLineLyrics.Length; j++) {
 _textContentLyric.text += kscword.PerLineLyrics [j];
 }
 _textContentLyric.text += "\n";
 }
 }

 /// <summary>
 /// 停止播放按鈕
 /// </summary>
 public void StopPlayMusic ()
 {
 Debug.Log ("停止播放按鈕");
 }

 /// <summary>
 /// 主要用於歌詞部分的卡拉OK過渡效果
 /// 1. 動態賦值歌詞框的長度
 /// 2. 支持快進快退同步顯示
 /// </summary>
 int row = 0, tempRow = 0;

 void FixedUpdate ()
 {
 #region *********************************************************播放過渡效果核心代碼
 //如果是播放狀態並且沒有快進或快退 , 獲得當前播放時間 , 如果都下一句歌詞了 , 則切換到下一句歌詞進行過渡效果
 //1. 是否是暫停;
 //2. 是否開始播放
 //3. 是否播放停止
 if (audioSource != null && audioSource.isPlaying) {
 //進度條
 slider.value = _timer / audioSource.clip.length;
 //快進快退快捷鍵
 if (Input.GetKey (KeyCode.RightArrow)) {
 audioSource.time = Mathf.Clamp ((audioSource.time + 1f), 0f, 4.35f * 60f);
 } else if (Input.GetKey (KeyCode.LeftArrow)) {
 audioSource.time = Mathf.Clamp ((audioSource.time - 1f), 0f, 4.35f * 60f);
// } else if (Input.GetKeyUp (KeyCode.LeftArrow)) {
 isStartLyricEffectTransition = true;
 rectBackLyricMask.GetComponentInChildren <Text> ().text = rectFrontLyricText.GetComponent <Text> ().text = string.Empty;
 }

 //實時計時
 _timer = audioSource.time;

 //歌曲開始播放的時間
 _textLogMessage.text = _timer.ToString ("F2");

 for (int i = 0; i < KSC.Instance.Add.Count; i++) {

 KSC.Instance.Add.TryGetValue (i, out kscword);

 //根據時間判斷當前播放的是哪一行的歌詞文件 ( 減去0.01可保證兩句歌詞銜接太快的時候的bug )
 if ((_timer >= (kscword.PerLineLyricStartTimer + lyricAdjust + 0.1f) && _timer <= (kscword.PerLintLyricEndTimer + lyricAdjust - 0.1f)) && isStartLyricEffectTransition) {
 tempRow = i;
 KSC.Instance.Add.TryGetValue (tempRow, out curKscword);
 isStartLyricEffectTransition = false;
 Debug.Log ("當前播放====>" + i + "行");
 //歌詞面板顯示當前播放內容
 LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);
 } else if ((_timer >= (curKscword.PerLintLyricEndTimer + lyricAdjust)) && !isStartLyricEffectTransition) {
 isStartLyricEffectTransition = true;
 //設置不顯示歌詞內容
 LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);
 } 
 }

// KSC.Instance.Add.TryGetValue (row, out kscword);
//
// //根據時間判斷當前播放的是哪一行的歌詞文件 ( 減去0.01可保證兩句歌詞銜接太快的時候的bug )
// if ((_timer >= (kscword.PerLineLyricStartTimer + lyricAdjust + 0.1f) && _timer <= (kscword.PerLintLyricEndTimer + lyricAdjust)) && isStartLyricEffectTransition) {
// tempRow = row;
// KSC.Instance.Add.TryGetValue (tempRow, out curKscword);
// isStartLyricEffectTransition = false;
// Debug.Log ("當前播放====>" + row + "行");
// //歌詞面板顯示當前播放內容
// LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);
// } else if ((_timer >= (curKscword.PerLintLyricEndTimer + lyricAdjust)) && !isStartLyricEffectTransition) {
// isStartLyricEffectTransition = true;
// //設置不顯示歌詞內容
// LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);
// row = (row + 1) % KSC.Instance.Add.Count;
// } 
 #endregion
 }
 }
}

###KSC文件解析類 ↓

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Text;
using UnityEngine.UI;
using System;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

/// <summary>
/// KSC歌詞文件解析屬性, 單例工具類 ( 解析解析解析解析解析解析解析解析解析!!!!!!重要的事情多說幾遍 )
/// 1. 歌詞部分標題信息用單例instance訪問
/// 2. 正文信息部分使用KSCWord對象訪問( 每句開始時間\結束時間\每句歌詞文字的數組\每句歌詞文件時間的數組 )
/// </summary>
public class KSC : Singleton<KSC>
{
 /// <summary>
 /// 歌曲 歌名
 /// </summary>
 public string SongName { get; set; }

 /// <summary>
 /// 歌名字數 歌名字數
 /// </summary>
 public int WordCount{ get; set; }

 /// <summary>
 /// 歌名字數 歌名的拼音聲母
 /// </summary>
 public string Pinyin{ get; set; }

 /// <summary>
 /// 歌名字數 歌曲語言種類
 /// </summary>
 public string LangClass{ get; set; }

 /// <summary>
 /// 歌類,如男女樂隊等
 /// </summary>
 public string SongClass{ get; set; }

 /// <summary>
 /// 藝術家 演唱者,對唱則用斜槓"/"分隔
 /// </summary>
 public string Singer { get; set; }

 /// <summary>
 /// 歌曲編號 歌曲編號
 /// </summary>
 public int InternalNumber{ get; set; }

 /// <summary>
 /// 歌曲風格
 /// </summary>
 public string SongStyle{ get; set; }

 /// <summary>
 /// 視頻編號 
 /// </summary>
 public string VideoFileName{ get; set; }

 /// <summary>
 /// 前景顏色
 /// </summary>
 public Color Mcolor{ get; set; }

 /// <summary>
 /// 後景顏色
 /// </summary>
 public Color Wcolor{ get; set; }

 /// <summary>
 /// 偏移量
 /// </summary>
 public string Offset { get; set; }

 /// <summary>
 /// 各類標籤
 /// </summary>
 public List<string> listTags = new List<string> ();

 /// <summary>
 /// 歌詞正文部分信息 ( key = 行號 value = 解析出來的歌詞正文部分的每句歌詞信息 )
 /// </summary>
 public Dictionary<int,KscWord> Add = new Dictionary<int, KscWord> ();


 /// <summary>
 /// 獲得歌詞信息
 /// </summary>
 /// <param name="LrcPath">歌詞路徑</param>
 /// <returns>返回歌詞信息(Lrc實例)</returns>
 public static KSC InitKsc (string LrcPath)
 {
 int row = 0;
 //KscWord對象
 //清除之前的歌曲歌詞, 保持當前
 KSC.Instance.Add.Clear ();
 using (FileStream fs = new FileStream (LrcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
 string line = string.Empty;
 using (StreamReader sr = new StreamReader (fs, Encoding.Default)) {
 
 while ((line = sr.ReadLine ()) != null) {
 //每次循環新建一個對象用於存儲不同行數內容
 KSC.KscWord kscWord = new KSC.KscWord ();
 #region ######################################合唱歌曲格式
 if (line.StartsWith ("karaoke.songname := '")) {
 Instance.SongName = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.internalnumber := ")) {
 if (SplitIntInfo (line) != 0) {
 Instance.InternalNumber = SplitIntInfo (line);
 }
 } else if (line.StartsWith ("karaoke.singer := '")) {
 Instance.Singer = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.wordcount := ")) {
 if (SplitIntInfo (line) != 0) {
 Instance.WordCount = SplitIntInfo (line);
 }
 } else if (line.StartsWith ("karaoke.pinyin := '")) {
 Instance.Pinyin = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.langclass := '")) {
 Instance.LangClass = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.songclass := '")) {
 Instance.SongClass = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.songstyle := '")) {
 Instance.SongStyle = SplitStrInfo (line);
 } else if (line.StartsWith ("karaoke.videofilename :='")) {
 Instance.VideoFileName = SplitStrInfo (line);
 } else if (line.StartsWith ("mcolor :=rgb(")) {
 if (SplitColorInfo (line) != Color.clear) {
 Instance.Mcolor = SplitColorInfo (line);
 }
 } else if (line.StartsWith ("wcolor :=rgb(")) {
 if (SplitColorInfo (line) != Color.clear) {
 Instance.Wcolor = SplitColorInfo (line);
 }
 #endregion

 #region ##################################################獨唱歌曲風格
 } else if (line.StartsWith ("karaoke.tag('")) {
 //獲取tag標籤的參數信息
 KSC.Instance.listTags.Add (SplitTagInfo (line));
 #endregion 

 #region ################################################歌詞正文部分解析
 } else if (line.StartsWith (("karaoke.add"))) {   //表示歌詞正文部分
 if (SplitLyricStartTime (line) != null) {
 //行號 ( 從0行開始 )

 //獲取每句歌詞部分的開始時間
 kscWord.PerLineLyricStartTimer = SplitLyricStartTime (line);
 //獲取每句歌詞部分的結束時間
 kscWord.PerLintLyricEndTimer = SplitLyricEndTime (line);
 //獲取每行歌詞的內容,並存儲到KSCWord中 ( 歌詞文字的數組信息 左 → 右 )
 kscWord.PerLineLyrics = SplitPerLineLyrics (line);
 //獲取每行中單個文字的過渡時間數組 ( 歌詞文字過渡時間數組 左 → 右 )
 kscWord.PerLinePerLyricTime = SplitPerLinePerLyricTime (line);
 KSC.Instance.Add.Add (row, kscWord);
 row++;
 }
 } else {
 //忽略ksc文件中的其他部分
 if (line != "" && !line.Contains ("CreateKaraokeObject") && !line.Contains ("karaoke.rows") && !line.Contains ("karaoke.clear;") && !Regex.IsMatch (line, @"^\//")) {
 Debug.LogWarning ("歌詞含有不能解析的部分 ===> " + line);
 }
 }
 #endregion
 }
 }
 } 
 Debug.Log ("LyricFileInitialized" + " Path : \n" + LrcPath);
 return Instance;
 }

 #region ****************************************************************解析歌詞用的正則表達式部分 需更新

 /// <summary>
 /// 處理信息(私有方法)
 /// </summary>
 /// <param name="line"></param>
 /// <returns>返回基礎信息</returns>
 public static string SplitStrInfo (string line)
 {
// char[] ch = new char[]{ '\0', '\0' };
// return line.Substring (line.IndexOf ("'") + 1).TrimEnd (ch);
 string pattern = @"'\S{1,20}'"; //獲取歌曲標籤信息
 Match match = Regex.Match (line, pattern);

 //去除兩端的小分號
 string resout = string.Empty;
 resout = match.Value.Replace ("\'", string.Empty);
 return resout;
 }

 /// <summary>
 /// 處理參數是數字的情況
 /// </summary>
 /// <returns>The int info.</returns>
 /// <param name="line">Line.</param>
 public static int SplitIntInfo (string line)
 {
 string pattern = @"\d+"; //獲取歌曲標籤參數爲數字的信息
 Match match = Regex.Match (line, pattern);

 //去除兩端的小分號
 int result = 0;
 result = Int32.Parse (match.Value);
 return result;
 }

 /// <summary>
 /// 處理參數顏色色值的情況 如: mcolor :=rgb(0, 0, 255);
 /// </summary>
 /// <returns>The color info.</returns>
 /// <param name="line">Line.</param>
 public static Color32 SplitColorInfo (string line)
 {
 string pattern = @"[r,R][g,G][b,G]?[\(](2[0-4][0-9])|25[0-5]|[01]?[0-9][0-9]?"; //獲取歌曲標籤參數爲顏色值的信息
 MatchCollection matches = Regex.Matches (line, pattern);

 return new Color (float.Parse (matches [0].ToString ()), float.Parse (matches [1].ToString ()), float.Parse (matches [2].ToString ()));
 }

 /// <summary>
 /// 獲取歌曲的標籤部分信息 如 : karaoke.tag('語種', '國語'); // 國語/粵語/臺語/外語
 /// </summary>
 /// <returns>The tag info.</returns>
 public static string SplitTagInfo (string line)
 {
 string temp;
 string pattern = @"\([\W|\w]+\)"; //獲取歌曲標籤參數爲顏色值的信息
 Match match = Regex.Match (line, pattern);
 temp = match.Value.Replace ("(", string.Empty).Replace (")", string.Empty).Replace ("'", string.Empty).Replace (",", ":");
 return temp;
 }

 /// <summary>
 /// 獲取每句歌詞正文部分的開始時間 (單位 : 秒)
 /// </summary>
 /// <returns>The lyric start time.</returns>
 /// <param name="line">Line.</param>
 public static float SplitLyricStartTime (string line)
 {
 float time = 0f;
 Regex regex = new Regex (@"\d{2}:\d{2}\.\d{2,3}", RegexOptions.IgnoreCase); //匹配單句歌詞時間 如: karaoke.add('00:29.412', '00:32.655'
 MatchCollection mc = regex.Matches (line);
 time = (float)TimeSpan.Parse ("00:" + mc [0].Value).TotalSeconds;
 return time;
 }

 /// <summary>
 /// 獲取每句歌詞正文部分的結束時間 (單位 : 秒)
 /// </summary>
 /// <returns>The lyric start time.</returns>
 /// <param name="line">Line.</param>
 public static float SplitLyricEndTime (string line)
 {
 Regex regex = new Regex (@"\d{2}:\d{2}\.\d{2,3}", RegexOptions.IgnoreCase); //匹配單句歌詞時間 如: karaoke.add('00:29.412', '00:32.655'
 MatchCollection mc = regex.Matches (line);
 float time = (float)TimeSpan.Parse ("00:" + mc [1].Value).TotalSeconds;
 return time;
 }

 /// <summary>
 /// 獲取每句歌詞部分的每個文字 和 PerLinePerLyricTime相匹配 (單位 : 秒)
 /// </summary>
 /// <returns>The line lyrics.</returns>
 /// <param name="line">Line.</param>
 public static string[] SplitPerLineLyrics (string line)
 {
 List<string> listStrResults = new List<string> ();
 string pattern1 = @"\[[\w|\W]{1,}]{1,}"; //獲取歌曲正文每個單詞 如 : karaoke.add('00:25.183', '00:26.730', '[五][十][六][個][星][座]', '312,198,235,262,249,286');
 string pattern2 = @"\'(\w){1,}\'"; //獲取歌曲正文每個單詞 如 : karaoke.add('00:28.420', '00:35.431', '夕陽底晚風裏', '322,1256,2820,217,1313,1083');
 Match match = (line.Contains ("[") && line.Contains ("]")) ? Regex.Match (line, pattern1) : Regex.Match (line, pattern2);
 //刪除掉 [ ] '
 if (match.Value.Contains ("[") && match.Value.Contains ("]")) { //用於合唱類型的歌詞文件
 string[] resultStr = match.Value.Replace ("][", "/").Replace ("[", string.Empty).Replace ("]", string.Empty).Split ('/');
 foreach (var item in resultStr) {
 listStrResults.Add (item);
 }
 } else if (match.Value.Contains ("'")) {  //用於獨唱類型的歌詞文件 ( 尚未測試英文歌詞文件!!!!!!!!!!!!!!!!!!!!!!! )
 char[] tempChar = match.Value.Replace ("'", string.Empty).ToCharArray ();
 foreach (var item in tempChar) {
 listStrResults.Add (item.ToString ());
 }
 }
 return listStrResults.ToArray ();
 }

 /// <summary>
 /// 獲取每句歌詞部分的每個文字需要的過渡時間 和 PerLineLyrics相匹配 (單位 : 秒)
 /// </summary>
 /// <returns>The line per lyric time.</returns>
 /// <param name="line">Line.</param>
 public static float[] SplitPerLinePerLyricTime (string line)
 {
 string pattern = @"\'((\d){0,}\,{0,1}){0,}\'"; //獲取歌曲正文每個單詞過渡時間 如 : karaoke.add('00:25.183', '00:26.730', '[五][十][六][個][星][座]', '312,198,235,262,249,286');

 string str = null;
 List<float> listfloat = new List<float> ();
 //刪除掉 多餘項
 str = Regex.Match (line, pattern).Value.Replace ("'", string.Empty);
// Debug.Log (str);
 foreach (var item in str.Split (',')) {
 listfloat.Add (float.Parse (item));
 }
 return listfloat.ToArray ();
 }

 #endregion

 #region ********************************************************************歌詞正文部分的時間與文字信息

 /// <summary>
 /// 用單獨的類來管理歌詞的正文部分 ( 在KSC類下 )主要用來存儲每句歌詞和每個歌詞的時間信息
 /// 1. 每句歌詞的時間的 ( 開始 - 結束 )
 /// 2. 每句歌詞中單個文字的時間信息 (集合的形式實現)
 /// </summary>
 public class KscWord
 {
 /// <summary>
 /// 每行歌詞部分開始的時間 (單位 : 秒) (key=行號,value=時間)
 /// </summary>
 public float PerLineLyricStartTimer { get; set; }

 /// <summary>
 /// 每行歌詞部分結束時間 (單位 : 秒) (key=行號,value=時間)
 /// </summary>
 public float PerLintLyricEndTimer { get; set; }

 /// <summary>
 /// 每行歌詞的單個文字集合
 /// </summary>
 public string[] PerLineLyrics{ get; set; }

 /// <summary>
 /// 每行歌詞中單個文字的速度過渡信息 (單位 : 毫秒)
 /// </summary>
 public float[] PerLinePerLyricTime{ get; set; }
 }

 #endregion
}

不敢說代碼如何清新脫俗 , 自己也在學習的路上 , 有程序愛好者想要交流的話歡迎交流啊 . 有心的朋友可以看看 , 年後看時間再完善啦

配套資源下載

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章