打印

[服务器端交互] ★火山flash音乐播放器三部曲完成(附源文件和歌词同步教程)

[歌词同步教程从9楼开始]

经过一个多星期的奋战,终于把“火山音乐播放器”三部曲全部完工了,它们分别是:

1,FLASH+WMP播放FLASH本身无法播放的音乐格式和视频格式。
→参考教程:http://bbs.blueidea.com/thread-2677496-1-1.html
→源文件:http://www.huoshan.org/shiyan/flash_wmp/flash_wmp.rar

2,FLASH+SwiftMP3波谱同步。
→参考教程:http://space.flash8.net/bbs/thread-307160-1-1.html
→源文件:http://www.huoshan.org/shiyan/flash_boxing/flash_boxing.rar

3,FLASH+LRC歌词同步。
→参考教程:http://bbs.blueidea.com/viewthread.php?tid=2205817&page=1

下面的任务就是把这几种功能融合到一起,倾力打造“火山多功能条形网页播放器”了,不过首先要好好设计一下界面

在这里要特别感谢HBrO斑竹,1和3都是参考他的教程做的,不然我不可能这么快完成三部曲。

★歌词和波谱同步演示:http://www.huoshan.org/shiYanShi/shiYanShi.html#id=1
★这次没有开放源文件,其实在这个歌词同步播放器中,LRC的解析是其灵魂,在这方面HBrO表现了天才的创造性,我准备征得HBrO的同意后,把这部分作为专题用自己的语言再讲讲,分享知识的同时,加强自己的理解。到时候我会提供一个含金量更高的源文件,就是不知道大家现在还对这个技术感兴趣不?

[ 本帖最后由 jimohuoshan 于 2007-10-23 10:06 编辑 ]
本帖最近评分记录
  • HBrO 威望 +3 精品文章 2006-10-12 01:20
有人说歌词不能同步,可我测试的都问题啊?大家帮我测试一下到底能不能同步
你的歌词就只有一行,有的人能不能看到歌词还成问题呢.

TOP

HOHO,原来现在才发布啊,我这边测试可以同步的。
停止签名

TOP

认证您的手机,获得手机认证图标, 更多手机认证的好处
呵呵:)原来如次啊,忘给个提示了。
弄成一行主要是考虑以后要弄成条形播放器。
对了,HBrO老大,我能把你那个LRC解析过程作为专题再讲一遍?
你那个解析过程太有创造性了,但由于跟播放器的制作放到了一起,有点乱,我想再把它系统化一下,方便新手看 其实只要LRC解析成功,同步效果就可以任意发挥了!

TOP

你可以再写一遍.

TOP

收到,马上写,就写到这个帖子里吧,用不着再开新帖了:)

TOP

回复

很好的!
也许有些朋友的旧版本文件在缓存了吗?
快乐每一天!

TOP

★再论LRC歌词的解析(一)

