ActionScript3 使用sound类 下篇

本文详细介绍了使用ActionScript 3处理声音的方法,包括创建进度条显示声音文件的加载和播放状态、读取MP3文件的ID3信息、实现自动播放下一首的功能、计算播放进度、以及实现播放暂停功能。
相关 ActionScript3 使用sound类 上篇
问题六

       我们想创建一个声音文件加载情况的进度条,这就要求我们能获取文件的大小,及已经下载了多少了。

解决方法
      访问sound对象的bytesTotal 和bytesLoaded属性。
对于流式的音频文件,让用户知道目前已经下载了多少数据是个不错的想法。理想情况是:声音文件的下载速度比播放速度快,这样就不会在播放的时候暂停。但是,在不稳定的网络和带宽比较窄的情况下,如果声音文件的编码率比较高,就很难保证缓冲区里总是非空的,也就很难保证不会出现暂停。

       因此,用进度条来向用户展示目前声音的加载和播放情况是一个不错的选择。你也许看过很多流媒体播放器的进度条,比如Windows Media Player或QuickTime Player。通常,会有一个进度条表示音乐的播放进度,进度条的背景色是白色的,前景有一个黑色的进度条表示目前播放的位置,另外,还有一个灰色的进度条表示目前缓冲区的情况。当灰色的进度条(缓冲buffer)比黑色的进度条(当前播放位置play position)长的时候,我们知道文件播放很流畅;当黑色的进度条赶上灰色的进度条的时候,媒体会停止播放,灰色进度条继续变长,继续向缓冲区加载数据,当它足够长的时候,媒体会继续播放,黑色进度条会继续移动,这时灰色进度条就有希望一直领先了。

  本文教你如何实现创建上面提到的灰色进度条和白色背景(以后我们将学习如何创建黑色进度条),要用到声音对象的两个属性bytesTotal 和bytesLoaded,这些属性的含义相当明了:bytesTotal 包含mp3文件总长度的信息,bytesLoaded包含当前已经下载了多少数据的信息。有了这两个值,我们就有了数据下载的百分比。

下面的例子设定了enterFrame的处理函数,让影片每播放一帧就重新计算当前下载百分比,然后根据这个绘制进度条。

package {   
                  import flash.display.Sprite;   
                  import flash.media.Sound;  
                  import flash.net.URLRequest;   
                  import flash.events.Event;
   public class ProgressBar extends Sprite {      
                          private var _sound:Sound;

  public function ProgressBar(  ) {            
                   addEventListener(Event.ENTER_FRAME, onEnterFrame);           
                    _sound = new Sound(new URLRequest("song.mp3"));         
                     _sound.play(  );      
                }
public function onEnterFrame(event:Event):void{           
                    var barWidth:int = 200;            
                    var barHeight:int = 5;           
                    var loaded:int = _sound.bytesLoaded;         
                    var total:int = _sound.bytesTotal;
          if(total > 0) {               
                   // 绘制白背景               
              graphics.clear(  );               
                     graphics.beginFill(0xFFFFFF);              
                     graphics.drawRect(10, 10, barWidth, barHeight);               
                     graphics.endFill(  );               
                  // 已经加载数据的百分比               
              var percent:Number = loaded / total;               
                // Draw a bar that represents the percent of               
                // the sound that has loaded               
                    graphics.beginFill(0xCCCCCC);               
                    graphics.drawRect(10, 10,barWidth * percent, barHeight);               
                    graphics.endFill(  );         
                         }      
               }  
        }  
  }
       如果我们把声音文件放在本地机器上进行测试,可能会看不到灰色进度条慢慢增长的效果,它会一下子变成100%,如果可能,把文件放在网络上进行测试,这样你就能看到效果了。注意:当你第二次或后面测试的时候,请清空浏览器的缓存,否则,会和在本地机器上测试的效果一样。



问题七

我们现在想获取正在播放的MP3文件的一些相关信息,比如:艺术家、音乐集、风格, 等。

解决方案

读取sound对象的id3属性

MP3文件中可以包含很多关于声音文件的一些数据,这些数据通常包含艺术家、音乐集、发行时间、作曲家、等。包含信息的多少取决于制作或为这个音乐添加标签的人。在绝大多数情况下,我们至少可以从中获取歌曲名和艺术家的标签。

这些数据是我们用ActionScript通过访问sound对象的id3属性来得到的。
这些属性是flash.media.ID3Info 类的实例,它包含下面的一些具体属性:


