捐赠 | 广告 | 注册 | 发布 | 上传 | 关于我们    
  沪ICP备05001939号 DELPHI盒子 | 盒子论坛 | 盒子文章 | 盒子问答悬赏 | 最新更新 | 论坛检索 | 下载中心 | 高级搜索    
  精品专区 | 繁體中文 | 奖励公告栏 | 直通车账号登陆 | 关闭GOOGLE广告 | 临时留言    
盒子资源分类
全部展开 - 全部合拢
LRC歌词文件解析单元
关键字:Lyric LRC歌词 幸运播放
来 自:原创
平 台:Win9x,Win2k/XP/NT,Win2003 下载所需:0 火柴
深浅度:初级 完成时间:2005/10/21
发布者:luckywangxw 发布时间:2005/10/21
编辑器:DELPHI7 语  种:简体中文
分 类:媒体与图形 下载浏览:0/12073
加入到我的收藏
下载错误报错
登陆以后才能下载
 用户名:
 密 码:
自动登陆(30天有效)
无图片
//////////
//
//   《幸运播放》 LRC歌词文件解析单元
//
//原文件名:lyric.pas
//作者:《幸运播放》作者luckywangxw
//QQ:375771206   
//Web:http://luckyplayer.go3.icpcn.com
//说明:该文件可以自由传播,但请注明出处
//
//////////
unit lyric;

interface
  uses Classes,SysUtils;

type
  TOneLyric=Record
    time:longint;
    lyStr:string;
  end;

  TLyric=class
  private
    FFilename:string;
    FOffset:integer; //时间补偿值 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
    FAur:string; //艺人名
    FBy:string; //编者(指编辑LRC歌词的人)
    FAl:string; //专辑名
    FTi:string; //曲名
    FCount:integer;

    FLyricArray : array of TOneLyric;
    function GetLyric(i:integer): TOneLyric ;
    function ExistTime(vTime:longint):boolean;

    procedure sortLyric;
    procedure ResetLyrics(FTxt:Tstrings);
  protected
  public
    constructor Create;
    destructor Destroy; override;
    procedure loadLyric(afilename:string);
    procedure SetTxt(aLyrics:Tstrings);
    procedure UnloadLyric(strs:Tstrings);

    //整体提前(正值)或整体延后(负值)atime毫秒
    function ChgOffset(atime:integer):boolean;

    //提前(正值)/延后(负值)某一句歌词 aTime毫秒
    function ChgOneLyric(oldTime:longint;aTime:integer):boolean;

    //保存歌词内容到文件
    function SaveLyricsToFile(vFileName:string):boolean;

    property filename:string read ffilename;
    property Ar:string read FAur;
    property By:string read FBy;
    property Al:string read FAl;
    property Ti:string read FTi;
    property Offset :integer read FOffset;

    property LyricArray[i:integer]: TOneLyric read GetLyric ;

    property Count:integer read FCount;
  end;

implementation

uses  main,pubUnit;

constructor TLyric.Create;
begin
  inherited Create;
  FTi:=';
  FAur:=';
  Fal:=';
  FBy:=';
  FOffset:=0;
end;

function TLyric.ExistTime(vTime:longint):boolean;
var i:integer;
begin
  result:=false;
  for i:=0 to length(FLyricArray) -1 do
    if  FLyricArray[i].time =vTime then
    begin
        result:=true;
        break;
    end;
end;

procedure TLyric.loadLyric(afilename:string);
var
  FTxt:Tstrings;
begin
  FTi:=';
  FAur:=';
  Fal:=';
  FBy:=';
  FOffset:=0;

  FFilename:=afilename;
  //载入歌词

  FTxt:=TStringlist.create;
  FTxt.LoadFromFile(Ffilename);

  ResetLyrics(FTxt);

  FTxt.Clear;
  FTxt.free;
end;

procedure TLyric.SetTxt(aLyrics:Tstrings);
begin
  FTi:=';
  FAur:=';
  Fal:=';
  FBy:=';
  FOffset:=0;

  //载入歌词
  ResetLyrics(aLyrics);
end;

