Lrc歌词解析器0.0.2.0

 1. 类图
Lrc歌词解析器0.0.2.0_第1张图片

2. 源码清单
/**
 * 文件名:LrcAnalyst.java 
 * 环境: GNU/Linux Ubuntu 7.04 + Eclipse 3.2 + JDK 1.6
 * 功能:解析Lrc歌词文件的主驱动程序
 * 版本:0.0.2.0
 * 作者:88250 
 * 日期:2007.4.27 
 * E-mail & MDN: [email protected] 
 * QQ:845765
 
*/

import  javax.swing.JFrame;

/**
 * 测试歌词解析结果
 
*/
public   class  LrcAnalyst
{
    
public  LrcAnalyst()
    {
    JFrame frame 
=   new  JFrame( " Lrc Srcoll " );

        frame.setBounds(
600 300 400 200 );  
        frame.setResizable(
false );
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        LrcScrollPane pane 
=   new  LrcScrollPane();
        frame.getContentPane().add(pane);
        frame.setVisible(
true );
        pane.scroll();
    }
    
    
/**
     * 主程序入口点
     * 
     * 
@param  args
     *                命令行参数,这里没用到,为<code>null</code>
     
*/
    
public   static   void  main(String[] args)
    {
    
new  LrcAnalyst();
    }
}

/**
 * 文件名:LrcAnalystBase.java 
 * 环境: GNU/Linux Ubuntu 7.04 + Eclipse 3.2 + JDK 1.6
 * 功能:解析Lrc歌词文件
 * 版本:0.0.2.0
 * 作者:88250 
 * 日期:2007.4.22 
 * E-mail & MDN: [email protected] 
 * QQ:845765
 
*/

import  java.io. * ;
import  java.util. * ;

