Home  >  Article  >  php教程  >  Flex player (implementing playback, buffering progress bar and audio curve display)

Flex player (implementing playback, buffering progress bar and audio curve display)

高洛峰
高洛峰Original
2016-12-27 16:51:421403browse

I started playing with Flex on a whim. I originally wanted to make a Flex blog, but for now I can only make an announcement in it. . . There's no way to finish it, you're such a mess! Flex layout is not like CSS. Beautiful Flash animations are not created by dragging one or two controls, but by drawing them one stroke at a time! I'm not familiar with any of this yet. I've been working on it for almost a week, and I don't go to bed until I'm tired every day. Today I finally have a simple player.

I have always liked music. I like Jay and his songs even more. I also admire Xiaozhu. His piece of gray space once made me move forward. I thought I could make a podcast for myself to listen to. Songs out of narcissism will give you a little more satisfaction. Uh~ I got distracted. I accidentally saw the personal blogs of a group of teachers two days ago. I was deeply attracted by their blog posts. Whether they were talking about technology or recording life, the writing was so real and they insisted on blogging every day. Yes, persist and never give up...

mx:ProgressBar implements loading song buffer progress bar

ProgressBar has three major modes, namely event, manual, polled, and event is based on event-driven mode. The source object can be set to automatically display the loading process; manual is manual mode, you need to call the ProgressBar.setProgress() method to set the scroll bar progress; polled is polling mode, the manual mode used in this example, Sound loads the load request song to add a ProgressEvent.PROGRESS Listen to the event during processing, and then set the setProgress progress based on the number of bytes and bytesTotal that Sound has loaded. It should be noted here that when switching songs, the ProgressEvent.PROGRESS event must be removed first. Otherwise, when switching to load a new song before the previously played song has finished loading, the ProgressBar will trigger multiple PROGRESS events and the progress will scroll back and forth.

mx:HSlide adjusts the slider

This control is used in 2 places in this example to control the playback progress and sound volume. The problem of adjusting the playback progress stumped me for a long time at the beginning, because during the song playback process, HSlide needs to automatically slide the current playback position, and at the same time, it needs to be able to manually drag the playback position. HSlide originally has a good change event to detect. Listen to changes, but when I use a timer to set the value of HSlide, the change event is also triggered for me. I refer to the help document on Adobe's official website, which says that it is scheduled when the value of the Slider component changes due to mouse or keyboard interaction. If liveDragging If the property is true, the event will continue to be dispatched when the user moves the slider. If liveDragging is false, this event is dispatched when the user releases the slider. But no matter how I set it up, how can the change event be triggered when the value of HSlide is changed in the code? Doesn't it mean that it is scheduled when the value changes due to user interaction? What a shame, so I had to compromise by monitoring the thumbDrag event. Adobe explained that this event is scheduled when the slider is pressed and then moved with the mouse. There is a small problem, that is, the slider needs to be dragged. It will only be triggered when the stalk is pressed, and clicks will have no effect.

SoundMixer.computeSpectrum() analyzes the audio curve

In this example, the audio curve you see displayed is actually an arrangement of 64 Canvas controls drawn in strips on the right, and then a timer is used every time Reset their scaleY position every 100 milliseconds to show the effect of changing curves. The code is only three lines and is very simple. For details, please refer to the timerTick event given in my source code below. Why use a timer here? I saw on the Internet that others listen to the Event.ENTER_FRAME event and redraw the audio curve. If I don’t want to cause so much trouble, I just use a timer. I can calculate the song playback time based on bytesTotal and bytesLoaded. Using a 100 millisecond timer does not consume much site resources. , the CPU did not increase very high.

Rendering:

Flex player (implementing playback, buffering progress bar and audio curve display)

