• Flash/Flex学习笔记(32):播放音乐并同步显示lyc歌词(适用于Silverlight)


    题外话:个别朋友总是问我同样的问题,做为一名c#/silverlight程序员为啥还要学flash ?

    回 答:看日本片时,就不能对照看欧美的么? 不体会日本的细腻,又怎能感觉到欧美的粗放;同样都是web相关的技术,不必报门户之见;何况这二者有很多可以相互借鉴的东西。

    注:这个例子来自[FL车在臣](在blueidea上又名“寂寞火山”)翻译的“Animation in ActionScript3.0”一书,下面的原理分析也来自他的思路

    原 理:

    1.先分析一下lyc的格式:

    [ti:Going Home]
    [ar:Sophie Zelmani]
    [al:]
    [by:yitian1977]
    [offset:500]
    [00:01.52]Going Home
    [00:06.66]Sophie Zelmani
    [00:11.32]
    [00:36.60]Not very often have we met /
    [00:42.94]But the music's been too bad
    [00:48.92]Can only sense happiness
    [00:55.68]if the music is sad
    [00:59.34]
    [01:00.29]So, I'm going home
    [01:06.30]I must hurry home
    [01:11.88]Where a life goes on
    [01:16.05]
    [01:20.14]We're too old to make a mess
    [01:26.16]Dreams will keep me young
    [01:32.78]Old enough to stress
    [01:38.86]Only mirrors tell the time
    [01:41.76]
    [02:52.99][01:42.80]So, I'm going home
    [02:59.19][01:48.91]I must hurry home
    [03:05.33][01:55.04]So will my life go on
    [03:09.29][02:00.56]
    [03:17.40][02:07.45]Yes, I'm going home
    [03:23.70][02:13.43]Going home alone
    [03:29.80][02:19.77]And your life goes on
    [03:40.16][02:34.09]
    [04:05.13][03:52.01](edit by Nathan_na@msn.com)

    基本上就是: [时:分.秒](一个或多个) + 本句歌词
    2.不管是Flash还是Silverlight,在播放声音时,都可以得到播放进度:即当前播放到了第多少(豪)秒

    3.看懂了第1,2点的分析后,可以这么干:

    创建一个全局数组(或字典对象,反正只要能满足key-value结构就行),key为该句歌词对应的(豪)秒数,而value即为对应的歌词,然后将其按key(即歌词出现的时间)升序排序

    注:对于"[02:52.99][01:42.80]So, I'm going home"这种写法的歌词,在数组中要拆分成二条,即相当于:

    [02:52.99]So, I'm going home
    [01:42.80]So, I'm going home
    播放时,根据当前播放的时间进度,找到对应的数组元素,然后显示

    Flash版:

    As3代码
    package {
        import flash.display.Sprite;
        import flash.net.URLRequest;
        import flash.net.URLLoader;
        import flash.media.Sound;
        import flash.media.SoundChannel;
        import flash.events.Event;
        import flash.text.TextField;
        import flash.system.System;
        import flash.text.TextFieldAutoSize;
        import flash.events.MouseEvent;

        public class LycPlayer extends Sprite {

            
    var lrc_txt:TextField=new TextField();
            
    var LRCarray:Array=new Array();//全局数组
            var sc:SoundChannel;
            
    var sound:Sound;

            public 
    function LycPlayer() {

                
    //定位歌词显示文本框 
                lrc_txt.width=500;
                lrc_txt.selectable
    =false;
                lrc_txt.autoSize
    =TextFieldAutoSize.CENTER;
                lrc_txt.x
    =stage.stageWidth/2-lrc_txt.width/2;
                lrc_txt.y
    =0;
                addChild(lrc_txt);

                
    //加载歌词
                var loader:URLLoader=new URLLoader();
                loader.load(
    new URLRequest("http://images.24city.com/jimmy/flash/LycPlayer/lyc/GoingHome.txt"));
                loader.addEventListener(Event.COMPLETE,LoadFinish);

                
    //加载mp3
                sound=new Sound();
                sound.load(
    new URLRequest("http://www.apple520.com/templates/default/images/new/3.mp3"));
                
                
    //开始播放
                sc=sound.play();

                
    //监听Enter_Frame事件
                stage.addEventListener(Event.ENTER_FRAME,SoundPlaying);
                btnStop.addEventListener(MouseEvent.MOUSE_DOWN,StopMouseDownHandler);
                btnPlay.addEventListener(MouseEvent.MOUSE_DOWN,PlayMouseDownHandler);
            }

            
    function StopMouseDownHandler(e:MouseEvent) {
                
    if (sc!=null){
                    sc.stop();
                    sc 
    = null;
                }
            }
            
            
    function PlayMouseDownHandler(e:MouseEvent) {
                
    if (sc==null){
                    sc 
    = sound.play();
                }
            }

            
    function SoundPlaying(evt:Event):void {
                
    if (sc==null){return;}
                
    //trace(sc.position);
                for (var i:uint=2,j:uint=LRCarray.length-1; i <j; i++) {
                    
    if (sc.position<LRCarray[i].timer) {
                        lrc_txt.text
    =" "+LRCarray[i-2].lyric+"\n→"+LRCarray[i-1].lyric+"\n "+LRCarray[i].lyric;
                        
    break;
                    }
                    lrc_txt.text
    =LRCarray[LRCarray.length-1].lyric;
                }
            }

            
    function LoadFinish(evt:Event):void {

                
    var list:String=evt.target.data;
                
    var listarray:Array=list.split("\r\n");


                
    //分析歌词,填充到全局歌词数组中
                var reg:RegExp=/\[[0-5][0-9]:[0-5][0-9].[0-9][0-9]\]/g;
                
    for (var i:uint=1,j:uint=listarray.length; i <j; i++) {
                    
    var info:String=listarray[i];

                    
    var len:int=info.match(reg).length;
                    
    var timeAry:Array=info.match(reg);
                    
    var lyric:String=info.substr(len*10);

                    
    if (lyric.length<=0) {
                        
    continue;
                    }

                    
    for (var k:uint=0,t:uint=timeAry.length; k < t; k++) {
                        
    var obj:Object = new Object();
                        
    var ctime:String=timeAry[k];
                        
    var ntime:uint = 1000 * (parseInt(ctime.substr(1,2),10)*60 + parseInt(ctime.substr(4,5),10)) + parseInt(ctime.substr(7,8),10);
                        obj.timer
    =ntime;
                        obj.lyric
    =lyric;
                        LRCarray.push(obj);
                    }

                }

                
    //数组排序
                LRCarray.sort(compare);

                
    var objFirst:Object = new Object();
                objFirst.timer
    =1;
                objFirst.lyric
    ="Loading...";
                LRCarray.unshift(objFirst);

                
    var objLast:Object = new Object();
                objLast.timer
    =999999;
                objLast.lyric
    ="the end.";
                LRCarray.push(objLast);

                
    for (var m:Number=0,n =LRCarray.length; m<n; m++) {
                    trace(LRCarray[m].timer 
    + "\t" + LRCarray[m].lyric);
                }
            }

            
    //数组排序辅助方法
            private function compare(paraA:Object,paraB:Object):int {
                
    if (paraA.timer>paraB.timer) {
                    
    return 1;
                }
                
    if (paraA.timer<paraB.timer) {
                    
    return -1;
                }
                
    return 0;
            }
        }
    }

    Silverlight版:

    Xaml部分:

    Xaml代码
    <UserControl x:Class="SilverlightLyricPlayer.MainPage"
        xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d
    ="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable
    ="d"
        d:DesignHeight
    ="60" d:DesignWidth="400">

        
    <Grid x:Name="LayoutRoot" Background="White">
            
    <TextBlock x:Name="txtLyc" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
            
    <StackPanel Orientation="Horizontal" Height="20" HorizontalAlignment="Right" Margin="0,0,10,0">
                
    <Button x:Name="btnPlay" Width="40" Margin="5,0,5,0" Content="Play" Click="btnPlay_Click"></Button>
                
    <Button x:Name="btnStop" Width="40" Content="Stop" Click="btnStop_Click"></Button>
            
    </StackPanel>
            
    <MediaElement AutoPlay="True" x:Name="mePlayer" Visibility="Collapsed" />
        
    </Grid>
    </UserControl>

    cs部分:

    Xaml.CS代码
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text.RegularExpressions;
    using System.Windows;
    using System.Windows.Browser;
    using System.Windows.Controls;
    using System.Windows.Media;

    namespace SilverlightLyricPlayer
    {
        
    public partial class MainPage : UserControl
        {
            List
    <KeyValuePair<intstring>> lstLycs;

            
    public MainPage()
            {
                InitializeComponent();
                
    this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            }

            
    void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                lstLycs 
    = new List<KeyValuePair<intstring>>();
                WebClient _wcLyc 
    = new WebClient();
                Uri _uriLyc 
    = new Uri(HtmlPage.Document.DocumentUri, "http://images.24city.com/jimmy/flash/LycPlayer/lyc/GoingHome.txt");
                _wcLyc.OpenReadCompleted 
    += new OpenReadCompletedEventHandler(wcLyc_OpenReadCompleted);
                _wcLyc.OpenReadAsync(_uriLyc);
            }

            
    void wcLyc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                
    if (e.Error == null)
                {
                    Dictionary
    <intstring> dicLyc = new Dictionary<intstring>();

                    StreamReader _srReader 
    = new StreamReader(e.Result);
                    
    string _strlyc = _srReader.ReadToEnd().Replace(Environment.NewLine, "\n");
                    
    string[] _arrTemp = _strlyc.Split('\n');
                    Regex _reg 
    = new Regex("\\[[0-5][0-9]:[0-5][0-9].[0-9][0-9]\\]");
                    
    int _key = -1;
                    
    string _lyc = "";
                    
    foreach (string item in _arrTemp)
                    {
                        MatchCollection _mc 
    = _reg.Matches(item);
                        
    foreach (Match m in _mc)
                        {
                            _key 
    = 1000 * (int.Parse(m.Value.Substring(12)) * 60 + int.Parse(m.Value.Substring(42))) + int.Parse(m.Value.Substring(72));//将时间换成总毫秒数
                            _lyc = item.Substring(item.LastIndexOf(']'+ 1);
                            
    if (!dicLyc.ContainsKey(_key) && _lyc.Length > 0)
                            {
                                dicLyc.Add(_key, _lyc);
                            }
                        }

                        
                    }
                    dicLyc.Add(
    1"Loading...");
                    dicLyc.Add(
    999999"the end.");

                    lstLycs 
    = dicLyc.OrderBy(c => c.Key).ToList();

                    
    foreach (var item in lstLycs)
                    {
                        Debug.WriteLine(item.Key 
    + "\t" + item.Value);
                    }

                    mePlayer.Source 
    = new Uri(HtmlPage.Document.DocumentUri, "http://www.apple520.com/templates/default/images/new/3.mp3");
                    mePlayer.Volume 
    = 0.9;
                    mePlayer.Play();
                    CompositionTarget.Rendering 
    += new EventHandler(CompositionTarget_Rendering);//相当于As3.0中的addEventListener(Enter.ENTER_FRAME,EnterFrameHandler);
                }
            }

            
    void CompositionTarget_Rendering(object sender, EventArgs e)
            {
                
    for (int i = 2; i < lstLycs.Count-1; i++)
                {
                    
    if (mePlayer.Position.TotalMilliseconds < lstLycs[i].Key)
                    {
                        txtLyc.Text 
    = " " + lstLycs[i - 2].Value + Environment.NewLine + "" + lstLycs[i - 1].Value + Environment.NewLine + " " + lstLycs[i].Value;
                        
    break;
                    }
                    txtLyc.Text 
    = lstLycs.Last().Value;
                }
            }

            
    private void btnPlay_Click(object sender, RoutedEventArgs e)
            {
                mePlayer.Play();
            }

            
    private void btnStop_Click(object sender, RoutedEventArgs e)
            {
                mePlayer.Stop();
            }
        }
    }


    Silverlight演示地址:http://images.24city.com/jimmy/LycPlayer/ (安全沙箱原因,无法在播客园上正常播放,所以只能给出地址)

    下载:示例源文件代码

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    MFC线程(二):线程同步临界区CRITICAL SECTION
    自定义消息
    Visual C++线程同步技术剖析:临界区,时间,信号量,互斥量
    //解析数据函数指针,很爽
    CListCtrl使用方法汇总
    进度条的使用 Progress控件
    CListBOX 用法
    文件操作总结
    CString 十六进制转二进制
    Numpy常用数据结构、数据清洗函数、数据结构series和方法、数据结构dataframe和方法
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/1711725.html
Copyright © 2020-2023  润新知