album

artist

comment

genre

songName

TRack

year

所以要想知道音乐的名字,你可以这样做:


_sound.id3.songName


上面只是一个例子,注意:我们不能在音乐还没有真正下载到swf文件中就去获取这些信息。如果想在声音文件刚刚创建完毕或者刚刚开始播放就获取这些信息,将是不成功的。因为那时声音文件的具体信息还没下载到swf文件中,所以此时没有相关数据可用。


我们如何知道知道声音文件的id3相关数据已经到达swf文件中了呢?幸运的是,sound对象有个ID3事件可供我们侦听,这个事件发生了,就表明可以安全地读取id3数据了。Sound对象继承了EventDispatcher类,因此我们可以用事件侦听函数来侦听这个事件(这个事件被定义为flash.events.Event.ID3),然后添加一个事件处理函数,来读取id3的信息。


下面的例子创建了一个文本框,并在其中列出了id3的所有信息

package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.net.URLRequest;
    import flash.events.Event;
    import flash.text.TextField;
   
    public class ID3Reader extends Sprite {
        private var _sound:Sound;
        
        public function ID3Reader (  ) {
            _sound = new Sound(new URLRequest("song.mp3"));
            _sound.addEventListener(Event.ID3, onID3);
            _sound.play(  );
        }
        
        public function onID3(event:Event):void {
            // Create a text field and display it
            var id3Display:TextField = new TextField(  );
            addChild(id3Display);
            id3Display.x = 10;
            id3Display.y = 20;
            id3Display.width = 200;
            id3Display.height = 200;
            id3Display.background = true;
            id3Display.multiline = true;
            id3Display.wordWrap = true;

            // Add some info about the song to the text field
            id3Display.text += _sound.id3.songName + "/n";
            id3Display.text += _sound.id3.artist + "/n";
            id3Display.text += _sound.id3.album + "/n";
            id3Display.text += _sound.id3.year + "/n";  
        }
}
}

译者注:上面的这个例子的使用方法:

1,  新建立一个fla文件,命名,保存;

2,  找一首歌曲(mp3格式)复制到fla的那个目录里面,命名为song.mp3(mp3是后缀名);

3,  新建一个.as文件,把上述代码复制到其中,保存为ID3Reader.as保存在fla同一个目录;

4,  把fla文件的document属性(选中舞台,打开属性面板就能看到)设置为ID3Reader;

5,  按ctrl+enter测试。






问题八

       当我们播放音乐以后,想知道声音何时播放结束。(成业注:当我们播放完一首歌曲后想播放器自动切换到下一首,这时就需要音乐播放结束的消息)

解决方法
          侦听soundComplete事件

  有很多时候我们需要知道音乐在什么时候播放结束。比如:在正式的内容开始之前,我们想让用户先听完一段介绍,那么就需要获取介绍是否播放结束的信息;再比如:有个带索音乐列表的播放器,当一首歌播放完毕之后要自动切换到下一首,就需要获取当前的歌是否已经播放结束。

       这一节中我们开始讨论另外一个类,它叫做flash.media.SoundChannel。当我们调用sound对象的play()方法的时候,它返回一个SoundChannel对象。各种声音在swf文件中播放都有唯一的一个SoundChannel对象代表,所有的这些SoundChannel混合在一起构成了最终的音频输出。

       当一个声音文件播放结束的时候,和它绑定的SoundChannel对象将引发一个soundComplete事件,它被定义为:flash.events.Event.SOUND_COMPLETE.我们可以为SoundChannel对象的SOUND_COMPLETE事件添加一个事件处理函数,处理当声音播放结束的时候,程序干什么。



       下面的例子演示了一个简单的播放列表(a simple playlist)

package {   
          import flash.display.Sprite;   
           import flash.media.Sound;   
           import flash.net.URLRequest;  
           import flash.events.Event;   
           import flash.media.SoundChannel;   
public class PlayList extends Sprite {      
           private var _sound:Sound;      
           private var _channel:SoundChannel;      
           private var _playList:Array;     
         //歌曲列表      
       private var _index:int = 0;      
         //当前歌曲
      public function PlayList(  ) {           
        //创建歌曲列表并开始播放            
        _playList = ["song1.mp3",                       
                            "song2.mp3",                       
                             "song3.mp3"];           
         playNextSong(  );      
     }        
private function playNextSong(  ):void{            
                         //如果列表中还有歌曲的话           
            if(_index < _playList.length) {               
                        //创建一个新的Sound对象,加载并播放之               
                // 数组_playList[_index]包含了要播放的下一首歌歌名及路径               
                _sound = new Sound(  );               
                        _sound.load(new URLRequest(_playList[_index]));              
                        _channel = _sound.play(  );               
                       // 为_channel添加事件侦听处理函数               
               _channel.addEventListener(Event.SOUND_COMPLETE,onComplete);
                               // 计数器加1               
                               _index++;           
              }        
      }        
        public function onComplete(event:Event):void{            
playNextSong(  );      
             }   
        }   
}
这里,变量index从0开始计数,它将导致_playList[index]值变成为"song.mp3",这样第一个加载的歌曲是"song.mp3"。然后,index的值增加了,当soundComplete事件被引发,playNextSong()方法加载了_playList里的下一首歌,直到index的值比列表里的歌曲还大为止。

译者注:上面的这个例子的使用方法:

1,新建立一个fla文件,命名,保存;

2,找三首歌曲(mp3格式)复制到fla的那个目录里面,命名为song1.mp3,song2.mp3,song3.mp3(mp3是后缀名);

3,新建一个.as文件,把上述代码复制到其中,保存在fla同一个目录,命名为PlayList.as;

4,把fla文件的document class属性(选中舞台,打开属性面板就能看到)设置为PlayList;

5,按ctrl+enter测试。我们将依次听到上面的三首歌





问题九

    我们想知道当前的歌曲已经播放了百分之几(意译)

解决方法

    用Sound.length获取声音文件的长度,用SoundChannel.position获取当前播放了多少。



       问题六ActionScript3 使用sound类——获取文件大小中,我们提到了如何添加一个不仅显示下载进度还显示播放进度的进度条,那一节中学习了创建显示下载进度的部分。



       本节讨论另外一个部分:如何跟踪播放进度。为了实现这个目标,我们必须知道两个量:当前文件播放位置是多少和文件总长度。虽然它们看起来差不多,但是它们却在不同的类中,文件长度信息是sound对象的一个属性,当前播放位置在SoundChannel类中。类似于问题六[原创]ActionScript3 使用sound类(e文翻译)——获取文件大小中创建已下载进度条一样,有这两个量很容易得到播放进度条。



    不幸的是,播放进度条做起来比下载进度条要复杂,因为声音文件的总长度要等到声音文件全部下载完毕之后才能得到,此时读取文件长度只是得到了已经下载的声音文件的长度。因此,比如:以个十分钟的音乐,下载了10%,它的长度(length)是一分钟。(事实上,length和position都返回毫秒为单位的数据,如果需要,我们也可以把它转换成“分:秒”的表示形式)



       幸运的是,我们只要经过一点小小的数学运算就能得到文件的总长度(毫秒),我们拿当前文件的长度(毫秒)除以当前已经下载下来的百分比,结果将非常接近文件的实际长度(毫秒)。说一下刚刚提到的例子:长度返回值是1分钟,这个一分钟是指已经下载的文件长度。当我们拿这个一分钟除以1/10,就能得到结果是10,这样我们就得到了文件的总长度是10分钟。



上面提到的百分比是用bytesLoaded/bytesTotal得到的,这个值是我们在做下载进度条时候用过并存起来的,所以所以文件总长度只要一行代码就能实现了:

length /= percentBuffered;

说明:问题六[原创]ActionScript3 使用sound类——获取文件大小中,我们提到了要想正确显示进度条要清空缓存的问题,在此不再重复。下面的代码展示了如何把两个进度条放在一起:

package {   
               import flash.display.Sprite;   
               import flash.media.Sound;   
               import flash.media.SoundChannel;   
               import flash.net.URLRequest;   
               import flash.events.Event;
public class ProgressBar2 extends Sprite {      
               private var _sound:Sound;        
              private var _channel:SoundChannel;              
public function ProgressBar2(  ) {           
               addEventListener(Event.ENTER_FRAME, onEnterFrame);           
             _sound = new Sound(new URLRequest("song.mp3"));           
             _channel = _sound.play(  );      
}        
public function onEnterFrame(event:Event):void{           
             var barWidth:int = 200;            
             var barHeight:int = 5;                       
             var loaded:int = _sound.bytesLoaded;           
             var total:int = _sound.bytesTotal;            
             var length:int = _sound.length;            
             var position:int = _channel.position;           
         // Draw a background bar
            graphics.clear(  );           
            graphics.beginFill(0xFFFFFF);            
graphics.drawRect(10, 10, barWidth, barHeight);           
                    graphics.endFill(  );
          if(total > 0) {
                // The percent of the sound that has loaded
                var percentBuffered:Number = loaded / total;
                // Draw a bar that represents the percent of
                // the sound that has loaded
                graphics.beginFill(0xCCCCCC);               
graphics.drawRect(10, 10,barWidth * percentBuffered,  barHeight);
                graphics.endFill(  );
                 // Correct the sound length calculation
                length /= percentBuffered;               
                  // The percent of the sound that has played
                  var percentPlayed:Number = position / length;
                // Draw a bar that represents the percent of
                // the sound that has played
                graphics.beginFill(0x666666);               
graphics.drawRect(10, 10, barWidth * percentPlayed, barHeight);               
                graphics.endFill(  );
            }
        }
    }   
}
译者注:上面的这个例子的使用方法:

1,新建立一个fla文件,命名,保存;

2,找首歌曲(mp3格式)复制到fla的那个目录里面,命名为song.mp3(mp3是后缀名);

3,新建一个.as文件,把上述代码复制到其中,保存在fla同一个目录,命名为ProgressBar2.as;

4,把fla文件的document class属性(选中舞台,打开属性面板就能看到)设置为ProgressBar2,设置背景颜色为兰色(只要不是白色黑色灰色就行);

5,按ctrl+enter测试。我们看到效果。

如果看不到加载进度,请换个网络上的歌曲试试看。





问题十

    如何暂停声音,如何从暂停的地方继续播放声音。

解决方法

    通过记录当前声音的SoundChannel的position属性值,继续播放时用刚刚的值恢复一下。

具体讨论

       在问题二中提到了sound对象的close()方法,它可以用来停止一个声音文件的播放,但是,同时它也停止了声音文件的加载,当重新播放的时候,我们必须重新调用load()方法。

      

       幸运的是,SoundChannel类提供了一个stop()方法,它可以使声音文件停止播放而不停止加载,当再次播放音乐的时候,只要调用play()方法就可以了。

      

       我们应该记住:不管什么时候只要是使用play()方法都是从文件开头进行播放的,这相当于播放器中的“STOP■”按钮。创建一个“PAUSE‖”按钮稍微有点麻烦。解决的策略是:当按下按钮的时候调用一个事件处理函数:这个函数从SoundChannel中读取当前的position数据并把它保存起来,它提供了声音文件已经播放了多少毫秒。把这个量保存为类级别的,以便后面调用。此时,“PAUSE‖”按钮变成“PLAY”按钮,当再次被按下的时候,调用sound对象的play()方法,通过刚才保存的位置信息,就能恢复到刚才停下来的那地方继续播放,下面给出例程:

      

package {
    import flash.display.Sprite;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.net.URLRequest;
    import flash.events.Event;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
   
    public class PlayPause extends Sprite {
        private var _sound:Sound;
        private var _channel:SoundChannel;
        private var _playPauseButton:Sprite;
        private var _playing:Boolean = false;
        private var _position:int;
        
        public function PlayPause(  ) {
            // 创建一个声音对象,并播放之
            _sound = new Sound(new URLRequest("song.mp3"));
            _channel = _sound.play(  );
            _playing = true;

            //一个作为Play/Pause按钮的sprite
            _playPauseButton = new Sprite(  );
            addChild(_playPauseButton);
            _playPauseButton.x = 10;
            _playPauseButton.y = 20;
            _playPauseButton.graphics.beginFill(0xcccccc);
            _playPauseButton.graphics.drawRect(0, 0, 20, 20);
            _playPauseButton.addEventListener(MouseEvent.MOUSE_UP,
                                             onPlayPause);
        }
        
        public function onPlayPause(event:MouseEvent):void {
            // 如果正在播放,停止,记下当前位置信息
            if(_playing) {
                   _position = _channel.position;
                   _channel.stop(  );
            }
            else {
                // 如果未播放,从记录处开始播放
                //
                _channel = _sound.play(_position);
            }
               _playing = !_playing;
        }
    }
}
以上代码创建了一个sprite图像作为按钮,为其鼠标抬起事件添加了事件处理函数,如果当前声音正在播放,则停止当前播放,并记录当前位置,如果当前已经停止,则从刚才记录的位置开始播放。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值