mxml code is as follows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" verticalGap="0" scroll="false" backgroundAlpha="0"
     horizontalScrollPolicy="off" verticalScrollPolicy="off" verticalAlign="middle" horizontalAlign="center"
     initialize="init(event)" layout="vertical" fontSize="14" paddingLeft="0" paddingTop="0" paddingRight="0" paddingBottom="0" >
    <mx:Script>
        <![CDATA[
            import mx.formatters.DateFormatter;
        
            import mx.effects.SoundEffect;
            import mx.events.SliderEvent;
            import mx.core.SoundAsset;
        
            import mx.controls.Alert;
            import mx.managers.CursorManager;
            import flash.media.*;
            
            import flash.utils.Timer;
            
            [Embed(source="images/cursor.gif")] 
            private var cursorHand : Class;//图标
            
            private var xml:XML; 
            private var xmlPath:String = "/flex/bin-debug/song.xml";
            private var currIndex : Number = 0; 
            
            private var song :Sound;
            private var channel :SoundChannel;
            private var position : Number = 0;
            // 保存 512 个声音波形的快照
            private var bytes:ByteArray = new ByteArray();
            // SoundBar 的个数
            private var barNum:uint = 64;
            // 保存所有 SoundBar 的引用
            private var soundBars:Array = new Array();
            
            //定时器
            private var timer : Timer;
            
            //Application的initialize初试化事件
            private function init(event:Event):void
            {
                var loader:URLLoader = new URLLoader(); 
                loader.load(new URLRequest(xmlPath)); 
                loader.addEventListener(Event.COMPLETE,Xml_Complete);
                
                timer = new Timer(100);
                timer.addEventListener(TimerEvent.TIMER,timerTick);
                
                var barWidth:Number = boxSoundBar.width*1.00/barNum;
                // 初始化Canvas为音频条,放入舞台并加入数组
                for (var i:uint = 0; i < barNum; i++)  {
                   var soundBar:Canvas = new Canvas();
                   soundBar.width = barWidth;
                   soundBar.height = boxSoundBar.height;
                   soundBar.x = i * barWidth;
                      soundBar.y =  0;
                   var g:Graphics = soundBar.graphics;
                   g.lineStyle(1,0x6688AA,1);
                   g.beginGradientFill(GradientType.RADIAL,[0x33cc00,0x456628],[1,1],[0,255],null,SpreadMethod.REFLECT,InterpolationMethod.RGB,0);
                   g.drawRect(0,0,soundBar.width,soundBar.height);
                   g.endFill();
                   boxSoundBar.addChild(soundBar);
                   soundBars.push(soundBar);
                }
                // 隐藏一些内建的鼠标右键菜单项
                this.contextMenu.hideBuiltInItems(); 
                var contextMenuItem : ContextMenuItem = new ContextMenuItem("Powered By: Jonllen");
                contextMenuItem.enabled = false;
                contextMenu.customItems.push(contextMenuItem);
                this.contextMenu.customItems.push(contextMenuItem);
                
                //更改鼠标图标
                CursorManager.setCursor(cursorHand);
            }
            
            //读取XML文件完成事件
            private function Xml_Complete(event:Event):void 
            {
                xml = new XML(event.target.data);
                if(xml.item.length()>=1)
                {
                    listSong.dataProvider= xml.item.name;
                    listSong.selectedIndex = 0;
                    //手动触发List的Change事件
                    listSong.dispatchEvent(new mx.events.ListEvent(Event.CHANGE, true, false));
                }
            }
            
            //List选择歌曲改变事件
            private function Xml_Change(event:Event):void
            {
                currIndex = event.target.selectedIndex;
                
                timer.stop();
                
                //停止声音文件的加载
                if( song!=null )
                {
                    //移除之前加载PROGRESS事件对songProgress进度条的控制
                    song.removeEventListener(ProgressEvent.PROGRESS,songProgress_Change);
                    if( song.isBuffering )
                        song.close();
                }
                
                song = new Sound();
                var url : String = xml.item[currIndex].url;
                var source:URLRequest = new URLRequest(url);
                song.load(source);
                song.addEventListener(ProgressEvent.PROGRESS, songProgress_Change);
                song.addEventListener(IOErrorEvent.IO_ERROR, songProgress_Error);
                
                position = 0;
                songStart();
            }
            
            //歌曲播放完成
            private function songProgress_Complete(e:Event):void {
                if(currIndex == xml.item.length()-1) {
                    currIndex = 0;
                }else {
                    currIndex++;
                }
                listSong.selectedIndex = currIndex;
                listSong.dispatchEvent(new mx.events.ListEvent(Event.CHANGE, true, false));
            }
            
            //加载歌曲失败
            private function songProgress_Error(e:IOErrorEvent):void {
                Alert.show("文件不存在!","系统提示");
            }
            
            //开始播放歌曲
            private function songStart():void {
                
                if ( channel != null ){
                    channel.stop();
                }
                
                lblName.text = xml.item[currIndex].name;
                channel = song.play(position,int.MAX_VALUE);
                
                var length :Number = song.length*song.bytesTotal/song.bytesLoaded;
                var date : Date = new Date();
                date.time = length;                
                var dt : DateFormatter = new DateFormatter();
                dt.formatString="NN:SS";
                var totalTime : String = dt.format(date);
                
                date.time = channel.position;
                lblTime.text = dt.format(date) + " | " + totalTime;
                lblStatus.text = "播放";
                
                var soundcontrol : SoundTransform = channel.soundTransform;
                soundcontrol.volume = volumeSlider.value;
                channel.soundTransform= soundcontrol;
                
                timer.start();
                boxSoundBar.visible = true;
            }
            
            //停止歌曲播放
            private function songStop():void {
                timer.stop();
                position = 0;
                boxSoundBar.visible = false;
                lblTime.text = "00:00 |"+lblTime.text.split("|")[1];
                lblStatus.text = "停止";
                songSlider.value = songSlider.minimum;
                songProgress.setProgress(songProgress.minimum,songProgress.maximum);
                if ( channel != null )
                {
                    channel.stop();
                }
            }
            
            //暂停歌曲播放
            private function songPause():void {
                if ( channel != null ){
                    timer.stop();
                    position = channel.position;
                    channel.stop();
                    lblStatus.text = "暂停";
                }
            }
            
            //加载歌曲进度条显示
            private function songProgress_Change(e:ProgressEvent):void {
                var percent:int = Math.round(e.bytesLoaded * 100 / e.bytesTotal);
                songProgress.setProgress(e.bytesLoaded,e.bytesTotal);
            }
            
            //定时器方法
            private function timerTick( e:TimerEvent):void {
                
                if( channel!=null) {
                    
                    var length :Number = song.length*song.bytesTotal/song.bytesLoaded;
                    var date : Date = new Date();
                    date.time = length;                
                    var dt : DateFormatter = new DateFormatter();
                    dt.formatString="NN:SS";
                    var totalTime : String = dt.format(date);
                    
                    date.time = channel.position;
                    lblTime.text = dt.format(date) + " | " + totalTime;
                    
                    songSlider.value=100*channel.position/length;
                    if( songSlider.value>=songSlider.maximum){
                        timer.stop();
                        songProgress_Complete(null);
                        return;
                    }
                    
                    SoundMixer.computeSpectrum(bytes, false, 0);
                    for (var i:uint = 0; i < barNum; i++)  {
                       soundBars[i].scaleY = bytes.readFloat();
                    }
                    
                }
            }
            
            //歌曲进度调整事件
            internal function songSlider_Change(e:SliderEvent):void{
                timer.stop();
                if ( channel != null ){
                    var length :Number = song.length*song.bytesTotal/song.bytesLoaded;
                    position = e.value*length/100;
                    songStart();
                }
            }
            
            //声音大小调整事件
            internal function changeVolume(evt:SliderEvent):void{
                if ( channel != null ){
                    var soundcontrol : SoundTransform = channel.soundTransform;
                    soundcontrol.volume = evt.value;
                    channel.soundTransform= soundcontrol;
                }
            }
            
            //设置歌曲播放时间和总时间
            private function setTimeStatus():void {
                var length :Number = song.length*song.bytesTotal/song.bytesLoaded;
                var date : Date = new Date();
                date.time = length;                
                var dt : DateFormatter = new DateFormatter();
                dt.formatString="NN:SS";
                var totalTime : String = dt.format(date);
                
                date.time = channel.position;
                lblTime.text = dt.format(date) + " | " + totalTime;
            }
            
        ]]>
    </mx:Script>
    <mx:HBox width="100%" verticalGap="0" verticalAlign="middle" horizontalAlign="center">
        <mx:Canvas width="440" borderColor="#CCCCCC" borderStyle="solid" height="171">
            <mx:Label id="lblName" x="5" fontSize="18" y="10" text=""/>
            <mx:HBox id="boxSoundBar" horizontalGap="0" verticalAlign="middle"
                 width="192" height="50" x="5" y="39" visible="false"></mx:HBox>
            <mx:ProgressBar id="songProgress" label="" 
                width="290" height="3" mode="manual" textAlign="left" 
                labelPlacement="center" fontSize="3" x="10" y="97" 
                minimum="0" maximum="100" barColor="yellow"
                trackColors="[white, haloSilver]"/>
            <mx:HSlider id="songSlider" styleName="song" value="0"
                 showTrackHighlight="true" x="5" y="85" thumbDrag="songSlider_Change(event)"
                 width="300" height="22" minimum="0" maximum="100" 
                 liveDragging="false" snapInterval="1"  toolTip="拖动调整播放进度">
            </mx:HSlider>
            <mx:Label id="lblStatus" x="243" y="41" text=""/>
            <mx:Label id="lblTime" x="205" y="66" text="00:00 | 5:23"/>
            <mx:Button x="10" y="124" label="Play" click="songStart()"/>
            <mx:Button x="74" y="124" label="Pause" click="songPause()"/>
            <mx:Button x="152" y="124" label="Stop" click="songStop()"/>
            <mx:HSlider id="volumeSlider" styleName="volume" change="changeVolume(event)"
                 showTrackHighlight="true" value="0.5" x="222" y="133"
                  width="81" minimum="0" maximum="10" liveDragging="true"
                   snapInterval="0.1" toolTip="音量调节" />
            <mx:Label x="308" fontSize="18" y="10" text="歌曲列表"/>
            <mx:List id="listSong" alpha="0.25" x="308" y="43" height="116"
                 change="Xml_Change(event)" width="130" toolTip="点击选择歌曲"></mx:List>
        </mx:Canvas>
    </mx:HBox>
</mx:Application>

More Flex players (implementing playback, buffering progress bars and audio curves Display) Please pay attention to the PHP Chinese website for related articles!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn