As3音乐播放器教程

作者: dymkkk

性质: 原创

阅读次数: 10514

发表时间: 2010-02-02 09:14:21


2009年的最后一天了,送ws的朋友们一个播放器吧!貌似很有记念意义。按惯例先看一下最终效果:呵呵,界面是我自己在ps中画的,感觉也不是很丑。


 

 

 

源文件下载

那么开始吧!大家先下载一下源文件。对着源文件的结构看教程。我将整个播放器做到一个元件中(Control_panel),再给它绑定一个类(sound_lib.Control_panel),所有的代码就写在这个类里面了。这样做的好处是:日后要用到它时,直接把Control_panel元件拖到你要用的地方就Ok了!
接下来就是code了:要做音乐播放器,最重要的两个类当然就是Sound和SoundChannel。
先试一下,怎样让一首mp3播放起来:

 

//建立一个Sound类
sound=new Sound()
//加载mp3文件
sound.load(new URLRequest(“你的mp3路径”))
//播放
sound.play()

Ok了!
完整代码:

 

package sound_lib{
	import flash.display.*
	import flash.media.Sound
	import flash.media.SoundChannel
	import flash.net.URLRequest
	public class Control_panel extends MovieClip{
		private var sound:Sound
		private const sound_url:String="sound_data/m01.mp3"
		public function Control_panel(){
			init()
		}
		private function init(){
			sound_init()
		}
		function sound_init(){
			sound=new Sound()
			sound.load(new URLRequest(sound_url))
			sound.play()
		}
	}
}

Ctrl+Enter一下。是不是听到音乐了?啊?没听到?看看sound_data目录下是否放了mp3文件没?如果一切正常的话,你现在应该在享受你的音乐了。
呵呵。不过别忘了大多数播放器是要用在web上的。有时候声音播放的速度可能比下载的速度还要快,这种情况下声音播放就会暂停等待数据下载,为了更好的处理这个环节,我们可以设置一个数据缓冲区,当声音数据下载到一定数量时再进行播放,这样的话即使下载速度偶尔变慢也不会影响正常播放。默认下Sound对象只创建1秒钟的缓冲,也就是说要想立即播放也需要等待1秒钟的缓冲,缓冲区的数据播放完后要想再次播放还要至少等1秒钟缓冲时间。显然如果网速较慢的话且缓冲为1秒时,在这种情况下音乐的播放将会给人很”卡”的感觉。所以我们必需手动设置一下缓冲:
设置缓冲需要用到SoundLoaderContext类:建立一个SoundLoaderContext对象,然后设置它的bufferTime属性就行了。最后将SoundLoaderContext对象传给sound对象的load()方法的参数就行了。