//根据歌词文件  载入每行歌词
procedure TLyric.ResetLyrics(FTxt:Tstrings);
var i:integer;
  function makeOneLyric(CurLyric:string):string;
  var p1,p2,p3:integer;
     timestr,lyricstr:string;
     time1,time2:longint;

     isFuSign:boolean;
  begin
    p1:=pos('[',CurLyric);//第一个‘[’位置
    if p1=0 then begin   //判断是否非法行
      result:= CurLyric;          //无 '['
      exit;
    end;
    p2:=pos(']',CurLyric); //第一个‘]’位置
    if p2=0 then begin
      result:= CurLyric;
      exit;          //无 ']'
    end;

    timestr:=copy(curLyric,p1+1,p2-p1-1);
    //左右两边为歌词
    lyricStr:= copy(curLyric,1,p1-1) + copy(curLyric,p2+1,length(curLyric)-p2) ;

    lyricStr:=makeOneLyric(lyricStr);

    if copy(Lowercase(timeStr),1,2)='ar' then  //作者信息
       FAur:= copy(timestr,4,length(timestr)-3)
    else if copy(Lowercase(timeStr),1,2)='ti' then  //曲目标题
       FTi:= copy(timestr,4,length(timestr)-3)
    else if copy(Lowercase(timeStr),1,2)='al' then  //专辑名
       FAl:= copy(timestr,4,length(timestr)-3)
    else if copy(Lowercase(timeStr),1,2)='by' then  //编辑LRC歌词的人
       FBy:= copy(timestr,4,length(timestr)-3)
    else if copy(Lowercase(timeStr),1,6)='offset' then  //时间补偿值
      try
        FOffset:= strtoint(copy(timestr,8,length(timestr)-7))
      except
        FOffset:=0;
      end
    else   //此时为 时间标记
    begin
       p3:= pos(':',timestr) ;
       if p3>0 then begin //判断是否非法行
          isFuSign:=false;
         try
          time1:=strtoint(copy(timestr,1,p3-1))*1000;
          if time1<0 then
          isFuSign:=true;  //记录 该 时间标签 为 负(小于零)
         except
          //非法歌词行
          exit;          //分钟有误
         end;

         try
          time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
          if isFuSign then
          time2:=-time2;
         except
          exit;          //秒 有误
         end;

         if not ExistTime(time1*60+time2) then
         begin
          setLength(FLyricArray,length(FLyricArray)+1);
          //if trim(lyricStr)=' then
          //  lyricStr:= '(Music)';
          with FLyricArray[length(FLyricArray)-1] do
          begin
          time :=time1*60+time2;
          lystr:=lyricStr;
          end;
          result:=lyricStr;
         end;
       end;
    end;

  end;
begin
  SetLength(FLyricArray,0);

  //解析歌词各部分
  for i:= 0 to FTxt.count-1 do
  begin
      makeOneLyric(FTxt[i]) ;
  end;

  FCount:=length(FLyricArray) ;
  sortLyric;

  {if FTi<>' then FTi:= replaceWithchr(FTi,'&','&&');
  if FAur<>' then FAur:= replaceWithchr(FAur,'&','&&');
  if FAl<>' then FAl:= replaceWithchr(FAl,'&','&&');
  if FBy<>' then FBy:= replaceWithchr(FBy,'&','&&');
  }
  //根据 整体时间偏移,重新计算每句歌词时间
    for i:=0 to length(FLyricArray)-1 do
    begin
       //FLyricArray[i].lyStr := replaceWithchr(FLyricArray[i].lyStr,'&','&&');

       if FLyricArray[i].time >= 0 then
         begin
          if FLyricArray[i].time - FOffset>=0 then
          FLyricArray[i].time:=FLyricArray[i].time - FOffset ;

         end
       else
         FLyricArray[i].time:=0;
    end;
end;

procedure TLyric.UnloadLyric(strs:Tstrings);
var i:integer;
begin
   SetLength(FLyricArray,strs.Count );
   FCount:= strs.Count;
   for i:=0 to strs.Count -1 do
   begin
      FLyricArray[i].time :=0;
      FLyricArray[i].lyStr := strs[i];
   end;

   FTi:=';
   FAur:=';
   Fal:=';
   FBy:=';
   FOffset:=0;

end;

destructor TLyric.Destroy;
begin
  SetLength(FLyricArray,0);

  inherited Destroy;
end;

function TLyric.GetLyric(i:integer): TOneLyric ;
begin
  if (i>=0) and (i<length(FLyricArray)) then
    result:=FLyricArray[i] ;
end;

procedure TLyric.sortLyric;
var i,j:integer;
  tmpLyric:TOneLyric;
