Android lyrics Synchronization

Source: Internet
Author: User
Tags gety


Recently I made an android music player. The following describes the implementation of synchronous display of lyrics. Most people recommend yoplayer for reference instances on the Internet. Yoyoplayer is a cross-platform music playing software written in Java. It allows you to play a video, display the lyrics in one, and open source code. If you are interested, You can Google it on your own.

I. parsing LRC lyrics

For more information about the LRC file format, see The general idea is to read the lyrics text by line, ignore the comments in each line, that is, the content after "[:]", and then parse the ID tag (ID-tags ); finally, the time tag and its corresponding lyrics are parsed. The specific implementation is as follows:

1. Ignore comments

Private string removecomment (string line) {matcher M = pattern. compile ("\ [: \]"). matcher (line); string STR = line; while (M. find () {If (M. start () = 0) // all rows are annotated STR = NULL; else STR = line. substring (0, M. start ();} return STR ;}

2. Resolve the tag

private void getLyricIdTags(String line){        Matcher m = Pattern.compile("\\[((ti)|(ar)|(al)|(by)):.+\\]")     .matcher(line);while (m.find()){String type =, 3);if (type.equals("ti")){title =, m.end()-1);}else if (type.equals("ar")){artist =, m.end()-1);}else if (type.equals("al")){album =, m.end()-1);}else if (type.equals("by")){author =, m.end()-1);}}}

3. parse the time tag

Here I use the map structure to store the matching relationship between the start time and the statement of the lyrics. value is the statement of the lyrics, and key value is the start time of the lyrics. A regular expression is used to match time tags. The time tags in the format of [:], [:], and [:.] are supported. The gettimeofline () function converts a time tag to a time value in milliseconds.

private void getLyricTimeTags(String line){Matcher m = Pattern.compile("\\[\\d{1,2}:\\d{1,2}([\\.:]\\d{1,2})?\\]").matcher(line);            List<Integer> time = new ArrayList<Integer>();         int begIndex = 0;        while (m.find())        {        time.add(getTimeOfLine(;        begIndex = m.end();        }        for (int i : time)        {        sortedLyric.put(i, line.substring(begIndex, line.length()));        }    }


2. Branch of the lyrics statement

The single-sentence lyrics in the LRC file may be too long and may not be displayed in a single row in a given area of the android screen. Therefore, you need to split the sentences according to the width of the display area of the screen lyrics. The implementation of searching for Split points is as follows:

private int getDividePoint(String str, int begIndex, int endIndex){//not to divide (letter,letter) or (digit,digit)int original = endIndex; while ( (charType(str.charAt(endIndex)) == LETTER && charType(str.charAt(endIndex-1)) == LETTER) || ( charType(str.charAt(endIndex)) == DIGIT && charType(str.charAt(endIndex-1)) == DIGIT) ){if (endIndex > begIndex)     endIndex--;else {     endIndex = original;     break;}}return endIndex;}

The splitting process is as follows. TP is a textpaint type object in Android. textpaint is used to draw text in the view. It provides the measuretext () function for measuring the text width ():

Int begindex = 0; For (INT I = 0; I <= line. length (); ++ I) {string STR = line. substring (begindex, I); If (TP. measuretext (STR)> width) {int dividepoint = getdividepoint (line, begindex, I-1); lines. add (line. substring (begindex, dividepoint); begindex = dividepoint;} if (I = line. length () /// add the last line of the branch result. add (line. substring (begindex, I ));}

3. synchronous display of lyrics

To display the lyrics on the mobile phone screen synchronously and scroll, You need to customize the view. Here I choose to inherit from textview. It mainly overrides the ondrow () function in textview. The main idea is to first draw the currently playing lyrics, then draw the lyrics above the current lyrics and the lyrics below the current lyrics (the position displayed on the screen ). Based on the playing progress of the song, the lyrics are repeatedly re-painted to Achieve Synchronous scrolling.

Bundle currentLine = lyric.getLineFromTime(currentTime);float offset = calOffsetOfCurrentLine();Bundle bundle = drawCurrentLine(canvas, offset, height, currentLine.getStringArrayList("Lines"));drawAboveLines(canvas, bundle.getFloat("PositionAbove"), lineWidth, lyric.valuesOfHeadMap(currentTime, false));drawBelowLines(canvas, bundle.getFloat("PositionBelow"), lineWidth, height, lyric.valuesOfTailMap(currentTime, false));

The getlinefromtime () function obtains the expected lyrics based on the current playback progress. caloffsetofcurrentline () returns the offset from the initial display position of the current lyrics, because there is a period of time from the highlight to the end of the highlight, the highlight of the lyrics is also rolling, as shown in:

The sentence "The enemy moves, I do not move, you do not move, I do not move, you do not move, I do not move" is highlighted.

The caloffsetofcurrentline () function is:

private float calOffsetOfCurrentLine(){Bundle bundle = lyric.getLineFromTime(currentTime);int numOfLines = bundle.getInt("Number");float fromTime = bundle.getInt("FromTime");float toTime = bundle.getInt("ToTime");float offset = (currentTime - fromTime) * 1.0f/(toTime - fromTime) * (30 * numOfLines);return offset;}


4. Drag the lyrics to control the playback progress

First of all, it should be clear that sliding up or down the lyrics is just an action to control the playing progress of the music. Slide up indicates that the progress is forward. Slide down indicates that the progress is backward. Set a proper Conversion Relationship Between sliding distance and time.

public boolean onTouchEvent(MotionEvent event){ switch (event.getAction()){ case MotionEvent.ACTION_DOWN: isMoving = true; targetTime = currentTime; startY = event.getY(); break; case MotionEvent.ACTION_MOVE: targetTime = moveTo(event.getY()-startY); currentTime = targetTime; postInvalidate(); break; case MotionEvent.ACTION_UP: Intent intent = new Intent(getContext(), MusicPlayService.class); intent.setAction(MyIntentAction.SEEK_TO_FROM_LYRIC); intent.putExtra("SeekTo", currentTime); getContext().startService(intent);  isMoving = false; break;}return true;}

The moveTo here is the conversion between the sliding distance and time I set. There are three steps: recording the start slide point when the finger is pressed; updating the progress of the lyrics continuously during the activity (that is, the slide up and down effect of the lyrics); modifying the playing progress of the song when the finger is released.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.