code
//建立一个SoundLoaderContext类,设置bufferTime为5秒
var buffer:SoundLoaderContext=new SoundLoaderContext(5000)
sound=new Sound()
sound.load(new URLRequest(sound_url),buffer)
sound.play()
:
声音的暂停与回放
这样,即使放到web上也不成问题了。不过现在只是能正常播放了,我们还得控制它才行嘛!最常见的控制就是暂停与回放了。声音的暂停与回放不像视频流那样,可以直接pause和resume来操作。看看Soun类,大家可能会调用Sound对象的close( )方法可以停止播放,但是这样也停止了声音流,要想重新播放,必须再次调用load( )方法。这显然不是我们想要的。这里我们终于要用到上面所提到的SoundChannel了,其实对音频的绝大多数操作都是SoundChannel类来完成的。SoundChannel的stop()方法可以让音乐暂停而不影响声音流的中断。于是我们可以用SoundChannel对象的stop()方法与Sound对象的play()方法来暂停与回流音频流。但是,当再次调用play( )方法时,音乐会从头开始播放而不是从暂停的地方开始,这个时候就要用到SoundChannel类的position属性了:position属性是用来记录音乐播放头的。我们可以在暂停时,记录下position的值,然后再次调play()时,将它传给play()方法的参数。这样就达到了最终目:
code:
sound_channel.stop()
//记录position属性
position=sound_channel.position
sound_channel=sound.play(position)
完整代码:
package sound_lib{
	import flash.display.*
	import flash.media.Sound
	import flash.media.SoundChannel
	import flash.media.SoundLoaderContext
	import flash.events.*
	import flash.net.URLRequest
	public class Control_panel extends MovieClip{
		private var sound:Sound
		private const sound_url:String="sound_data/m01.mp3"
		private var sound_channel:SoundChannel
		private var position:int
		private var is_play:Boolean
		public function Control_panel(){
			addEventListener(Event.ADDED_TO_STAGE,add_to_stage)
		}
		private function add_to_stage(_evt:Event):void{
			init()
		}
		private function init(){
			sound_init()
			control_init()
		}
		//==================sound part====================//
		function sound_init(){
			var buffer:SoundLoaderContext=new SoundLoaderContext(5000)
			sound=new Sound()
			sound.load(new URLRequest(sound_url),buffer)
			sound_channel=sound.play()
			is_play=true
			play_mc.visible=false
		}
		//===================control part=================//
		function control_init(){
			pause_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
			play_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
		}
		private function is_play_Handler(_evt:MouseEvent):void{
			if(is_play){
				is_play=false
				position=sound_channel.position
				sound_channel.stop()
				play_mc.visible=true
				pause_mc.visible=false
			}else{
				is_play=true
				sound_channel=sound.play(position)
				play_mc.visible=false
				pause_mc.visible=true
			}
		}
	}
}
Ctrl+Enter一下。Ok了吧?
跟踪声音的加载进度与播放进度
要得到声音的加载进度是很简单的,Sound类本身有bytesLoaded属性与bytesTotal属性。只要在progress事件中监测到这个属性值就Ok了具体操作如下:
private function sound_loading_Handler(_evt:ProgressEvent):void{
	var loaded_per=Math.ceil(100*_evt.bytesLoaded/_evt.bytesTotal)/100
	scroll_bar.loading_bar.scaleX=loaded_per
}
// loaded_per就是加载进度的百分比了,简单吧!
不过用户肯定不满足于只看到加载进度,他们更希望能看到声音的播放进度并能控制播放进度。要得到播进度,必须知道两个值:音乐的长度和当前的播放位置。这两个属性分别在两不同的类里。长度属性在sound类里,播放位置在SoundChannel类里,这两个值相除就是播放进度百分比。呵呵,就这么简单!不过好像高兴得有点早了:sound类的length属性是不确定的,直到声音被下载完才确定,也就说它只表示已经被下载的那部分数据的长度,举个例子说,如果一个10分钟的音乐已下载了10%,那么length报告歌曲长度为1分钟(length和position的单位都是毫秒)。不过从我上面的例子不难看出,只要长度除以加载进度百分比即可算出实际长度即sound_length/loaded_per。
嗯原理搞清楚了就来试试吧:
code:
	var loaded=sound.bytesLoaded
	var total=sound.bytesTotal
	sound_length=sound.length
	if(total>0){
		var loaded_per=loaded/total
		scroll_bar.loading_bar.scaleX=loaded_per
		sound_length=length/loaded_per
		position=sound_channel.position
		var played_per=position/sound_length
	}
好了。跟据以上思路再整理一下你的code:
package sound_lib{
	import flash.display.*
	import flash.media.Sound
	import flash.media.SoundChannel
	import flash.media.SoundLoaderContext
	import flash.events.*
	import flash.net.URLRequest
	public class Control_panel extends MovieClip{
		private var sound:Sound
		private const sound_url:String="sound_data/m01.mp3"
		private var sound_channel:SoundChannel
		private var position:int
		private var sound_length
		private var is_play:Boolean
		private var loadEnd:Boolean=false
		public function Control_panel(){
			addEventListener(Event.ADDED_TO_STAGE,add_to_stage)
		}
		private function add_to_stage(_evt:Event):void{
			init()
		}
		private function init(){
			sound_init()
			control_init()
		}
		//==================sound part====================//
		function sound_init(){
			var buffer:SoundLoaderContext=new SoundLoaderContext(5000)
			sound=new Sound()
			sound.load(new URLRequest(sound_url),buffer)
			sound_channel=sound.play()
			sound.addEventListener(ProgressEvent.PROGRESS,sound_loading_Handler)
			is_play=true
			play_mc.visible=false
		}
		//===================control part=================//
		function control_init(){
			pause_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
			play_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
			addEventListener(Event.ENTER_FRAME,progress_Handler)
		}
		private function is_play_Handler(_evt:MouseEvent):void{
			if(is_play){
				is_play=false
				position=sound_channel.position
				sound_channel.stop()
				play_mc.visible=true
				pause_mc.visible=false
			}else{
				is_play=true
				sound_channel=sound.play(position)
				play_mc.visible=false
				pause_mc.visible=true
			}
		}
		private function sound_loading_Handler(_evt:ProgressEvent):void{
			var loaded_per=Math.ceil(100*_evt.bytesLoaded/_evt.bytesTotal)/100
			if(loaded_per>=100) loadEnd=true
			scroll_bar.loading_bar.scaleX=loaded_per
		}
		private function progress_Handler(_evt:Event):void{
			var loaded=sound.bytesLoaded
			var total=sound.bytesTotal
			sound_length=sound.length
			if(total>0){
				var loaded_per=loaded/total
				if(loaded_per>=1) loadEnd=true
				scroll_bar.loading_bar.scaleX=loaded_per
				sound_length=sound_length/loaded_per
				position=sound_channel.position
				var played_per=position/sound_length
				scroll_bar.dragger.x=(scroll_bar.scroll_bg.width-scroll_bar.dragger.width)*played_per
			}
		}
	}
}
呼。。。我是不是讲得太啰嗦了?继续吧。
这才只能让用户看到播放进度而以。下面我们还要让用户能控制它。要控制它用到了我们常见的滚动条。由于滚动条是我们很常用的东东,所以我把它写成了一个类。(Sound_lib/Scroll_bar.as),类很简单,如果看不懂的话,可以参考控制音量的滚动条。其实这里用Scroll_bar.as不大合适,不过我还是想偷一下懒!
说到这里,怎么定位播放头呢?想想“声音的暂停与回放”是怎么做的,我们就可以得找出办法了用sound.play(position)。Position的值就更容易得到了: sound_length* per。但是这里值得注意的是play()之前要把之前的sound_channel 停止,要不就出现多重声音了。。。OK了。再跟据以上思路完善一下你的code吧!
package sound_lib{
	import flash.display.*
	import flash.media.Sound
	import flash.media.SoundChannel
	import flash.media.SoundLoaderContext
	import flash.events.*
	import flash.net.URLRequest
	public class Control_panel extends MovieClip{
		private var sound:Sound
		private const sound_url:String="sound_data/m01.mp3"
		private var sound_channel:SoundChannel
		private var position:int
		private var sound_length
		private var is_play:Boolean
		private var loadEnd:Boolean=false
		public function Control_panel(){
			addEventListener(Event.ADDED_TO_STAGE,add_to_stage)
		}
		private function add_to_stage(_evt:Event):void{
			init()
		}
		private function init(){
			sound_init()
			control_init()
		}
		//==================sound part====================//
		function sound_init(){
			var buffer:SoundLoaderContext=new SoundLoaderContext(5000)
			sound=new Sound()
			sound.load(new URLRequest(sound_url),buffer)
			sound_channel=sound.play()
			sound.addEventListener(ProgressEvent.PROGRESS,sound_loading_Handler)
			is_play=true
			play_mc.visible=false
		}
		//===================control part=================//
		function control_init(){
			pause_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
			play_mc._btn.addEventListener(MouseEvent.CLICK,is_play_Handler)
			addEventListener(Event.ENTER_FRAME,progress_Handler)
		}
		private function is_play_Handler(_evt:MouseEvent):void{
			if(is_play){
				is_play=false
				position=sound_channel.position
				sound_channel.stop()
				play_mc.visible=true
				pause_mc.visible=false
			}else{
				is_play=true
				sound_channel=sound.play(position)
				play_mc.visible=false
				pause_mc.visible=true
			}
		}
		private function sound_loading_Handler(_evt:ProgressEvent):void{
			var loaded_per=Math.ceil(100*_evt.bytesLoaded/_evt.bytesTotal)/100
			if(loaded_per>=100) loadEnd=true
			scroll_bar.loading_bar.scaleX=loaded_per
		}
		private function progress_Handler(_evt:Event):void{
			var loaded=sound.bytesLoaded
			var total=sound.bytesTotal
			sound_length=sound.length
			if(total>0){
				var loaded_per=loaded/total
				if(loaded_per>=1) loadEnd=true
				scroll_bar.loading_bar.scaleX=loaded_per
				sound_length=sound_length/loaded_per
				position=sound_channel.position
				var played_per=position/sound_length
				scroll_bar.dragger.x=(scroll_bar.scroll_bg.width-scroll_bar.dragger.width)*played_per
			}
		}
	}
}
Ctrl+Enter一下!再拖动一下滑块,别拖到音量骨块上去哦。呵呵。。。
 
音量的控制
要改调节音量需用到SoundChannel对象的soundTransform属性,它是SoundTransform的类实例。操用步骤:1.建立一个soundTransform对象。2.设置soundTransform对象的volume值(0-1)3.将soundTransform对象赋给SoundChannel的soundTransform属性属性。为了方便我将其写成函数
function set_volume(temp:SoundChannel,temp_value:Number){
	var sound_trf:SoundTransform=new SoundTransform()
	sound_trf.volume=temp_value
	temp.soundTransform=sound_trf
}
再看一下控制音量的滑块。也写成了一个类(sound_lib/Vol_scroll_bar.as)
package sound_lib{
	import flash.display.*
	import flash.events.*
	import flash.geom.*
	public class Vol_scroll_bar extends MovieClip{
		public static const SCROLL:String="scroll"
		public var per
		public function Vol_scroll_bar(){
			this.addEventListener(Event.ADDED_TO_STAGE,add_to_stage)
		}
		private function add_to_stage(_evt:Event):void{
			init()
		}
		private function init(){
			dragger._btn.addEventListener(MouseEvent.MOUSE_DOWN,press_Handler)
			dragger._btn.addEventListener(MouseEvent.MOUSE_UP,release_Handler)
		}
		private function press_Handler(_evt:MouseEvent):void{
			dragger.startDrag(false,new Rectangle(scroll_bg.x,scroll_bg.y,scroll_bg.width-dragger.width,0))
			scroll_bg.addEventListener(Event.ENTER_FRAME,move_Handler)
			stage.addEventListener(MouseEvent.MOUSE_UP,release_Handler)
		}
		private function release_Handler(_evt:MouseEvent):void{
			dragger.stopDrag()
			scroll_bg.removeEventListener(Event.ENTER_FRAME,move_Handler)
			stage.removeEventListener(MouseEvent.MOUSE_UP,release_Handler)
		}
		private function move_Handler(_evt:Event):void{
			per=Math.ceil(100*dragger.x/(scroll_bg.width-dragger.width))/100
			this.dispatchEvent(new Event(SCROLL))
		}
	}
}
该类就公开了一个属性per(百分比)那么怎么实时获取per呢?
看到this.dispatchEvent(new Event(SCROLL))这句没?在拖动滑块的同时给该类加入了一个事件,所以我们只需在父类中贞听这个事件就可以了:
private function Vol_scroll_init(){
			vol_scroll_bar.addEventListener(Vol_scroll_bar.SCROLL,get_per_Handler)
		}
		private function get_per_Handler(_evt):void{
			trace(vol_scroll_bar.per)
		}
Ctrl+Enter一下!拖动滑块(别拖错了哦)查看trace出来的值。这到里你应该明天怎么做了吧:再结合上面给出的调节音量的函数。
 
private function Vol_scroll_init(){
			vol_scroll_bar.addEventListener(Vol_scroll_bar.SCROLL,get_per_Handler)
		}
		private function get_per_Handler(_evt):void{
			set_volume(sound_channel,Number(vol_scroll_bar.per))
			trace(vol_scroll_bar.per)
		}
		function set_volume(temp:SoundChannel,temp_value:Number){
			var sound_trf:SoundTransform=new SoundTransform()
			sound_trf.volume=temp_value
			temp.soundTransform=sound_trf
		}
至此音量的控制搞定
 
读取声音文件的ID3数据
MP3 文件大多包含一些如songname, artist, album, genre, year等元数据,不过这些并不是都有。通过Sound对象的id3属性可获得这些数据。这个属性其实是ID3Info的类实例,它包含下列属性:artist(歌手名)、songName(歌曲名).........等。获取文件的ID3数据很简单:通过监听Sound对象的ID3事件就行了
sound.addEventListener(Event.ID3,ID3_Handler)
private function ID3_Handler(_evt:Event):void{
			trace(sound.id3.songName)
		}
将以上代码加到之前的代码Ctrl+Enter一下!很不幸,你很可能看到的是乱码。编码问题,不想多说了,用这个函数转一下就行了
private function EncodeUtf8(str : String):String {
   			var oriByteArr : ByteArray = new ByteArray();
   			oriByteArr.writeUTFBytes (str);
  			var tempByteArr : ByteArray = new ByteArray();
   			for (var i = 0; i<oriByteArr.length; i++) {
    			if (oriByteArr[i] == 194) {
     				tempByteArr.writeByte(oriByteArr[i+1]);
     				i++;
    			} else if (oriByteArr[i] == 195) {
     				tempByteArr.writeByte(oriByteArr[i+1] + 64);
     				i++;
    			} else {
    				 tempByteArr.writeByte(oriByteArr[i]);
    			}
   			}
   			tempByteArr.position = 0;
   			return tempByteArr.readMultiByte(tempByteArr.bytesAvailable,"chinese");
  		}
读取音乐声谱
自己看源吧。
服务项目_SERVICE

关于我们

万博思图(北京)信息技术有限公司,专业的flash,flex开发团队,5年经验。公司致力于互联网上的业务的开展,对于互动网站行销,互联网应用程序开发有成熟的解决方案。我们关注互联网市场动态,关注新技术,更注重在新的领域不断探索发现。
万博思图业务内容主要包括企业品牌Flash网站开发,企业形象宣传Flash设计,动画,多媒体演示,Flex企业级应用程序开发,拥有众多成功案例,欢迎来电咨询。
 
COPYRIGHT BY WEBSTUDIO INTERACTIVE DESIGN Co.,Ltd. ALL RIGHTS RESERVED.
公司地址: 北京市朝阳区光华路15号院泰达时代中心4号楼704 邮编: 100026 EMAIL: WEBSTUDIO@WEBSTUDIO.COM.CN
电话: 010-59070059   (新号:010-59897050 010-59897060)  手机: 13693660520 传真: 010-59070059-801
京公网安备:110108006741      京ICP备:05013074号-1
王先生