begin
   for i:=0 to length(FLyricArray)-2 do
   begin
     for j:=i to length(FLyricArray)-1 do
     begin
        if FLyricArray[j].time < FLyricArray[i].time then
        begin
          tmpLyric:= FLyricArray[i];
          FLyricArray[i]:= FLyricArray[j];
          FLyricArray[j]:= tmpLyric;
        end;
     end;
   end;
end;

function TLyric.ChgOffset(atime:integer):boolean;//提前(正值)或延后(负值)atime毫秒
var i,numberLine:integer;
  p1,p2,p3:integer;
     timestr,lyricstr,CurLyric,signStr:string;
     aOffset:longint;
     afind:boolean;
  FTxt:Tstrings;
begin
   Result:=false;

  //修改offset 保存文件
    afind:=false;
    aOffset:=0;
    numberLine:=-1;

    FTxt:=TStringlist.create;
 try
    FTxt.LoadFromFile(FFilename);

     for i:=0 to FTxt.Count-1 do
     begin
        curLyric:=fTxt[i];

          p1:=pos('[',CurLyric);//第一个‘[’位置
          if p1=0 then begin   //判断是否非法行
          continue;          //无 '['
          end;
          p2:=pos(']',CurLyric); //第一个‘]’位置
          if p2=0 then begin
          continue;          //无 ']'
          end;

          timestr:=copy(curLyric,p1+1,p2-p1-1);
          //左右两边为歌词
          lyricStr:= copy(curLyric,1,p1-1) + copy(curLyric,p2+1,length(curLyric)-p2) ;

          if copy(Lowercase(timeStr),1,6)='offset' then  //找到 时间补偿串
          begin
          try
          aOffset:= strtoint(copy(timestr,8,length(timestr)-7));
          except
          continue;
          end ;
          fTxt[i]:=copy(curLyric,1,p1-1)
          +'[offset:'+inttostr(aOffset+aTime) +']'
          +copy(curLyric,p2+1,length(curLyric)-p2);

          if  aOffset+aTime=0 then
          FTxt.Delete(i);

          fTxt.SaveToFile(FFilename);
          afind:=true;
          break;
          end
          else
          begin
          if numberLine=-1 then
          begin
          signStr:=copy(Lowercase(timeStr),1,2) ;
          if (signStr<>'ar') and (signStr<>'al') and (signStr<>'ti') and (signStr<>'by') then begin
          p3:= pos(':',timestr) ;
          if p3>0 then         //为时间标记
          numberLine:=i;        //记录行号
          end;
          end;
          end;
     end;

   if (not afind) and (numberLine<>-1) then
   begin
     //fTxt.Add('[offset:'+inttostr(aOffset+aTime) +']');
     fTxt.Insert(numberline, '[offset:'+inttostr(aOffset+aTime) +']');
     fTxt.SaveToFile(FFilename);
   end;

   //重新载入歌词
   loadLyric(FFilename);

   result:=true;    

   FTxt.Clear;
 finally
   FTxt.free;
 end;
end;

function TLyric.ChgOneLyric(oldTime:longint;aTime:integer):boolean;
var i:integer;
    FTxt:Tstrings;
    AjustOk:boolean;
    thisLyric:string;

   function AjustOneLine(var curLyric:string):boolean;
   var
     isFu:boolean;//该时间是否为负.

     p1,p2,p3:integer;
     timestr,left_lyric,right_lyric:string;    //
     time1,time2:longint;
     findok:boolean;
     isValid:boolean;//
     
     NewTimeLabel:string;
     NewTime:longint;

     UseMS:boolean;
   begin
        //---------该串内 是否有标签 ----------
        p1:=pos('[',CurLyric);//第一个‘[’位置
        if p1=0 then begin   //判断是否非法行
          Result:=false;          //无 '['
          exit;
        end;
        p2:=pos(']',CurLyric); //第一个‘]’位置
        if p2=0 then begin
          result:= false;
          exit;          //无 ']'
        end;
        //==========串内 是否有标签==========

        //----------目前标签 是否是 指定时间的 标签----------
        timestr:=copy(curLyric,p1+1,p2-p1-1);

        Left_lyric:= copy(curLyric,1,p1-1);
        Right_lyric:= copy(curLyric,p2+1,length(curLyric)-p2)  ;

        isValid:=true;
        findok:=false;
        p3:= pos(':',timestr) ;
        if p3>0 then begin //判断是否 合法时间标签
          isFu:=false;
          try
          time1:=strtoint(copy(timestr,1,p3-1))*1000;
          if time1<0 then
          isFu:=true;
          except
          //非法歌词行
          isValid:=false;          //分钟有误
          end;

          try
          if isValid then
          begin
          time2:= trunc( strtofloat(copy(timestr,p3+1,length(timestr)-p3)) *1000);
          if isFu then
          time2:=-time2;
          end;
          except
          isValid:=false;          //秒 有误
          end;

          if isValid and (time1*60+time2 - FOffset = oldtime) then //找到 指定时间串
          findOk:=true;  //找到 啦 啦 啦 ...


        end; //非法行 判断结束
        //==========是否找到 指定时间标签==========

        //-------找到 和 没找到 之后的处理 ----------
        if findok then begin
          Result:= true;

          //根据 老时间标签(timerstr)
          //生成 新的时间标签
          NewTime:=time1*60+time2 - aTime;

          //根据 原来是否使用毫秒 和 目前调整的偏移时间是否属于毫秒级别
          //          来决定 是否 使用毫秒
          UseMS:= (Pos('.',timestr)>0) or (aTime mod 1000 <>0);

          //转化时间为时间串例如: 72秒 ==>> '00:01:12.000'
          NewTimeLabel:=ConvertTimeToTimestr(NewTime,0,false,true,UseMS,true);

          //返回 新的歌词部分
          curLyric := left_Lyric + '[' + NewTimeLabel + ']'+ Right_Lyric;

          end
         else //还 没找到
          begin  //在 该行歌词剩余部分 找找看

          if AjustOneLine(Right_lyric) then
          begin
          //在剩余部分内找到了
          curLyric:= Left_lyric+ '[' + timestr +']' +Right_lyric ;

          Result:=true;
          end
          //else  剩余部分内 没有的话 ,只好返回 false 啦
          //   (函数开始处,已经默认=false)

          end;
         //=========找到 和 没找到 之后的处理==========  

   end; //end function AjustOneLine

begin
    AjustOk:=false;
    Result:=false;

    FTxt:=TStringlist.create;
 try
    FTxt.LoadFromFile(FFilename);

     for i:=0 to FTxt.Count-1 do
     begin
        thisLyric:=FTxt[i];

        if AjustOneLine(thisLyric) then
        begin
          AjustOk:=true;
          //更新 新生成 的歌词行
          FTxt[i]:=thisLyric;

          break;
        end;
     end;

   if AjustOk then
   begin
     //保存歌词文件
     FTxt.SaveToFile(FFilename);

     //重新载入歌词
     loadLyric(FFilename);

     Result:=true;
   end;
   
   FTxt.Clear;
 finally
   FTxt.free;
 end;

end;

//保存歌词内容到文件
function TLyric.SaveLyricsToFile(vFileName:string):boolean;
var i:integer;
   aTxt:Tstrings ;
begin
   result:=false;
   if FCount<=0 then exit;

   aTxt:=Tstringlist.Create;
   try
      if FTi <>' then
        aTxt.Add('歌名:'+FTi);
      if FAur <>' then
        aTxt.Add('歌手:'+FAur);
      if Fal <>' then
        aTxt.Add('专辑:'+Fal);
     // if Fby <>' then
     //   lbxpreview.Items.Add('歌词编辑:'+Fby);
       if aTxt.Count >0 then
          aTxt.Add('--- --- --- --- --- --- ---');

     for i:=0 to FCount-1 do
        aTxt.Add(LyricArray[i].lyStr ) ;

     aTxt.SaveToFile(vFilename);

     Result:=true;
   finally
     aTxt.Free;
   end;
end;

end.
Google
 
本站原创作品,未经作者许可,严禁任何方式转载;转载作品,如果侵犯了您的权益,请联系我们
龙脉加密锁 15元起 Grid++Report 报表 申请支付@网
 相关文章
没有相关文章
相关评论
共有评论10条 当前显示最后6条评论
luckywangxw 2005/11/14 9:47:40
函数
//转化时间(毫秒) 为 时间字符串
//   RestTime: 是否为 剩余时间
//   AutoHour: 是否 小时 为自动显示模式(有小时则显示,否则不显示)
//   ShowMS  : 是否 显示毫秒
//   UseColon : 中间用冒号 隔开,否则 用 "时、分、秒"
function ConvertTimeToTimestr(aTimePos,aTimeLen:longInt;RestTime,AutoHour,ShowMS,UseColon:boolean):string;

