Android 歌詞同步

歌詞同步的原理其實很簡單:

       歌詞顯示是一個線程, 音樂播放時一個線程,通過播放時間將歌詞顯示進度與播放進度同步起來。

       網絡標準的歌詞格式是LRC. 我們看下一個LRC文檔,其格式就一目瞭然了.

[ti:]

[ar:小虎隊]

[al:華納國語情濃13]

[by:愛上你了音樂網]

[02:08.00][00:38.00]把你的心、我的心串一串

[02:11.00][00:41.00]串一株幸運草、串一個同心圓

[02:16.00][00:46.00]讓所有期待未來的呼喚

[02:19.00][00:49.00]趁青春做個伴

[03:16.00][02:24.00][00:53.00]別讓年輕越長大越孤單

[03:19.00][02:27.00][00:56.00]把我的幸運草種在你的夢田

[03:23.00][02:31.00][01:01.00]讓地球隨我們的同心圓

….

LRC 格式爲 [歌詞顯示起始時間][歌詞顯示結束時間]歌詞內容。

      

瞭解歌詞同步原理,我們可以想到要做如下工作:

1.  LRC 解析

2.  LRC 歌詞顯示

3.  歌詞與播放音樂同步

4.  歌詞的獲取

LRC解析

   這邊我推薦YOYOPlayer 音樂播放開源項目. 源代碼已經非常好的支持了LRC解析. 我拿過來就用了.  

       過程大概如此: LRC文件讀到內存裏面,用 sentence數據結構存放. Sentence裏面有 Fromtime, Totime, content三個成員變量。顯示的時候需要這些數據。

. LRC歌詞顯示

    歌詞的繪製通過重寫 OnDraw方法.

繪製的代碼貼出來:

long t = tempTime;

       int index = getNowSentenceIndex(t);

       if (index == -1) {

           return;

       }

       Sentence now = list.get(index);

       float f = (t - now.getFromTime()) * 1.0f

              / (now.getToTime() - now.getFromTime());

       if (f > 0.98f) {

           f = 0.98f;

       }

 

       Shader shader = new LinearGradient(0, 0,

              now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,

                     Color.BLUE }, new float[] { f, f + 0.01f },

              TileMode.CLAMP);

       mTxtPaint.setShader(shader);

canvas.drawText(now.getContent(), 0, 20, mTxtPaint);

   上面的代碼很簡單,關鍵一個函數是getNowSentenceIndex(t). 通過播放時間來獲得歌詞的索引. 我們看下getNowSentenceIndex()如何實現.

    /**

     * 得到當前正在播放的那一句的下標 不可能找不到,因爲最開頭要加一句 自己的句子 ,所以加了以後就不可能找不到了

     *

     * @return 下標

     */

    private int getNowSentenceIndex(long t) {

       for (int i = 0; i < list.size(); i++) {

           if (list.get(i).isInTime(t)) {

              return i;

           }

       }

       // throw new RuntimeException("竟然出現了找不到的情況!");

       return -1;

    }

   還有一個歌詞漸變的效果,其關鍵代碼在與對畫筆的設置,如下.

    Shader shader = new LinearGradient(0, 0,

              now.getContentWidth(mTxtPaint), 0, new int[] { Color.RED,

                     Color.BLUE }, new float[] { f, f + 0.01f },

              TileMode.CLAMP);

    mTxtPaint.setShader(shader);

. 歌詞與播放音樂同步

       音樂播放的時候,同時啓動歌詞顯示線程. 將音樂播放的時間設置到歌詞View的成員變量中, 以達到同步的目的。

       private class MyHandler extends Handler {

       @Override

       public void handleMessage(Message msg) {

// Log.v("#################hahah", "" + mp.getCurrentPosition());

           // 重畫

           lrcView.mLyric.setTime(mp.getCurrentPosition());

           lrcView.invalidate();

       }

    }

. 歌詞的獲取

歌詞的獲取是通過百度搜索出來的. 具體代碼如下,很好看懂,關鍵代碼如下:

        GetMethod get = new GetMethod("http://www.baidu.com/s?wd=" + URLEncoder.encode("filetype:lrc " + key, "GBK"));

        get.addRequestHeader("Host", "www.baidu.com");

        get.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11");

        get.addRequestHeader("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");

        get.addRequestHeader("Accept-Language", "zh-cn,zh;q=0.5");

        get.addRequestHeader("Keep-Alive", "300");

        get.addRequestHeader("Referer", "http://www.baidu.com/");

        get.addRequestHeader("Connection", "keep-alive");

        int i = http.executeMethod(get);

返回的結果是歌詞的xml格式轉化字符串就可以了,這個太簡單了,懶得說了.

 

項目源碼

發佈了79 篇原創文章 · 獲贊 34 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章