音乐播放器的歌词同步实现
生活随笔
收集整理的這篇文章主要介紹了
音乐播放器的歌词同步实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?
首先,要下載對應(yīng)的歌詞Lrc文件。因為對應(yīng)的lrc文件中有固定格式,如:[00:00.00]荷塘月色。前面是時間,可以通過字符串操作得到,進(jìn)而轉(zhuǎn)換為毫秒數(shù)或者其他格式。
我的想法:
1>先創(chuàng)建一個工具包類:
?
import java.awt.Color;public class LrcDao {private double time = 0.0f;private String lyric = "";/** 獲取時間*/public double getTime(){return time;}/** 設(shè)置時間* tine :被設(shè)置成的時間*/public void setTime(double time){this.time = time;}/** 設(shè)置時間* time:被設(shè)置成的時間字符串,格式為毫秒數(shù)*///str[0]為分鐘,str[1]為秒鐘,str[2]為小數(shù)點后的數(shù)字public void setTime(String time ){String str[] = time.split(":|\\.");//this.time = Integer.parseInt(str[0])*60 + Integer.parseInt(str[1]) + Integer.parseInt(str[2])*0.01;//將這個時間化為毫秒數(shù)this.time = Integer.parseInt(str[0])*60*1000 + Integer.parseInt(str[1])*1000 + Integer.parseInt(str[2]);}/** 獲取歌詞*/public String getLyric(){return lyric;}public void setLyric(String lyric){this.lyric = lyric;}}?
2>以上工具包類的作用是存儲每一行歌詞,每一行歌詞創(chuàng)建一個以上的對象,每個對象中有兩個屬性:這一行顯示的時間和這一行顯示的字符串。
接下來就要讀取Lrc文件,進(jìn)而處理字符串,
import java.awt.Color; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern;import javax.swing.JFrame;import com.team.Music.SetSongLists; import com.team.ui.MainUI; import com.team.ui.MusicPlaySystem;public class LrcData extends Thread {BufferedReader bufferReader = null;public String title = "";public String artist = "";public String album = "";public String lrcMaker = "";public static long time2;public static long time1 = 0;public static JFrame jf = null;public static boolean run = true;public static boolean endLrc = false;public static LrcData lrcData = new LrcData();public FileInputStream file = null;public static long timeTemp = 0;public String lrcPathpppp = null;Vector<LrcDao> statements = new Vector<LrcDao>();/** 實例化一個歌詞數(shù)據(jù),歌詞數(shù)據(jù)信息由指定的文件提供 filename :指定的歌詞文件*/public void setPath(String filename) {try {// 先轉(zhuǎn)化為文件流FileInputStream file = new FileInputStream(filename);// 再轉(zhuǎn)化為bufferReaderbufferReader = new BufferedReader(new InputStreamReader(file, "GB2312"));// 將文件數(shù)據(jù)讀入內(nèi)存readData();} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}private LrcData() {}public static LrcData getLrcData() {return lrcData;}public LrcData(String filename) {bufferReader = null;try {// 先轉(zhuǎn)化為文件流file = new FileInputStream(filename);// 再轉(zhuǎn)化為bufferReaderbufferReader = new BufferedReader(new InputStreamReader(file, "GB2312"));// 將文件數(shù)據(jù)讀入內(nèi)存readData();} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}public void readData() {statements.clear();String strLine = "";// 循環(huán)讀入所有行try {while (null != (strLine = bufferReader.readLine())) {// 判斷該行是否為空行if ("".equals(strLine.trim())) {continue;}int timeNum = 0; // 本行含時間個數(shù)String str[] = strLine.split("\\]"); // 以]分隔for (int i = 0; i < str.length; ++i) {String str2[] = str[i].split("\\["); // 以[分隔str[i] = str2[str2.length - 1];if (isTime(str[i])) {++timeNum;}}for (int i = 0; i < timeNum; ++i) // 處理歌詞復(fù)用的情況{LrcDao sm = new LrcDao();sm.setTime(str[i]);if (timeNum < str.length) // 如果有歌詞{sm.setLyric(str[str.length - 1]);}statements.add(sm);}}} catch (IOException e) {e.printStackTrace();}}private boolean isTime(String string) {String str[] = string.split(":|\\.");//有關(guān)split的具體用法請上百度查if (3 != str.length) {return false;}try {//確保這三段字符串都是時間,for (int i = 0; i < str.length; ++i) {Integer.parseInt(str[i]);}} catch (NumberFormatException e) {return false;}return true;}// 將讀取的歌詞按時間排序 // public void sortLyric() { // for (int i = 0; i < statements.size() - 1; ++i) { // int index = i; // double delta = Double.MAX_VALUE; // boolean moveFlag = false; // for (int j = i + 1; j < statements.size(); ++j) { // double sub; // if (0 >= (sub = statements.get(i).getTime() - statements.get(j).getTime())) { // continue; // } // moveFlag = true; // if (sub < delta) { // delta = sub; // index = j + 1; // } // } // if (moveFlag) { // statements.add(index, statements.elementAt(i)); // statements.remove(i); // --i; // } // } // }public void printLrcDate(){time1 = System.currentTimeMillis();// System.out.println("歌曲名: "+title);// System.out.println("演唱者: "+artist);// System.out.println("專輯名: "+album);// System.out.println("歌詞制作: "+lrcMaker);for (int i = 0; i < statements.size();) {time2 = System.currentTimeMillis();// System.out.println(time1);if (time2 - time1 == statements.elementAt(i).getTime()) {// if(time1 == statements.elementAt(i).getTime()){System.out.println(statements.elementAt(i).getLyric());if (i + 1 < statements.size()) {System.out.println(statements.elementAt(i + 1).getLyric());//System.out.println(time2);}++i;}// System.out.println(statements.elementAt(i).getTime());// elementAt(i)第i個元素}} }不出意外的話,應(yīng)該可以在控制臺上按照時間顯示。如果要邊播放音樂邊顯示歌詞,除了要開線程外,這個時間判斷也要改。因為要每時每刻獲得傳進(jìn)來一個當(dāng)前播放的時間。
? ? ?第一:time1和time2不能都從系統(tǒng)獲得當(dāng)前時間,要獲得音樂已播放的當(dāng)前時間。
? ? ?第二:在歌詞的時間判斷里要把判斷改成時間段,而不是時間點。如:if(X?== 2) 改為:
if(X >=1 && X <3),這樣一個時間段,用于顯示歌詞。
為什么這么改? 因為有時候精度到只有一毫秒差,也是不相等的,就不會顯示歌詞,局限性太強。
?
總結(jié)
以上是生活随笔為你收集整理的音乐播放器的歌词同步实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CompareNoCase 比较两个字符
- 下一篇: audio进度条(改进)