function ConvertTimeToTimestr(aTimePos,aTimeLen:longInt;RestTime,AutoHour,ShowMS,UseColon:boolean):string;
var
   vHou,vMin,vSec:integer;
   vSecR:real;
   sHou,sMin,sSec:string;

   isFu:boolean;//该时间 是否为负

   lbstr:string;
begin
    vHou:=0;
    isFu:= ( aTimePos<0) ;
    lbStr:=';
    if isFu and Not RestTime then
    begin
       aTimePos:=-aTimePos;
       lbStr:='-';
    end;

    if not RestTime then
      begin
        if aTimePos> 3600000 then begin
          vHou:=trunc(aTimePos / 3600000) ;
          vMin:=trunc((aTimePos-vHou*3600000) / 60000);
          vSec:=trunc((aTimePos-vHou*3600000-vMin*60000) / 1000);
          vSecR:=(aTimePos-vHou*3600000-vMin*60000) / 1000;
        end
        else
        begin
          vMin:=trunc(aTimePos / 60000);
          vSec:=trunc((aTimePos-vMin*60000) / 1000);
          vSecR:=(aTimePos-vMin*60000) / 1000;
        end;
      end
    else          // 剩余时间
      begin
        if aTimeLen-aTimePos > 3600000 then begin
          vHou:=trunc((aTimeLen-aTimePos) / 3600000) ;
          vMin:=trunc(((aTimeLen-aTimePos)-vHou*3600000) / 60000);
          vSec:=trunc(((aTimeLen-aTimePos)-vHou*3600000-vMin*60000) / 1000);
          vSecR:=((aTimeLen-aTimePos)-vHou*3600000-vMin*60000) / 1000;
        end
        else
        begin
          vMin:=trunc((aTimeLen-aTimePos) / 60000);
          vSec:=trunc(((aTimeLen-aTimePos)-vMin*60000) / 1000);
          vSecR:=((aTimeLen-aTimePos)-vMin*60000) / 1000;
        end;
    end;

  if vHou<>0 then
    sHou:=  formatstr(inttostr(vHou),2,true,false)
  else
    sHou:=';

  sMin:=  formatstr(inttostr(vMin),2,true,false);

  if ShowMS then   //是否显示 毫秒
    sSec:= formatfloat('00.000',vSecR)
  else
    sSec:=  formatstr(inttostr(vSec),2,true,false);

  if UseColon then begin
      if AutoHour then begin
        if shou<>' then
          result:=lbStr + sHou+':'+sMin+':'+sSec
        else
          result:=lbStr + sMin+':'+sSec
      end
      else
        result:=lbStr + sHou+':'+sMin+':'+sSec;
    end
  else
    begin
      if AutoHour then begin
        if shou<>' then
          result:=lbStr + inttostr(strtoInt(sHou))+'时'+inttostr(strtoInt(sMin))+'分'+inttostr(strtoInt(sSec))+'秒'
        else
          result:=lbStr + inttostr(strtoInt(sMin))+'分'+inttostr(strtoInt(sSec))+'秒'
      end
      else
        result:=lbStr + inttostr(strtoInt(sHou))+'时'+inttostr(strtoInt(sMin))+'分'+inttostr(strtoInt(sSec))+'秒';
    end;

  if RestTime then
      Result:='-'+Result;
end;
jack011 2006/7/4 15:33:37
这个程序,在多个时间列表的时候,好象没有分开吧!

比如  [03:31.52][02:58.62][01:25.67]何必一再说慌
      [03:34.52][03:01.85][01:28.70]来帮美梦化装
      [03:04.83][01:31.70]沉醉但醉醒更长

说错了,请大虾见谅
whsbk 2007/11/21 10:25:31
兄弟给个使用该类的演示程序吧,谢了
itisgood 2008/4/1 16:53:36
是啊,给个演示,怎么调用
aping08 2008/11/6 21:19:07
好东西
aping08 2008/11/6 21:28:43
formatstr
这个有没有呀?
我要发表评论 查看全部评论
 
  DELPHI盒子版权所有 1999-2023 V4.01 粤ICP备10103342号-1 更新RSS列表