●歌词分析●
1.1:LRC歌词的结构。
示例:
复制内容到剪贴板
代码:
[ti:黑色幽默]
[ar:周杰伦]
[al:Jap]
[by:歌词吾爱[url]http://www.51lrc.com[/url]]
[offset:400]
[00:02.00]词/曲:周杰伦
[00:05.49]歌词吾爱
[00:09.48]http://www.51lrc.com
[00:15.84]难过 是因为闷了很久
[00:21.18]是因为想了太多
[00:24.91]是心理起了作用
[00:30.89]你说 苦笑常常陪着你
[00:36.13]在一起有点勉强
[00:39.83]该不该现在休了我
[02:45.62][00:44.86]不想太多
[02:47.71][00:47.41]我想一定是我听错弄错搞错
[02:53.55][00:53.28]拜托 我想是你的脑袋有问题
[03:00.53][01:00.11]随便说说
[03:04.49][01:02.47]其实我早已经猜透看透不想多说
[03:12.19][01:09.94]只是我怕眼泪撑不住
[03:16.31][01:15.77]不懂 你的黑色幽默
[03:23.51][01:23.25]想通 却又再考倒我
[03:30.61][01:30.63]说散 你想很久了吧?
[03:37.92][01:37.72]我不想拆穿你
[03:46.16][01:45.85]当作 是你开的玩笑
[03:53.54][01:53.22]想通 却又再考倒我
[04:16.74][04:01.06][02:00.76]说散 你想很久了吧?
[04:07.94][02:07.79]败给你的黑色幽默
[04:23.15]我的认真败给黑色幽默
说明:由上面的示例可以看出,LRC歌词是用时间标签来标定歌词内容,每个“时间标签”都由中括号标注,后面跟着在本时间要显示的歌词内容。比较特殊的情况有以下几点:
①在歌词最开头有一些歌曲文件信息,这些信息没有时间标签,在我们做歌词同步的时候,也不需要显示,我们可以将其删除。
②一行歌词内容往往照应一个或多个时间标签,这是由于同一句歌词在一首歌中可能出现好多次。按HBrO的叫法,我把它称为“压缩歌词”。然而我们在显示歌词的时候,却要进行“解压”,就是让每句歌词只对应一个时间标签,比如歌词倒数第三行:“[04:07.94][02:07.79]败给你的黑色幽默”
我们就要把它“解压”成两行:
[04:07.94]败给你的黑色幽默
[02:07.79]败给你的黑色幽默
同理,倒数第四行“[04:16.74][04:01.06][02:00.76]说散 你想很久了吧?”就要解压为三行了。
③有些地方会有空行,比如倒数第二行就是空行,我们在同步歌词的时候不需要,所以也要删除。


1.2:编码。
LRC文件其实也是文本文件,我们用千千静听保存歌词的时候会发现,它会提示将歌词保存成两种后缀名,一种是.lrc,而另一种,就是.txt。所以LRC文件的编码应该和TXT一样的。而在TXT中,换行是用\r\n表示的,这跟FLASH不一样,在FLASH中换行\r和回车\n都会造成空行,所以,有些朋友会发现,外部导入到FLASH中的TXT文本,在TXT中明明只换一行,而在FLASH中却换了两行!?懂得了这个原理,我们只要用geci_array = geci.split("\r\n");就可以根据换行把每行歌词信息都储存在geci_array数组里了。注:代码中的geci是外部载入的原始歌词内容,就是上面示例的歌词。

1.3:完成了对LRC歌词的分析,下面我将用三个函数完成对歌词解析,最终把时间和内容进行分离,并分别储存在两个长度相等,内容对应的数组中,也就是说,时间数组中的第一项对应内容数组中的第一项,时间数组中的第N项对应内容数组中的第N项,最终通过对比音乐播放的时间和时间数组,来同步的显示内容数组。

1.4:在开始讲解之前,请大家先看看我这个范例,有个感性认识,我下面的讲解也都是围绕这个范例讲解的。等歌词载入完成后,点击下面的开始按钮,就会发现随着时间的变化,歌词进行同步显示。
演示:http://www.huoshan.org/swf/boKe/geCiTongBu/geCi.html

[ 本帖最后由 jimohuoshan 于 2007-10-23 10:04 编辑 ]
附件: 您所在的用户组无法下载或查看附件,您需要注册/登录后才能查看!

TOP

佩服!

lrc文件的显示,大概是对string的处理和转换了,繁琐一点吧?还望指教12
flash提供的api还是好多阿。
有些不能实现的还能指望activeX.真实厉害
快乐每一天!

TOP

★再论LRC歌词的解析(二)

●前期工作●

2.1:界面布局。
新建一FLASH文件,在舞台上拖放四个textarea组件,左上为“yuangeci_txt”,左下为"wukonghanggeci_txt",右上为"jieyageci_txt",右下为"fenligeci_txt"。下面是显示歌词的部分,开始按钮的名字为:"kaishi_btn"。然后紧靠右的是时间显示动态文本框,名字为"shijiantishi_var"。再靠右则是歌词显示的文本框,名字为"gecixianshi_var"。

2.2:系统代码初始化。
在贞上写代码:
复制内容到剪贴板
代码:
//===================系统初始化===============
//编码
System.useCodepage = true;
//“按钮”不可用
kaishi_btn.enabled = false;
//储存原歌词及删除空行后的歌词
var geci_array = new Array();
//声明一个数组,记录解压后的歌词
var jieyageci_array = new Array();
//储存歌词处理最终生成的时间和内容序列
var shijian_array = new Array();
var neirong_array = new Array();
//=====================载入并处理歌词======================
//——————载入歌词
var geci_xml = new XML();
geci_xml.load("heiseyoumo.txt");
geci_xml.onLoad = function() {
    //“开始”按钮可用
    kaishi_btn.enabled = true;
    //载入完成提示
    gecixianshi_var = "歌词载入完成,请点左边的开始按钮查看同步效果!";
    //将XML转换成字符串,并储存在变量中
    geci = geci_xml.toString();
    //在textarea组件中显示原歌词
    yuangeci_txt.text = geci;
    //删除歌词空行
    shanchukonghang();
    //解压歌词
    jieya();
    //分离歌词
    fenli();
};
代码说明:代码中“系统初始化”部分主要是进行各种初始设置,以及声明用来储存各个阶段歌词的数组。“载入并处理歌词”部分,当载入歌词完成后,通过shanchukonghang、jieya、fenli三个函数完成对歌词的解析,我下面着重要讲的,就是这三个函数。
在这里需要说明的有两点:
①由于我的服务器不识别LRC文件格式,我只要将歌词文件后缀名改为TXT,这并不影响。
②XML对象除了可以载入XML文件外,其实它还可以载入任何文本文件。所以我们在这里用一个XML对象"geci_xml"储存原始歌词信息,并在歌词载入完成后把它赋予变量"geci"。

TOP

搂住辛苦了!

TOP

再论LRC歌词的解析(三)

●将每行歌词储存在一个数组中并删除多余空行●
在上一节中,我们把载入的原始歌词储存在了变量"geci"中, 但这样的歌词是无法被利用的,我们需要对其进行解析。第一步就是将歌词按换行分割成数组元素,每行歌词储存在一个数组元素中,所有的歌词数组元素储存在数组geci_array中。实现的代码为:geci_array = geci.split("\r\n");但这样拆分而成的数组中包含了空行元素,我们需要删除。实现的代码如下:
//如果数组元素为空,删除本元素
if (geci_array[i] == "") {
    //删除空行
    geci_array.splice(i, 1);
}
然后用循环检测一遍,删除所有空行元素:
for (var i = 0; i<geci_array.length; i++) {
       if (geci_array[i] == "") {
           //删除空行
           geci_array.splice(i, 1);
       }
}

最后,把这些封装成一个函数:shanchukonghang,即:
复制内容到剪贴板
代码:
//——————将每行歌词储存在一个数组中,并删除多余空行
function shanchukonghang() {
    //删除回车和换行,并把每行歌词储存到数组中
    geci_array = geci.split("\r\n");
    for (var i = 0; i<geci_array.length; i++) {
        if (geci_array[i] == "") {
            //删除空行
            geci_array.splice(i, 1);
        }
        //显示无空行歌词,为了方便查看,这里仅在查看时人为的添加了一个换行,但这个换行并不在数组中
                                wukonghanggeci_txt.text += geci_array[i]+"<br>";
    }
}
调用这个函数后,将会在左下的文本框中显示下面处理过的歌词:
复制内容到剪贴板
代码:
[ti:黑色幽默]
[ar:周杰伦]
[al:Jap]
[by:歌词吾爱http://www.51lrc.com]
[offset:400]
[00:02.00]词/曲:周杰伦
[00:05.49]歌词吾爱
[00:09.48]http://www.51lrc.com
[00:15.84]难过 是因为闷了很久
[00:21.18]是因为想了太多
[00:24.91]是心理起了作用
[00:30.89]你说 苦笑常常陪着你
[00:36.13]在一起有点勉强
[00:39.83]该不该现在休了我
[02:45.62][00:44.86]不想太多
[02:47.71][00:47.41]我想一定是我听错弄错搞错
[02:53.55][00:53.28]拜托 我想是你的脑袋有问题
[03:00.53][01:00.11]随便说说
[03:04.49][01:02.47]其实我早已经猜透看透不想多说
[03:12.19][01:09.94]只是我怕眼泪撑不住
[03:16.31][01:15.77]不懂 你的黑色幽默
[03:23.51][01:23.25]想通 却又再考倒我
[03:30.61][01:30.63]说散 你想很久了吧?
[03:37.92][01:37.72]我不想拆穿你
[03:46.16][01:45.85]当作 是你开的玩笑
[03:53.54][01:53.22]想通 却又再考倒我
[04:16.74][04:01.06][02:00.76]说散 你想很久了吧?
[04:07.94][02:07.79]败给你的黑色幽默
[04:23.15]我的认真败给黑色幽默
[ 本帖最后由 jimohuoshan 于 2006-10-11 01:08 编辑 ]

TOP

再论LRC歌词的解析(四)

●解压歌词●
经过上面一步的处理,我们已经把歌词储存在了"geci_array"数组中,每行歌词储存在一个数组元素中,空行不记入数组。现在我们要做的是“解压”歌词,举上面倒数第三行歌词为例:“[04:16.74][04:01.06][02:00.76]说散 你想很久了吧?”

①首先声明一个临时数组,用来储存拆分过后的单行歌词,示例的歌词就也会被储存在这个数组中:
var danhanggeci_array = new Array();

②以"]"为分隔符拆分这句歌词为数组:
danhanggeci_array = geci_array[i].split("]");
这时,示例歌词被分成以下四个数组元素:
danhanggeci_array[0]=“[04:16.74”
danhanggeci_array[1]=“[04:01.06”
danhanggeci_array[2]=“[02:00.76”
danhanggeci_array[3]=“说散 你想很久了吧?”

③对这四个元素进行重新组合,使每个时间标记都分别匹配歌词,也是所谓的“解压”:
for (var j = 0; j<danhanggeci_array.length-1; j++) {
       jieyageci_array.push(danhanggeci_array[j]+"]"+danhanggeci_array[danhanggeci_array.length-1]);
}
这句代码有点复杂,首先,jieyageci_array是一开始就声明过的用来储存解压后歌词的数组,"danhanggeci_array[j]"则是循环中的时间标签数组元素,而"danhanggeci_array[danhanggeci_array.length-1]"则是数组中的最后一项,它一定是歌词内容,这里正是“说散 你想很久了吧?”。这样我们经过"danhanggeci_array.length-1"次循环,这里为3次循环后,jieyageci_array里就被添加了三项内容:
[04:16.74]说散 你想很久了吧?
[04:01.06]说散 你想很久了吧?
[02:00.76]说散 你想很久了吧?

④上面的分析只是针对一行歌词,下面我们通过一个嵌套循环,对所有行歌词都进行类似操作:
for (var i = 0; i<geci_array.length; i++) {
       //用一个临时的数组储存单行歌词拆分而成的时间和内容
       var danhanggeci_array = new Array();
       danhanggeci_array = geci_array[i].split("]");
       //将重复的歌词拆分为独立歌词
       for (var j = 0; j<danhanggeci_array.length-1; j++) {
              jieyageci_array.push(danhanggeci_array[j]+"]"+danhanggeci_array[danhanggeci_array.length-1]);
       }
}

这样以来,原来储存在"geci_array"数组中的歌词,就被解压并保存在了新数组"jieyageci_array"中。由前面的分析可以知道,"jieyageci_array"中数组元素所储存的歌词,格式是统一的一个时间标记对应一句歌词内容,而且时间标记都在内容前面,这时候我们可以巧妙的利用数组的"sort"方法按时间先后对数组元素进行排序,关于sort排序的规则,你可以查一下帮助。代码为:jieyageci_array.sort();最后就是在右上文本框中显示解压后的歌词,代码如下:
for (var i = 0; i<jieyageci_array.length; i++) {
       //在右上文本框显示解压后的歌词,这里也是仅在显示时人为的在每句歌词之间添加了一个换行
       jieyageci_txt.text += jieyageci_array[i]+"<br>";
}

把上面的代码封装入"jieya"函数中,代码如下:
复制内容到剪贴板
代码:
//——————解压歌词
function jieya() {
    for (var i = 0; i<geci_array.length; i++) {
        //用一个临时的数组储存单行歌词拆分而成的时间和内容
        var danhanggeci_array = new Array();
        danhanggeci_array = geci_array[i].split("]");
        //将重复的歌词拆分为独立歌词
        for (var j = 0; j<danhanggeci_array.length-1; j++) {
            jieyageci_array.push(danhanggeci_array[j]+"]"+danhanggeci_array[danhanggeci_array.length-1]);
        }
    }
    //按时间先后排序:
    jieyageci_array.sort();
    //显示分解压后的歌词   
    for (var i = 0; i<jieyageci_array.length; i++) {
        //在右上文本框显示解压后的歌词,这里也是仅在显示时人为的在每句歌词之间添加了一个换行
        jieyageci_txt.text += jieyageci_array[i]+"<br>";
    }
}
调用这个函数后,右上文本框中显示的歌词为:
复制内容到剪贴板
代码:
[00:02.00]词/曲:周杰伦
[00:05.49]歌词吾爱
[00:09.48]http://www.51lrc.com
[00:15.84]难过 是因为闷了很久
[00:21.18]是因为想了太多
[00:24.91]是心理起了作用
[00:30.89]你说 苦笑常常陪着你
[00:36.13]在一起有点勉强
[00:39.83]该不该现在休了我
[00:44.86]不想太多
[00:47.41]我想一定是我听错弄错搞错
[00:53.28]拜托 我想是你的脑袋有问题
[01:00.11]随便说说
[01:02.47]其实我早已经猜透看透不想多说
[01:09.94]只是我怕眼泪撑不住
[01:15.77]不懂 你的黑色幽默
[01:23.25]想通 却又再考倒我
[01:30.63]说散 你想很久了吧?
[01:37.72]我不想拆穿你
[01:45.85]当作 是你开的玩笑
[01:53.22]想通 却又再考倒我
[02:00.76]说散 你想很久了吧?
[02:07.79]败给你的黑色幽默
[02:45.62]不想太多
[02:47.71]我想一定是我听错弄错搞错
[02:53.55]拜托 我想是你的脑袋有问题
[03:00.53]随便说说
[03:04.49]其实我早已经猜透看透不想多说
[03:12.19]只是我怕眼泪撑不住
[03:16.31]不懂 你的黑色幽默
[03:23.51]想通 却又再考倒我
[03:30.61]说散 你想很久了吧?
[03:37.92]我不想拆穿你
[03:46.16]当作 是你开的玩笑
[03:53.54]想通 却又再考倒我
[04:01.06]说散 你想很久了吧?
[04:07.94]败给你的黑色幽默
[04:16.74]说散 你想很久了吧?
[04:23.15]我的认真败给黑色幽默
[al:Jap]
[ar:周杰伦]
[by:歌词吾爱http://www.51lrc.com]
[offset:400]
[ti:黑色幽默]
[ 本帖最后由 jimohuoshan 于 2006-10-11 01:04 编辑 ]

TOP

再论LRC歌词的解析(五)

●分离歌词●
经过上面的解压歌词后,每句歌词内容都对应且仅对应一个时间标签,并且储存在数组"jieyageci_array"中。接下来我们要做的就是把时间和对应的内容再进行分离,分别储存在两个数组"shijian_array"和"neirong_array"中。

①按照上一节的思路,我们还把单行歌词储存在一个临时数组中,以第一句歌词为例:
var danhanggeci_array = jieyageci_array[0].split("]");
这时候,临时数组"danhanggeci_array"中就储存了两个元素:
danhanggeci_array[0]="[00:02.00"
danhanggeci_array[1]="词/曲:周杰伦"
这里比较麻烦的是时间元素,它不但多了个"[",而且又不是数字类型,在应用中不容易同歌曲播放时间进行比较从而实现歌词同步,所以这里必须对它进行处理。
1,祛除"[":
var shijianyuansu = danhanggeci_array[0].substring(1);  //"shijianyuansu"是一个记录时间元素的局域变量
2,把时间标记转换成数字:
shijianyuansu = shijianchuli(shijianyuansu);  //"shijianchuli"是一个自定义把时间转化成相应数字的函数,我一会儿再讲

OK,经过处理后,我们就可以通过以下代码把时间和内容赋予早在“系统代码初始化”中就定义好的"shijian_array"和"neirong_array"两个数组中了:
shijian_array.push(shijianyuansu);
neirong_array.push(neirongyuansu);

②上面是通过一句示例歌词说明问题,下面我们对所有歌词进行类似操作:
for (var i = 0; i<jieyageci_array.length; i++) {
       //用一个临时的数组储存解压之后单行歌词拆分而成的时间和内容
       var danhanggeci_array = jieyageci_array[i].split("]");
       //——————分离时间和歌词元素
       //删除时间元素中的“[”
       var shijianyuansu = danhanggeci_array[0].substring(1);
       //格式化时间元素  
       shijianyuansu = shijianchuli(shijianyuansu);
       //内容元素
       var neirongyuansu = danhanggeci_array[1];
       //将时间和内容赋予数组,如果内容为空,则不记入数组              
       shijian_array.push(shijianyuansu);
       neirong_array.push(neirongyuansu);
       }
}
嘿嘿,怎么样,是不是很简单?不过先别着急,我们还有点地方需要再完美一点,我们看看上一节中的歌词,倒数后五条是没用的信息,不需要记入数组,没用不说,还浪费内存,所以通过下面的代码将其屏蔽掉:
if (isNaN(shijianyuansu)) {
       break;
}
这段代码的作用就是,当发现时间元素的数据类型不为数字时,就退出循环,需要注意的是这段代码必须放在“将时间和内容赋予数组”的语句之前。

③我们把最终的代码封装到"fenli"函数中,代码如下:
复制内容到剪贴板
代码:
//——————分离歌词为时间和内容,并格式化歌词时间
function fenli() {
    for (var i = 0; i<jieyageci_array.length; i++) {
        //用一个临时的数组储存解压之后单行歌词拆分而成的时间和内容
        var danhanggeci_array = jieyageci_array[i].split("]");
        //——————分离时间和歌词元素
        //删除时间元素中的“[”
        var shijianyuansu = danhanggeci_array[0].substring(1);
        //格式化时间元素  
        shijianyuansu = shijianchuli(shijianyuansu);
        //内容元素
        var neirongyuansu = danhanggeci_array[1];
        //删除多余的说明信息,根据时间元素是否为
        if (isNaN(shijianyuansu)) {
            break;
        }
        //将时间和内容赋予数组,如果内容为空,则不记入数组              
        shijian_array.push(shijianyuansu);
        neirong_array.push(neirongyuansu);
    }
    //删除不用的数组,释放内存
    delete geci_array;
    delete jieyageci_array;
    //在右下文本框显示分离后的歌词   
    for (var i = 0; i<shijian_array.length; i++) {
                                //现在不用再解释了吧:)
        fenligeci_txt.text += shijian_array[i]+":"+neirong_array[i]+"<br>";
    }
}
④时间处理函数。
刚才为了连贯性,把时间处理函数跳了过去,现在回来解释一下。我们可以很明显的看到,LRC的歌词时间标记采用的是分秒形式,但秒精确到了小数点后两位。于是我们可以用下面的公式把时间统一用秒计算:总秒数=分*60+秒,按照这个思路我们来定义"shijianchuli"函数:
//时间元素处理函数,将歌词中的时间转换成以秒计算的数字
function shijianchuli(shijian_fc) {
       var shijian = shijian_fc.split(":");
       return parseInt(shijian[0])*60+parseFloat(shijian[1]);
}

⑤调用"fenli"函数后,右下文本框显示的歌词:
复制内容到剪贴板
代码:
2:词/曲:周杰伦
5.49:歌词吾爱
9.48:http://www.51lrc.com
15.84:难过 是因为闷了很久
21.18:是因为想了太多
24.91:是心理起了作用
30.89:你说 苦笑常常陪着你
36.13:在一起有点勉强
39.83:该不该现在休了我
44.86:不想太多
47.41:我想一定是我听错弄错搞错
53.28:拜托 我想是你的脑袋有问题
60.11:随便说说
62.47:其实我早已经猜透看透不想多说
69.94:只是我怕眼泪撑不住
75.77:不懂 你的黑色幽默
83.25:想通 却又再考倒我
90.63:说散 你想很久了吧?
97.72:我不想拆穿你
105.85:当作 是你开的玩笑
113.22:想通 却又再考倒我
120.76:说散 你想很久了吧?
127.79:败给你的黑色幽默
165.62:不想太多
167.71:我想一定是我听错弄错搞错
173.55:拜托 我想是你的脑袋有问题
180.53:随便说说
184.49:其实我早已经猜透看透不想多说
192.19:只是我怕眼泪撑不住
196.31:不懂 你的黑色幽默
203.51:想通 却又再考倒我
210.61:说散 你想很久了吧?
217.92:我不想拆穿你
226.16:当作 是你开的玩笑
233.54:想通 却又再考倒我
241.06:说散 你想很久了吧?
247.94:败给你的黑色幽默
256.74:说散 你想很久了吧?
263.15:我的认真败给黑色幽默
你会发现,不但删除了多余信息,而且时间也都被转换成了以秒计的数字。

TOP

再论LRC歌词的解析(六)

●显示歌词●
呼呼!歌词终于解析完了,现在激动人心的时刻到来了,我们要进行歌词同步了!
最后添加以下代码:
复制内容到剪贴板
代码:
kaishi_btn.onRelease = function() {
    //开始记录时间
    kaishishijian = getTimer();
    //歌词循环因子,用来在循环中显示下一条歌词,初始化为0,显示第一条歌词
    xunhuanyinzi = 0;
    //循环因子,根据此因子逐条显示歌词
    _root.onEnterFrame = function() {
        //显示播放时间
        shijiantishi_var = (getTimer()-kaishishijian)/1000;
        //显示歌词,根据播放时间和"shijian_array"元素之间的大小关系,显示对应的歌词内容
        if (Number(shijiantishi_var)<=shijian_array[xunhuanyinzi+1]) {
            gecixianshi_var = neirong_array[xunhuanyinzi];
        } else {
            //循环因子加1,显示下一条歌词
            xunhuanyinzi++;
        }
    };
};
说明:由于我这个是只是歌词解析范例演示,没有真的载入音乐,所以我用getTimer虚拟了一个时间,歌词载入完成,“开始”按钮可用后,就可以通过点击它查看同步效果了。当然,我这里只是实现了最基本的解析和同步,如果要在实战中运用,还有很多细节问题要处理,这个就留给聪明读者自己去发挥吧

现在回顾一下所有的代码:
复制内容到剪贴板
代码:
//===================系统初始化===============
//编码
System.useCodepage = true;
//“开始”按钮不可用
kaishi_btn.enabled = false;
//储存原歌词及删除空行后的歌词
var geci_array = new Array();
//声明一个数组,记录解压后的歌词
var jieyageci_array = new Array();
//歌词处理最终生成的时间和内容序列
var shijian_array = new Array();
var neirong_array = new Array();
//=====================载入并处理歌词=============================
//——————载入歌词
var geci_xml = new XML();
geci_xml.load("heiseyoumo.txt");
geci_xml.onLoad = function() {
    //“开始”按钮可用
    kaishi_btn.enabled = true;
    //载入完成提示
    gecixianshi_var = "歌词载入完成,请点左边的开始按钮查看同步效果!";
    //将XML转换成字符串,并储存在变量中
    geci = geci_xml.toString();
    //显示原歌词
    yuangeci_txt.text = geci;
    //删除歌词空行
    shanchukonghang();
    //解压歌词
    jieya();
    //分离歌词
    fenli();
};
//——————将每行歌词储存在一个数组中,并删除多余空行
function shanchukonghang() {
    //删除回车和换行,并把每行歌词储存到数组中
    geci_array = geci.split("\r\n");
    for (var i = 0; i<geci_array.length; i++) {
        if (geci_array[i] == "") {
            //删除空行
            geci_array.splice(i, 1);
        }
        //显示无空行歌词                                                                                                                                 
        wukonghanggeci_txt.text += geci_array[i]+"<br>";
    }
}
//——————解压歌词
function jieya() {
    for (var i = 0; i<geci_array.length; i++) {
        //用一个临时的数组储存单行歌词拆分而成的时间和内容
        var danhanggeci_array = new Array();
        danhanggeci_array = geci_array[i].split("]");
        //将重复的歌词拆分为独立歌词
        for (var j = 0; j<danhanggeci_array.length-1; j++) {
            jieyageci_array.push(danhanggeci_array[j]+"]"+danhanggeci_array[danhanggeci_array.length-1]);
        }
    }
    //按时间先后排序:
    jieyageci_array.sort();
    //显示分解压后的歌词   
    for (var i = 0; i<jieyageci_array.length; i++) {
        //在右上文本框显示解压后的歌词,这里也是仅在显示时人为的在每句歌词之间添加了一个换行
        jieyageci_txt.text += jieyageci_array[i]+"<br>";
    }
}
//——————分离歌词为时间和内容,并格式化歌词时间
function fenli() {
    for (var i = 0; i<jieyageci_array.length; i++) {
        //用一个临时的数组储存解压之后单行歌词拆分而成的时间和内容
        var danhanggeci_array = jieyageci_array[i].split("]");
        //——————分离时间和歌词元素
        //删除时间元素中的“[”
        var shijianyuansu = danhanggeci_array[0].substring(1);
        //格式化时间元素  
        shijianyuansu = shijianchuli(shijianyuansu);
        //内容元素
        var neirongyuansu = danhanggeci_array[1];
        //删除多余的说明信息,根据时间元素是否为
        if (isNaN(shijianyuansu)) {
            break;
        }
        //将时间和内容赋予数组,如果内容为空,则不记入数组               
        shijian_array.push(shijianyuansu);
        neirong_array.push(neirongyuansu);
    }
    //删除不用的数组,释放内存
    delete geci_array;
    delete jieyageci_array;
    //显示分离后的歌词   
    for (var i = 0; i<shijian_array.length; i++) {
        fenligeci_txt.text += shijian_array[i]+":"+neirong_array[i]+"<br>";
    }
}
//时间元素处理函数,将歌词中的时间转换成以秒计算的数字
function shijianchuli(shijian_fc) {
    var shijian = shijian_fc.split(":");
    return parseInt(shijian[0])*60+parseFloat(shijian[1]);
}
//=====================歌词同步演示=======================
kaishi_btn.onRelease = function() {
    //开始记录时间
    kaishishijian = getTimer();
    //歌词循环因子,用来在循环中显示下一条歌词,初始化为0,显示第一条歌词
    xunhuanyinzi = 0;
    //循环因子,根据此因子逐条显示歌词
    _root.onEnterFrame = function() {
        //显示播放时间
        shijiantishi_var = (getTimer()-kaishishijian)/1000;
        //显示歌词,根据播放时间和"shijian_array"元素之间的大小关系,显示对应的歌词内容
        if (Number(shijiantishi_var)<=shijian_array[xunhuanyinzi+1]) {
            gecixianshi_var = neirong_array[xunhuanyinzi];
        } else {
            //循环因子加1,显示下一条歌词
            xunhuanyinzi++;
        }
    };
};
★★★范例源文件:http://www.huoshan.org/shiyan/flash_geci/shiyan.rar

[ 本帖最后由 jimohuoshan 于 2006-10-11 09:39 编辑 ]

TOP

从十点半一直写到两点半,终于写完了,发现自己的文字表现能力好象下降了,以后要勤写日记。先不想那么多了,睡觉去

TOP

大概现在还在睡觉吧。我有一次打CS,打着打着,竟然发现窗户外隐隐透出亮光来了。
多年熬夜的代价就是现在不能平躺着睡了,腰疼。
兄弟,身体第一。
停止签名

TOP

我晚上睡再晚,早上8点之前一定会醒的,除非我8点睡
朱高兄起的也很早啊!

TOP

早醒是年老的一个特征,这个都市造就了许许多多年老的年轻人
停止签名

TOP

5555555555~~~~~~~~~~~~~~我老了

TOP

不错不错,像你这样学了还要写出来的人值得表扬。
还有我觉得你的服务器好怪,好像这也不支持,那也不支持,不支持lrc不可能吧,他没什么支持不支持的呀。

TOP

我也不知道啊,它好象是做了某种过滤吧,我把.lrc直接传上去,就无法载入,但改为.txt后就可以了。在本地测试的时候,什么后缀名都可以。——最郁闷的是,我的空间竟然还不支持MP3!

TOP

免费的空间都比你的强!真不知你干嘛还用它。