/**
 * 歌词解释类,用于对lrc歌词文件的解析
 
*/
public   class  LrcAnalystBase
{
    
/**
     * lrc文件缓冲区
     
*/
    
private   static  Vector lyrics;

    
/**
     * 格式化好的歌词时间与索引,格式参考TimeAndIndex类
     
*/
    
private   static  Vector lrcTimeValAndIndex;
    
/**
     * 返回保存歌词时间与对应歌词的索引容器
     * 
@return  LrcTimeAndIndex 时间标签与歌词索引
     
*/
    
public  Vector getLrcTimeValAndIndex()
    {
    
return  lrcTimeValAndIndex;
    }
    
    
/**
     * 歌词的实际内容
     
*/
    
private   static  Vector lyrcisContent;
    
    
/**
     * 返回歌词实际内容的容器
     * 
@return  歌词实际内容lyrcisContent
     
*/
    
public  Vector getLrcContent()
    {
    
return  lyrcisContent;
    }
    
/**
         * 时间标签的长度,用于区分时间标签的格式
         * 
         * 
@see  private float computeTimeTag(String timeStr)方法
         
*/
    
private   int  timeTagLength;
    
    
/**
     * 真正的歌词内容开始到lrc文本开头的偏移量
     
*/
    
private   int  realLyrcisStartOffset;
    
    
/**
     * 返回真正的歌词内容开始到lrc文本开头的偏移量
     * 
@return  偏移量
     
*/
    
public   int  getRealLrcStartOffset()
    {
    
return  realLyrcisStartOffset;
    }
    
    
/**
     * 是否确定了歌词标签的格式,确定的话是<code>true</code>, 否则是<code>false</code>
     * 
@see  private float computeTimeTag(String timeStr)方法
     
*/
    
private   boolean  isConfirmTimeTagLeng;
    
    
/**
         * 歌词解析器的默认构造器 <br>
         * 初始化歌词文件缓冲等字段
         
*/
    
public  LrcAnalystBase()
    {
    lyrics 
=   new  Vector();
    lrcTimeValAndIndex 
=   new  Vector();
    lyrcisContent 
=   new  Vector();
    timeTagLength 
=   0 ;
    isConfirmTimeTagLeng 
=   false ;
    realLyrcisStartOffset 
=   0 ;
    }

    
/**
         * 按行对去读取文本文件内容
         * 
@param  fileName
         *                文件路径与文件名
         * 
@throws  IOException
         
*/
    
public   void  readFile(String fileName)
    {
    
try
    {
        InputStream r 
=   new  FileInputStream(fileName);
        ByteArrayOutputStream byteout 
=   new  ByteArrayOutputStream();
        
byte  tmp[]  =   new   byte [ 1024 ];
        
byte  context[];
      
        r.read(tmp);
        byteout.write(tmp);
        context 
=  byteout.toByteArray();
        String str 
=   new  String(context,  " GBK " );     //  解决汉字问题
        String lyrcisText[]  =  str.split( " " );
        
        
for  ( int  i  =   0 ; i  <  lyrcisText.length; i ++ )
        {
        lyrics.add(lyrcisText[i]);
        }
    }
    
catch  (IOException e)
    {
        e.printStackTrace();
    }
    }

    
/**
     * 显示读取lrc里的所有内容到控制台
     
*/
    
public   void  displayLrcContent()
    {
    
for  ( int  i  =   0 ; i  <  lyrics.size(); i ++ )
    {
        System.out.println(lyrics.get(i));
    }
    }

    
/**
         * 从文件缓冲lyrics Vector里进行歌词文件内容的解析,并将解析结果保存 <br>
         * 解析方法: <br>
         * Step0. 用']'分割一行内容到String[] <br>
         * Step1. 查看每一行在第3个char是否是':' <br>
         * Step2. 查看每一行在第6个char是否是'.' <br>
         * Step3. 确定为歌词行,确定该lrc用的格式 <br>
         * <b>注意:目前,时间标签的格式有两种,分别是长度为8和5的</b> <br>
         * Step4. 循环直到歌词缓冲结束 <br>
         * <b>注意:这个算法可能存在严重缺陷<b>
         * 
         * 
@see  关于时间标签的格式,参考TimeTag类
         
*/
    
public   void  parseLyrics()
    {
    
for  ( int  i  =   0 ; i  <  lyrics.size(); i ++ )
    {
        String aLineLyrics 
=  (String) lyrics.get(i);
        String[] partsLrc 
=  aLineLyrics.split( " ] " );
        
        
char  flag1  =   0 ;
        
char  flag2  =   0 ;
        
if  ( ! aLineLyrics.isEmpty())
        {
//  很多制作lrc文件的人不负责,乱搞格式!!!!
        flag1  =  aLineLyrics.charAt( 1 );
        flag2 
=  aLineLyrics.charAt( 3 );
        }
        
        
if  ((aLineLyrics.length()  >   3 )
            
&&  (flag1  >=   48   &&  flag1  <=   57 )     //  是否是数字
             &&  ( ' : '   ==  flag2))
        {
//  确定为歌词内容行
         if  ( ! isConfirmTimeTagLeng  &&  aLineLyrics.length()  >   9 )
        {
            
if  (aLineLyrics.charAt( 9 ==   ' ] ' )
            {
//  长度为8的时间标签格式
            timeTagLength  =   8 ;
            }
            
else   if  (aLineLyrics.charAt( 6 ==   ' ] ' )
            {
//  长度为5的时间标签格式
            timeTagLength  =   5 ;
            }
            realLyrcisStartOffset 
=  i;
            isConfirmTimeTagLeng 
=   true ;
        }
        
        
for  ( int  j  =   0 ; j  <  partsLrc.length; j ++ )
        {
            
if  (partsLrc[j].charAt( 0 ==   ' [ ' )
            {
//  确定为时间标签部分,而不是歌词内容部分
            String timeTagStr  =  partsLrc[j].substring( 1 , timeTagLength + 1 );
            
float  timeValue  =  computeTimeTag(timeTagStr);
            
//  添加歌词时间于对应的歌词索引
            lrcTimeValAndIndex.add( new  LrcTimeAndIndex(timeValue, i));
            }
            
else      //  如果歌词开头的内容也是'['将出现FATAL ERROR 
            { //  确定为歌词内容部分
            lyrcisContent.add(partsLrc[j]);
            }
        }
        }
    }
    
//  通过对歌词出现时间的先后顺序进行排序
    sortByTimeTag();
    }
    
    
/**
         * 
@param  timeStr
         *                表示歌词显示时间的String <br>
         *                例如:<br>
         *                "02:03.30"表示2*60s+3.3s=123.3s=1233ms的时刻 <br>
         *                <b>注意:考虑到歌曲长度不会很长,所以算法中直接取前两位作为分钟, <br>
         *                而从':'后的单位是秒。但是因为现在lrc文件格式不是很统一,例如: <br>
         *                "02:03"表示2*60s+3s=123s=1230ms,这是短格式表示,也要考虑到。 <br>
         *                目前,将时间标签分为的两种格式,长度分别为8,5
         * 
@return  计算好的时间值
         
*/
    
private   float  computeTimeTag(String timeStr)
    {
    
int  minutes  =  Integer.parseInt(timeStr.substring( 0 2 ));     //  取得分钟
     float  seconds  =   0 ;
    
    
if  (timeStr.length()  ==   8 )
    {
        seconds 
=  Float.parseFloat(timeStr.substring( 3 8 ));     //  取得秒钟
    }
    
else   if  (timeStr.length()  ==   5 )
    {
        seconds 
=  Float.parseFloat(timeStr.substring( 3 5 )); 
    }

    
return  (minutes  *   60   +  seconds);     //  返回时间值
    }

    
/**
     * 更具歌词显示的先后时间顺序进行排序的标准
     
*/
    
private   void  sortByTimeTag()
    {
    Collections.sort(lrcTimeValAndIndex, 
new  Comparator()
    {
        
//  Parameters:
        
//  o1 - the first object to be compared.
        
//  o2 - the second object to be compared.
        
//  Returns:
        
//  a negative integer, zero, or a positive integer as the first
        
//  argument is less than, equal to, or greater than the second.
        
//  Throws:
        
//  ClassCastException - if the arguments' types prevent them from
        
//  being compared by this Comparator.
         public   int  compare(Object o1, Object o2)
        {
        LrcTimeAndIndex fl1 
=  (LrcTimeAndIndex) o1;
        LrcTimeAndIndex fl2 
=  (LrcTimeAndIndex) o2;

        
if  (fl1.getLrcTime()  -  fl2.getLrcTime()  >   0 )
        {
            
return   1 ;
        }
        
else   if  (fl1.getLrcTime()  -  fl2.getLrcTime()  >   0 )
        {
            
return   - 1 ;
        }
        
else
        {
            
return   0 ;
        }
        }

    });
    }
}

/**
 * 用于保存歌词时间与歌词容器的下标索引
 
*/
class  LrcTimeAndIndex
{
    
/**
     * 该行歌词的显示时间
     * @uml.property   name="lrcTime"
     
*/
    
private   float  lrcTime;

    
/**
     * 该行歌词行索引
     * @uml.property   name="lrcIndex"
     
*/
    
private   int  lrcIndex;

    
/**
     * 默认的构造器
     
*/
    
public  LrcTimeAndIndex()
    {

    }

    
/**
     * 带参数的构造器,设置时间标签和对应的歌词行索引
     * 
@param  lrcTime 时间标签
     * 
@param  lrcIndex 歌词行索引
     
*/
    
public  LrcTimeAndIndex( float  lrcTime,  int  lrcIndex)
    {
    
this .lrcTime  =  lrcTime;
    
this .lrcIndex  =  lrcIndex;
    }

    
/**
     * 返回歌词应该出现的时间
     * 
@return    lrcTime 出现时间
     * @uml.property   name="lrcTime"
     
*/
    
public   float  getLrcTime()
    {
        
return  lrcTime;
    }

    
/**
     * 返回歌词内容行索引
     * 
@return    歌词内容行索引
     * @uml.property   name="lrcIndex"
     
*/
    
public   int  getLrcIndex()
    {
        
return  lrcIndex;
    }
}

/**
 * 文件名:LrcScrollPane.java 
 * 环境: GNU/Linux Ubuntu 7.04 + Eclipse 3.2 + JDK 1.6
 * 功能:滚动的Lrc歌词显示面板
 * 版本:0.0.2.0
 * 作者:88250 
 * 日期:2007.4.28 
 * E-mail & MDN: [email protected] 
 * QQ:845765
 
*/

import  java.awt.Color;
import  java.awt.Font;
import  java.awt.Graphics;
import  java.awt.Point;
import  javax.swing.JPanel;
import  java.util.Date;

public   class  LrcScrollPane  extends  JPanel
{
    
private   final   int  heightOfChar  =   20 ;

    
private   final  Font fontOfChar  =   new  Font( " monospaced " , Font.BOLD,  14 );

    
private  Point scrollPoint;  //  参考点,会慢慢向上移。

    
private  LrcAnalystBase lrcAnalyst;
    
    
private   static   int  lrcIndex  =   0 ;
    
    
public  LrcScrollPane()
    {
    lrcAnalyst 
=   new  LrcAnalystBase();
    lrcAnalyst.readFile(
" 六月的雨.lrc " );
    lrcAnalyst.parseLyrics();
    scrollPoint 
=   new  Point( 5 , getSize().height);
    }

    
/**
     * 实现歌词的滚动显示
     
*/
    
public   void  scroll()
    {
    Date startTime 
=   new  Date();
    
for  ( int  i  =   0 ; i  <  lrcAnalyst.getLrcTimeValAndIndex().size(); i ++ )
    {
        
while  ( true )
        {
        
try
        {
            Thread.currentThread().sleep(
50 );
            
            Date currentTime 
=   new  Date();
            LrcTimeAndIndex fl 
=  (LrcTimeAndIndex) (lrcAnalyst
                .getLrcTimeValAndIndex().get(i));
            
float  diffTime  =  currentTime.getTime()
                
-  startTime.getTime();
            lrcIndex 
=  fl.getLrcIndex() -  lrcAnalyst.getRealLrcStartOffset();
            
if  (fl.getLrcTime()  -  ( float ) diffTime  /   1000   <   0.0 )
            {
            scrollPoint.y
-- ;
            
// System.out.println((String) lrcAnalyst.getLrcContent().get(
            
//     fl.getLrcIndex()- lrcAnalyst.getRealLrcStartOffset()));
            repaint();
            
            
break ;
            }
        }
        
catch  (Exception e)
        {
            e.printStackTrace();
        }
        }
    }
    }
    
    
public   void  paintComponent(Graphics brush)
    {
    
//  用背景色覆盖,原来的文字就看不到了。再写上新的文字,由于视觉停留,
    
//  看起来文字就会滚动
    brush.setColor(getBackground());
    brush.fillRect(
0 0 , getSize().width, getSize().height);

    brush.setColor(Color.blue);
    brush.setFont(fontOfChar);

    
//  i为下标,用来历遍歌词缓存容器,
    
//  当scrollPoint.y+(heightOfChar*i)<0 时,会把文字写到面板上方,看不见。
    
//  没有必要显示。
    
//  scrollPoint.y+(heightOfChar*i)=0 => i=(-scrollPoint.y/heightOfChar)
    
//  故要使(-scrollPoint.y/heightOfChar)和 0 作比较,要是小于0,i取0
     /* int i = 0;
    if ((-scrollPoint.y / heightOfChar) > 0)
    {
        i = (-scrollPoint.y / heightOfChar);
    }
*/
    
    
/* String lyrics = null;
    for (; i < lrcAnalyst.getLrcContent().size(); i++)
    {
        // 当条件成立,文字会写到面板下方,也没有必要显示,跳出循环
        if (scrollPoint.y + (heightOfChar * i) > getSize().height)
        {
        break;
        }
        lyrics = (String) (lrcAnalyst.getLrcContent().get(i));
        // 见scroll(),靠scrollPoint.y的上移,使文字上移
        brush.drawString(lyrics, scrollPoint.x, scrollPoint.y
             + (heightOfChar * i));
    }    
*/
    
    String lyrics 
=  (String) lrcAnalyst.getLrcContent().get(lrcIndex);
        
//  见scroll(),靠scrollPoint.y的上移,使文字上移
        brush.drawString(lyrics, scrollPoint.x,  - scrollPoint.y  +   20 );
    }
}

3. 工程文件
    LrcAnalyst0.0.2.0 by eclipse 3.2.0

你可能感兴趣的:(eclipse,String,vector,import,float,scroll)