1. [图片] 2012-08-21-13-07-10.png
![](http://static.oschina.net/uploads/code/201208/21132445_ddu9.png)
2. [代码][Java]代码 跳至[2][3][4][全屏预览]
001 | package my.android.karaoke.media; |
002 |
003 | import java.io.FileDescriptor; |
004 | import java.io.FileInputStream; |
005 | import java.io.IOException; |
006 | import java.io.InputStream; |
007 | import java.util.ArrayList; |
008 | import java.util.List; |
009 |
010 | import my.android.karaoke.bean.LyricSentence; |
011 | import my.android.karaoke.bean.LyricText; |
012 | import my.android.karaoke.bean.LyricWord; |
013 |
014 | import android.content.Context; |
015 | import android.content.res.AssetFileDescriptor; |
016 | import android.content.res.AssetManager; |
017 | import android.media.MediaPlayer; |
018 | import android.os.Handler; |
019 | import android.os.Message; |
020 | import android.util.Log; |
021 |
022 |
023 | public class KaraokeMedia { |
024 |
025 | private static KaraokeMedia karaokeMedia= new KaraokeMedia(); |
026 | |
027 | //文章每个段落的起始和结束时间段 |
028 | private static List<Integer> sentencesTimes= null ; |
029 | private static MediaPlayer mp3Player = new MediaPlayer(); |
030 | |
031 | private static int currentSentence_index ; //当前段落索引 |
032 | private static int currentWord_index; //当前段落单个字的字数索引 |
033 | private static int showWord_index; //当前段落单个字的显示字数索引 |
034 | |
035 | private static List<LyricSentence> sentences; |
036 | |
037 | private KaraokeMedia(){} |
038 | |
039 | public static KaraokeMedia getInstance() { |
040 | return karaokeMedia; |
041 | } |
042 | |
043 | //开始播放文章 |
044 | public static void playArticleMedia(LyricText lyricText,Context context) { |
045 | |
046 | karaokeMedia.prepareSentencesTimes(lyricText); |
047 | |
048 | currentSentence_index= 0 ; |
049 | currentWord_index= 0 ; |
050 | |
051 | mMode = RUNNING; |
052 | karaokeMedia.update(); |
053 | |
054 | AssetManager asset = context.getAssets(); |
055 | FileDescriptor fd = null ; |
056 | try { |
057 | fd = asset.openFd(lyricText.getSound_path()).getFileDescriptor(); |
058 | } catch (IOException e1) { |
059 | // TODO Auto-generated catch block |
060 | e1.printStackTrace(); |
061 | } |
062 | |
063 | if (fd == null ){ |
064 | return ; |
065 | } |
066 | |
067 | try { |
068 | //mp3Player.setDataSource(article.getSound_path()); |
069 | mp3Player.setDataSource(fd); |
070 | mp3Player.prepare(); |
071 | } catch (IllegalArgumentException e) { |
072 | // TODO Auto-generated catch block |
073 | e.printStackTrace(); |
074 | } catch (SecurityException e) { |
075 | // TODO Auto-generated catch block |
076 | e.printStackTrace(); |
077 | } catch (IllegalStateException e) { |
078 | // TODO Auto-generated catch block |
079 | e.printStackTrace(); |
080 | } catch (IOException e) { |
081 | // TODO Auto-generated catch block |
082 | e.printStackTrace(); |
083 | } |
084 |
085 | mp3Player.start(); |
086 | |
087 | //Log.v("KaraokeMedia playArticleMedia() Duration:", ""+mp3Player.getDuration()); |
088 | } |
089 | |
090 | //开始播放某个文章段落 |
091 | public static void seekToArticleMedia( int seekTotSentence_index) { |
092 | |
093 | currentSentence_index=seekTotSentence_index; |
094 | mMode = PAUSE; |
095 | |
096 | int seekToTime = sentencesTimes.get(currentSentence_index); |
097 | |
098 | if (mp3Player.isPlaying()){ |
099 | |
100 | mp3Player.seekTo(seekToTime); |
101 | |
102 | } else { |
103 |
104 | mp3Player.start(); |
105 | mp3Player.seekTo(seekToTime); |
106 | } |
107 | |
108 | mMode = RUNNING; |
109 | karaokeMedia.update(); |
110 | } |
111 | |
112 | //暂停播放文章,如果暂停成功则返回true |
113 | public static boolean pauseArticleMedia() { |
114 | |
115 | if (mp3Player.isPlaying()){ |
116 | mp3Player.pause(); |
117 | mMode = PAUSE; |
118 | |
119 | return true ; |
120 | } else { |
121 | return false ; |
122 | } |
123 | } |
124 | |
125 | //恢复播放文章,如果恢复成功则返回true |
126 | public static boolean reStartoArticleMedia() { |
127 | |
128 | if (!mp3Player.isPlaying()){ |
129 | mp3Player.start(); |
130 | mMode = RUNNING; |
131 | karaokeMedia.update(); |
132 | |
133 | return true ; |
134 | } else { |
135 | return false ; |
136 | } |
137 | } |
138 | |
139 | //初始化文章音频LRC时间段 |
140 | private void prepareSentencesTimes(LyricText lyricText){ |
141 | |
142 | sentences = lyricText.getSentences(); |
143 | int Sentences_size = sentences.size(); |
144 | |
145 | if (sentencesTimes!= null ){ |
146 | sentencesTimes.clear(); |
147 | } |
148 | |
149 | sentencesTimes = new ArrayList<Integer>(Sentences_size); |
150 | for (LyricSentence sentence : sentences){ |
151 | |
152 | Integer time = sentence.getSentence_offset(); |
153 | sentencesTimes.add(time); |
154 | } |
155 | } |
156 | |
157 | private static int mMediaDelay = 10 ; |
158 | |
159 | private static int mMode; |
160 | public static final int PAUSE = 0 ; |
161 | public static final int READY = 1 ; |
162 | public static final int RUNNING = 2 ; |
163 | public static final int STOP = 3 ; |
164 | |
165 | //定时器,每mMediaDelay时间循环一次,判断当前音频是否更换段落 |
166 | //update在RUNNING状态的更新间隔为此方法执行时间+mMediaDelay,因为经过测试,该方式执行时间大概为100MS,所以间隔时间为100MS左右+mMediaDelay |
167 | //有一定误差 |
168 | private void update() { |
169 | if (mMode == RUNNING) { |
170 | |
171 | int now = mp3Player.getCurrentPosition(); |
172 |
173 | //Log.v("ArticleMedia update() now:", ""+now); |
174 | |
175 | if (currentSentence_index < (sentencesTimes.size())) { |
176 | |
177 | //判断歌词段落的移动 |
178 | if (now >= sentencesTimes.get(currentSentence_index)) { |
179 | |
180 | // Log.v("ArticleMedia update():", ""+currentSentence_index); |
181 | mOnSentenceChangeListener.OnSentenceChange(currentSentence_index); |
182 | currentSentence_index++; |
183 | currentWord_index= 0 ; |
184 | showWord_index= 0 ; |
185 | } |
186 | } |
187 | |
188 | if (currentSentence_index <= (sentencesTimes.size())) { |
189 | //判断歌词单个字的移动 |
190 | int sentenceIndex4word = currentSentence_index- 1 ; |
191 | LyricSentence currentSentence = sentences.get(sentenceIndex4word); |
192 | List<LyricWord> words = currentSentence.getWords(); |
193 | |
194 | if (currentWord_index < words.size()) { |
195 | |
196 | LyricWord word = words.get(currentWord_index); |
197 | if (now >= word.getWord_offset()) { |
198 | |
199 | // Log.v("KaraokeMedia update():", ""+currentWord_index+"/"+words.size()); |
200 | |
201 | showWord_index = showWord_index + word.getWord().length(); |
202 | |
203 | mOnSentenceChangeListener.OnWordChange(showWord_index); |
204 | currentWord_index++; |
205 | } |
206 | } |
207 | } |
208 | |
209 | mRedrawHandler.sleep(mMediaDelay); |
210 | } |
211 |
212 | } |
213 | |
214 | private RefreshHandler mRedrawHandler = new RefreshHandler(); |
215 |
216 | class RefreshHandler extends Handler { |
217 |
218 | @Override |
219 | public void handleMessage(Message msg) { |
220 | karaokeMedia.update(); |
221 | } |
222 |
223 | public void sleep( long delayMillis) { |
224 | this .removeMessages( 0 ); |
225 | sendMessageDelayed(obtainMessage( 0 ), delayMillis); |
226 | } |
227 | }; |
228 | |
229 | public void SetOnSentenceChangeListener( |
230 | OnSentenceChangeListener l) { |
231 | mOnSentenceChangeListener = l; |
232 | } |
233 | |
234 | OnSentenceChangeListener mOnSentenceChangeListener = null ; |
235 | |
236 | public interface OnSentenceChangeListener { |
237 | void OnSentenceChange( int currentSentence_index); |
238 | void OnWordChange( int showWord_index); |
239 | } |
240 | |
241 | //停止播放文章 |
242 | public static void stopArticleMedia() { |
243 | |
244 | mMode=STOP; |
245 | |
246 | if (mp3Player!= null ) { |
247 | mp3Player.stop(); |
248 | mp3Player.release(); |
249 | mp3Player= null ; |
250 | } |
251 | } |
252 | } |
3. [代码][Java]代码 跳至[2][3][4][全屏预览]
001 | package my.android.karaoke.parse; |
002 |
003 | import java.io.BufferedReader; |
004 | import java.io.FileInputStream; |
005 | import java.io.FileNotFoundException; |
006 | import java.io.IOException; |
007 | import java.io.InputStream; |
008 | import java.io.InputStreamReader; |
009 | import java.io.StringReader; |
010 |
011 | import org.xmlpull.v1.XmlPullParser; |
012 | import org.xmlpull.v1.XmlPullParserException; |
013 | import org.xmlpull.v1.XmlPullParserFactory; |
014 |
015 | import android.content.Context; |
016 | import android.content.res.AssetManager; |
017 | import android.util.Log; |
018 |
019 | public class XmlPullFactory { |
020 | |
021 | private final static String CODING_TYPE= "utf-8" ; |
022 |
023 | public static XmlPullParser CreateXppFromAssets(String xmlPath,Context context) throws IOException { |
024 | AssetManager asset = context.getAssets(); |
025 | //return asset.openXmlResourceParser(xmlPath); |
026 | InputStream inputStream = null ; |
027 | |
028 | try { |
029 | |
030 | inputStream = asset.open(xmlPath); |
031 | |
032 | } catch (IOException e) { |
033 | |
034 | Log.e ( "tag" , e.getMessage()); |
035 | |
036 | } |
037 |
038 | XmlPullParser xpp = null ; |
039 |
040 | try { |
041 | XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); |
042 | |
043 | factory.setNamespaceAware( true ); |
044 | xpp = factory.newPullParser(); |
045 |
046 | } catch (XmlPullParserException e1) { |
047 | e1.printStackTrace(); |
048 | } |
049 | |
050 | String xmltext = "" ; |
051 | |
052 | try { |
053 | InputStreamReader inStreamReader = new InputStreamReader(inputStream,CODING_TYPE); |
054 | BufferedReader br = new BufferedReader(inStreamReader); |
055 | |
056 | String data = null ; |
057 | |
058 | while ((data = br.readLine())!= null ) |
059 | { |
060 | xmltext = xmltext + data; |
061 | } |
062 | |
063 | inStreamReader.close(); |
064 | inputStream.close(); |
065 | br.close(); |
066 |
067 | StringReader strReader = new StringReader(xmltext); |
068 | xpp.setInput(strReader); |
069 | |
070 | // strReader.close(); |
071 | } catch (FileNotFoundException e) { |
072 | e.printStackTrace(); |
073 | } catch (XmlPullParserException e) { |
074 | e.printStackTrace(); |
075 | } catch (IOException e) { |
076 | e.printStackTrace(); |
077 | } |
078 | |
079 | return xpp; |
080 | |
081 | } |
082 | |
083 | public static XmlPullParser CreateXppFromXml(String xmlPath) { |
084 | |
085 | XmlPullParser xpp = null ; |
086 |
087 | try { |
088 | XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); |
089 | |
090 | factory.setNamespaceAware( true ); |
091 | xpp = factory.newPullParser(); |
092 |
093 | } catch (XmlPullParserException e1) { |
094 | e1.printStackTrace(); |
095 | } |
096 | |
097 | String xmltext = "" ; |
098 | |
099 | try { |
100 | FileInputStream fileInStream = new FileInputStream(xmlPath); |
101 | InputStreamReader inStreamReader = new InputStreamReader(fileInStream,CODING_TYPE); |
102 | BufferedReader br = new BufferedReader(inStreamReader); |
103 | |
104 | String data = null ; |
105 | |
106 | while ((data = br.readLine())!= null ) |
107 | { |
108 | xmltext = xmltext + data; |
109 | } |
110 | |
111 | inStreamReader.close(); |
112 | fileInStream.close(); |
113 | br.close(); |
114 |
115 | StringReader strReader = new StringReader(xmltext); |
116 | xpp.setInput(strReader); |
117 | |
118 | // strReader.close(); |
119 | } catch (FileNotFoundException e) { |
120 | e.printStackTrace(); |
121 | } catch (XmlPullParserException e) { |
122 | e.printStackTrace(); |
123 | } catch (IOException e) { |
124 | e.printStackTrace(); |
125 | } |
126 | |
127 | return xpp; |
128 | } |
129 | |
130 | public static String getAttrValueByName(String name, XmlPullParser xpp){ |
131 | String valueStr = "" ; |
132 | |
133 | int attrCount = xpp.getAttributeCount(); |
134 | for ( int i= 0 ; i<attrCount ; i++) { |
135 | if (name.equals(xpp.getAttributeName(i))){ |
136 | valueStr = xpp.getAttributeValue(i); |
137 | break ; |
138 | } |
139 | } |
140 | |
141 | return valueStr; |
142 | } |
143 | } |
4. [代码][Java]代码 跳至[2][3][4][全屏预览]
001 | package my.android.karaoke.parse; |
002 |
003 | import java.io.IOException; |
004 | import java.util.ArrayList; |
005 | import java.util.List; |
006 |
007 | import org.xmlpull.v1.XmlPullParser; |
008 | import org.xmlpull.v1.XmlPullParserException; |
009 |
010 | import my.android.karaoke.bean.LyricSentence; |
011 | import my.android.karaoke.bean.LyricText; |
012 | import my.android.karaoke.bean.LyricWord; |
013 | import android.content.Context; |
014 | import android.util.Log; |
015 | import android.widget.Toast; |
016 |
017 | public class LyricParse { |
018 | |
019 | /**加载的歌词内容**/ |
020 | public static LyricText getLyricTextNew(String lyricpath,Context context) { |
021 | LyricText lyricText = null ; |
022 | try { |
023 | String lyricContent = getLyricContent(lyricpath,context); //获取歌词lyric内容字符串 |
024 | Log.v( "lrcText" ,lyricContent ); |
025 | if ( lyricContent != null && lyricContent != "" ) |
026 | { |
027 | lyricText = new LyricText(); |
028 | lyricText = getLyricTextFromString(context,lyricContent); |
029 | String soundPath = lyricpath.replace( ".xml" , ".mp3" ); //lrc必须要小写 |
030 | lyricText.setSound_path(soundPath); |
031 | } |
032 | //smartText_map.put(textpath, smartText); |
033 | |
034 | } catch (Exception e) { |
035 | e.printStackTrace(); |
036 | //Toast.makeText(context, "无法解析文件:" + textpath, Toast.LENGTH_LONG).show(); |
037 | return null ; |
038 | } |
039 | //} |
040 | return lyricText; |
041 | } |
042 | |
043 | public static String getLyricContent(String lyricpath,Context context) throws XmlPullParserException, IOException{ |
044 | |
045 | String lyricContent= "" ; |
046 | |
047 | XmlPullParser xpp = XmlPullFactory.CreateXppFromAssets(lyricpath,context); |
048 | //XmlPullParser xpp = XmlPullFactory.CreateXppFromXml(lyricpath); |
049 | int eventType = xpp.getEventType(); |
050 | |
051 | while (eventType != XmlPullParser.END_DOCUMENT) { |
052 | if (eventType == XmlPullParser.START_TAG) { |
053 | String tagName = xpp.getName(); |
054 | if ( "Lyric_1" .equals(tagName)) { |
055 | lyricContent = XmlPullFactory.getAttrValueByName( "LyricContent" ,xpp); |
056 | } |
057 | } |
058 | eventType = xpp.next(); |
059 | } |
060 | return lyricContent; |
061 | } |
062 | |
063 | /**从解密后得到的string解析lrc(直接从内存中解析,不必再写临时文件)*/ |
064 | public static LyricText getLyricTextFromString(Context context,String lrcText) { |
065 | |
066 | LyricText lyricText = new LyricText(); |
067 | |
068 | try { |
069 | |
070 | String[] lrcList = lrcText.split( "\\[" ); //将字符串按 [ 拆分为数组 |
071 | List<LyricSentence> sentences = new ArrayList<LyricSentence>(); //歌词段落时间点标签 |
072 | int count = lrcList.length; |
073 | int sentence_id= 0 ; |
074 | |
075 | for ( int i = 0 ; i < count; i ++) { |
076 | |
077 | if (lrcList[i].trim() != "" ){ |
078 | |
079 | String[] lrc_str = lrcList[i].split( "\\]" ); |
080 | |
081 | //判断是否为歌词部分还是信息部分 |
082 | if (lrc_str.length< 2 ){ |
083 | |
084 | String[] lrc_info = lrc_str[ 0 ].split( ":" ); |
085 | |
086 | if ( "ti" .equals(lrc_info[ 0 ])) { |
087 | lyricText.setLyric_ti(lrc_info[ 1 ]); |
088 | continue ; |
089 | } |
090 | |
091 | if ( "ar" .equals(lrc_info[ 0 ])) { |
092 | lyricText.setLyric_ar(lrc_info[ 1 ]); |
093 | continue ; |
094 | } |
095 | |
096 | if ( "al" .equals(lrc_info[ 0 ])) { |
097 | lyricText.setLyric_al(lrc_info[ 1 ]); |
098 | continue ; |
099 | } |
100 | |
101 | if ( "by" .equals(lrc_info[ 0 ])) { |
102 | lyricText.setLyric_by(lrc_info[ 1 ]); |
103 | continue ; |
104 | } |
105 | |
106 | if ( "offset" .equals(lrc_info[ 0 ])) { |
107 | lyricText.setLyric_offset(lrc_info[ 1 ]); |
108 | continue ; |
109 | } |
110 | |
111 | } else { |
112 | |
113 | LyricSentence sentence = new LyricSentence(); |
114 | sentence.setSentence_id(sentence_id); |
115 | sentence_id++; |
116 | |
117 | String[] lrc_time = lrc_str[ 0 ].split( "," ); |
118 | int sentence_offset = Integer.parseInt(lrc_time[ 0 ]); |
119 | sentence.setSentence_offset(sentence_offset); |
120 | |
121 | int sentence_duration = Integer.parseInt(lrc_time[ 1 ]); |
122 | sentence.setSentence_duration(sentence_duration); |
123 |
124 | parseLyricWord(sentence,lrc_str[ 1 ]); |
125 | |
126 | sentences.add(sentence); |
127 | } |
128 | } |
129 | } |
130 | lyricText.setSentences(sentences); |
131 | Log.v( "sentences.size()" , "" +sentences.size()); |
132 | } |
133 | catch (Exception e) { |
134 | Toast.makeText(context, "处理解析歌词部分出错" , Toast.LENGTH_LONG).show(); |
135 | return null ; |
136 | } |
137 | return lyricText; |
138 | } |
139 | |
140 | public static void parseLyricWord(LyricSentence sentence,String original_sentence){ |
141 | |
142 | List<LyricWord> words = new ArrayList<LyricWord>(); |
143 | String sentence_str= "" ; |
144 | |
145 | String[] words_str = original_sentence.split( "\\)" ); |
146 | int count = words_str.length; |
147 | |
148 | for ( int i = 0 ; i < count; i ++) { |
149 | |
150 | if (words_str[i].trim() != "" ){ |
151 | String[] word_str = words_str[i].split( "\\(" ); |
152 | LyricWord word = new LyricWord(); |
153 | |
154 | word.setWord(word_str[ 0 ]); |
155 | sentence_str = sentence_str+word_str[ 0 ]; |
156 | |
157 | String[] word_time = word_str[ 1 ].split( "," ); |
158 | int word_offset = Integer.parseInt(word_time[ 0 ]); |
159 | word.setWord_offset(word_offset); |
160 | |
161 | int word_duration = Integer.parseInt(word_time[ 1 ]); |
162 | word.setWord_duration(word_duration); |
163 | |
164 | words.add(word); |
165 | } |
166 | } |
167 | |
168 | sentence.setSentence(sentence_str); |
169 | sentence.setWords(words); |
170 | } |