ActionScript3.0编程入门与提高声音篇
第20章处理声音第20ActionScript是为开发引人入胜的交互式应用程序而设计的,这种极其引人入胜的应用程序
中经常被忽略的一个元素是声音。您可以在视频游戏中添加声音效果,在应用程序用户界面
中添加音频回馈,甚至创建一个分析通过Internet加载的mp3文件的程序(在这些情况
下,声音是应用程序的核心)。
在本章中,您将了解如何加载外部音频文件以及处理SWF中嵌入的音频。您还会了解如何
控制音频、创建声音信息的可视表示形式以及从用户麦克风捕获声音。
目录
声音处理基础知识.............................................................514
了解声音体系结构.............................................................516
加载外部声音文件.............................................................517
处理嵌入的声音..............................................................520
处理声音流文件...............................................................521
播放声音.....................................................................521
加载和播放声音时的安全注意事项...............................................525
控制音量和声相...............................................................526
处理声音元数据...............................................................527
访问原始声音数据.............................................................528
捕获声音输入.................................................................532
示例:PodcastPlayer.........................................................535
513
声音处理基础知识
处理声音简介
就像计算机可以采用数字格式对图像进行编码、将它们存储在计算机上以及检索它们以便在
屏幕上显示它们一样,计算机可以捕获并编码数字音频(声音信息的计算机表示形式)以及
对其进行存储和检索,以通过连接到计算机上的扬声器进行回放。一种回放声音的方法是使
用AdobeFlashPlayer和ActionScript。
将声音数据转换为数字形式后,它具有各种不同的特性,如声音的音量以及它是立体声还是
单声道声音。在ActionScript中回放声音时,您也可以调整这些特性;例如,使声音变得更
大,或者使其像是来自某个方向。
在ActionScript中控制声音之前,您需要先将声音信息加载到FlashPlayer中。可以使用
四种方法将音频数据加载到FlashPlayer中,以便通过ActionScript对其进行使用。您可
以将外部声音文件(如mp3文件)加载到SWF中;在创建SWF文件时将声音信息直接
嵌入到其中;使用连接到用户计算机上的麦克风来获取音频输入,以及访问从服务器流式传
输的声音数据。
从外部声音文件加载声音数据时,您可以在仍加载其余声音数据的同时开始回放声音文件的
开头部分。
虽然可以使用各种不同的声音文件格式对数字音频进行编码,但是ActionScript3.0和
FlashPlayer支持以mp3格式存储的声音文件。它们不能直接加载或播放其它格式的声音
文件,如WAV或AIFF。
在ActionScript中处理声音时,您可能会使用flash.media包中的某些类。通过使用Sound
类,您可以加载声音文件并开始回放以获取对音频信息的访问。开始播放声音后,Flash
Player可为您提供对SoundChannel对象的访问。由于已加载的音频文件只能是您在用户
计算机上播放的几种声音之一,因此,所播放的每种单独的声音使用其自己的
SoundChannel对象;混合在一起的所有SoundChannel对象的组合输出是实际通过计算
机扬声器播放的声音。可以使用此SoundChannel实例来控制声音的属性以及将其停止回
放。最后,如果要控制组合音频,您可以通过SoundMixer类对混合输出进行控制。
也可以使用几个其它类,在ActionScript中处理声音时执行更具体的任务;要了解与声音
有关的所有类的详细信息,请参阅第516页的“了解声音体系结构”。
514
处理声音
常见的声音处理任务
本章介绍了以下您将希望执行的与声音有关的任务:
■加载外部mp3文件并跟踪其加载进度
■播放、暂停、继续播放以及停止播放声音
■在加载的同时播放声音流
■控制音量和声相
■从mp3文件中检索ID3元数据
■使用原始声音波形数据
■从用户麦克风捕获并重新播放声音输入
重要概念和术语
以下参考列表包含您将会在本章中遇到的重要术语:
■波幅(Amplitude):声音波形上的点与零或平衡线之间的距离。
■比特率(Bitrate):每秒为声音文件编码或流式传输的数据量。对于mp3文件,比特率
通常是以每秒千位数(kbps)来表述的。较高的比特率通常意味着较高品质的声音波形。
■缓冲(Buffering):在回放之前接收和存储声音数据。
■mp3:MPEG-1AudioLayer3(mp3)是一种常用的声音压缩格式。
■声相(Panning):将音频信号放在立体声声场中左声道和右声道之间。
■峰值(Peak):波形中的最高点。
■采样率(Samplingrate):定义在生成数字信号时每秒从模拟音频信号采集的样本数。标
准光盘音频的采样率为44.1kHz或每秒44,100个样本。
■流式传输(Streaming):此过程是指,在仍从服务器加载声音文件或视频文件的后面部分
的同时播放该文件的前面部分。
■音量(Volume):声音的响度。
■波形(Waveform):声音信号波幅随时间变化的图形形状。
完成本章中的示例
学习本章的过程中,您可能希望测试某些示例代码清单。由于本章介绍了在ActionScript中
处理声音,因此许多示例都涉及对声音文件的处理,例如,播放声音文件、停止回放或以某
种方式调整声音。测试本章中的示例:
1.创建一个新的Flash文档并将它保存到您的计算机上。
2.在时间轴上,选择第一个关键帧,然后打开“动作”面板。
3.将示例代码清单复制到“脚本”窗格中。
声音处理基础知识
515
4.
5.
如果代码涉及加载外部声音文件,则其中会有一行与下面的代码类似的代码:
varreq:URLRequest=newURLRequest("click.mp3");
vars:Sound=newSound(req);
其中“click.mp3”是要加载的声音文件的名称。为了测试这些示例,需要有一个可使用
的mp3文件。应将此mp3文件放入Flash文档所在的文件夹中。然后应更改代码以使
用mp3文件的名称,而不是代码清单中的名称(例如,在上面的代码中,将“click.mp3”
改为mp3文件的名称)。
从主菜单中,选择“控制”>“测试影片”以创建SWF文件并预览(并且听一下)示
例的输出。
除了播放音频外,某些示例将使用trace()函数来显示值;当测试这些示例时,将会在“输
出”面板中看到这些值的结果。一些示例还将内容绘制到屏幕上,因此对于这些示例,您还
将在FlashPlayer窗口中看到内容。
有关测试本手册中的示例代码清单的详细信息,请参阅第53页的“测试本章内的示例代码
清单”。
了解声音体系结构
应用程序可以从以下四种主要来源加载声音数据:
■在运行时加载的外部声音文件
■在应用程序的SWF文件中嵌入的声音资源
■来自连接到用户系统上的麦克风的声音数据
■从远程媒体服务器流式传输的声音数据,如FlashMediaServer
可以在回放之前完全加载声音数据,也可以进行流式传输,即在仍进行加载的同时回放这些
数据。
ActionScript3.0和FlashPlayer支持以mp3格式存储的声音文件。它们不能直接加载或
播放其它格式的声音文件,如WAV或AIFF。
使用AdobeFlashCS3Professional,可以导入WAV或AIFF声音文件,然后将其以mp3
格式嵌入应用程序的SWF文件中。Flash创作工具还可压缩嵌入的声音文件以减小文件大
小,但会降低声音的品质。有关详细信息,请参阅《使用Flash》中的“导入声音”。
516
处理声音
ActionScript3.0声音体系结构使用flash.media包中的以下类。
类描述
flash.media.SoundSound类处理声音加载、管理基本声音属性以及启动声
音播放。
flash.media.SoundChannel当应用程序播放Sound对象时,将创建一个新的
SoundChannel对象来控制回放。SoundChannel对象
控制声音的左和右回放声道的音量。播放的每种声音具有
其自己的SoundChannel对象。
flash.media.SoundLoaderContextSoundLoaderContext类指定在加载声音时使用的缓冲
秒数,以及FlashPlayer在加载文件时是否从服务器中
查找跨域策略文件。SoundLoaderContext对象用作
Sound.load()方法的参数。
flash.media.SoundMixerSoundMixer类控制与应用程序中的所有声音有关的回放
和安全属性。实际上,可通过一个通用SoundMixer对象
将多个声道混合在一起,因此,该SoundMixer对象中的
属性值将影响当前播放的所有SoundChannel对象。
flash.media.SoundTransformSoundTransform类包含控制音量和声相的值。可以将
SoundTransform对象应用于单个SoundChannel对
象、全局SoundMixer对象或Microphone对象等。
flash.media.ID3InfoID3Info对象包含一些属性,它们表示通常存储在mp3
声音文件中的ID3元数据信息。
flash.media.MicrophoneMicrophone类表示连接到用户计算机上的麦克风或其它
声音输入设备。可以将来自麦克风的音频输入传送到本地
扬声器或发送到远程服务器。Microphone对象控制其自
己的声音流的增益、采样率以及其它特性。
加载和播放的每种声音需要其自己的Sound类和SoundChannel类的实例。然后,全局
SoundMixer类在回放期间将来自多个SoundChannel实例的输出混合在一起。
Sound、SoundChannel和SoundMixer类不能用于从麦克风或流媒体服务器(如Flash
MediaServer)中获取的声音数据。
加载外部声音文件
Sound类的每个实例可加载并触发特定声音资源的回放。应用程序无法重复使用Sound对
象来加载多种声音。如果它要加载新的声音资源,则应创建一个新的Sound对象。
如果要加载较小的声音文件(如要附加到按钮上的单击声音),应用程序可以创建一个新的
Sound,并让其自动加载该声音文件,如下所示:
varreq:URLRequest=newURLRequest("click.mp3");
vars:Sound=newSound(req);
加载外部声音文件
517
Sound()构造函数接受一个URLRequest对象作为其第一个参数。当提供URLRequest参
数的值后,新的Sound对象将自动开始加载指定的声音资源。
除了最简单的情况下,应用程序都应关注声音的加载进度,并监视在加载期间出现的错误。
例如,如果单击声音非常大,在用户单击触发该声音的按钮时,该声音可能没有完全加载。
尝试播放未加载的声音可能会导致运行时错误。较为稳妥的作法是等待声音完全加载后,再
让用户执行可能启动声音播放的动作。
Sound对象将在声音加载过程中调度多种不同的事件。应用程序可以侦听这些事件以跟踪
加载进度,并确保在播放之前完全加载声音。下表列出了可以由Sound对象调度的事件。
事件描述
open(Event.OPEN)就在声音加载操作开始之前进行调度。
progress(ProgressEvent.PROGRESS)从文件或流接收数据时,在声音加载过程中定期进行调度。
id3(Event.ID3)当存在可用于mp3声音的ID3数据时进行调度。
complete(Event.COMPLETE)在加载了所有声音资源后进行调度。
ioError(IOErrorEvent.IO_ERROR)在以下情况下进行调度:找不到声音文件,或者在收到所
有声音数据之前加载过程中断。
以下代码说明了如何在完成加载后播放声音:
importflash.events.Event;
importflash.media.Sound;
importflash.net.URLRequest;
vars:Sound=newSound();
s.addEventListener(Event.COMPLETE,onSoundLoaded);
varreq:URLRequest=newURLRequest("bigSound.mp3");
s.load(req);
functiononSoundLoaded(event:Event):void
{
varlocalSound:Sound=event.targetasSound;
localSound.play();
}
首先,该代码范例创建一个新的Sound对象,但没有为其指定URLRequest参数的初始
值。然后,它通过Sound对象侦听Event.COMPLETE事件,该对象导致在加载完所有声音
数据后执行onSoundLoaded()方法。接下来,它使用新的URLRequest值为声音文件调用
Sound.load()方法。
在加载完声音后,将执行onSoundLoaded()方法。Event对象的目标属性是对Sound对象
的引用。如果调用Sound对象的play()方法,则会启动声音回放。
518
处理声音
监视声音加载过程
声音文件可能很大,而需要花很长时间进行加载。尽管FlashPlayer允许应用程序甚至在完
全加载声音之前播放声音,但您可能需要向用户指示已加载了多少声音数据以及已播放了多
少声音。
Sound类调度以下两个事件,它们可使声音加载进度显示变得相对比较简单:
ProgressEvent.PROGRESS和Event.COMPLETE。以下示例说明了如何使用这些事件来显示
有关所加载的声音的进度信息:
importflash.events.Event;
importflash.events.ProgressEvent;
importflash.media.Sound;
importflash.net.URLRequest;
vars:Sound=newSound();
s.addEventListener(ProgressEvent.PROGRESS,onLoadProgress);
s.addEventListener(Event.COMPLETE,onLoadComplete);
s.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
varreq:URLRequest=newURLRequest("bigSound.mp3");
s.load(req);
functiononLoadProgress(event:ProgressEvent):void
{
varloadedPct:uint=
Math.round(100(event.bytesLoaded/event.bytesTotal));
trace("Thesoundis"+loadedPct+"%loaded.");
}
functiononLoadComplete(event:Event):void
{
varlocalSound:Sound=event.targetasSound;
localSound.play();
}
functiononIOError(event:IOErrorEvent)
{
trace("Thesoundcouldnotbeloaded:"+event.text);
}
此代码先创建一个Sound对象,然后在该对象中添加侦听器以侦听ProgressEvent.PROGRESS
和Event.COMPLETE事件。在调用Sound.load()方法并从声音文件接收第一批数据后,将
会发生ProgressEvent.PROGRESS事件并触发onSoundLoadProgress()方法。
已加载的声音数据百分比等于ProgressEvent对象的bytesLoaded属性值除以bytesTotal
属性值。Sound对象上也提供了相同的bytesLoaded和bytesTotal属性。以上示例只显
示了有关声音加载进度的消息,但您可以方便地使用bytesLoaded和bytesTotal值来更新
进度栏组件,例如随AdobeFlex2框架或Flash创作工具提供的组件。
加载外部声音文件
519
此示例还说明了应用程序在加载声音文件时如何识别并响应出现的错误。例如,如果找不到
具有给定文件名的声音文件,Sound对象将调度一个Event.IO_ERROR事件。在上面的代码
中,当发生错误时,将执行onIOError()方法并显示一条简短的错误消息。
处理嵌入的声音
对于用作应用程序用户界面中的指示器的较小声音(如在单击按钮时播放的声音),使用嵌
入的声音非常有用(而不是从外部文件加载声音)。
在应用程序中嵌入声音文件时,生成的SWF文件大小比原来增加了声音文件的大小。也就是
说,如果在应用程序中嵌入较大的声音文件,可能会使SWF文件增大到难以接受的大小。
将声音文件嵌入到应用程序的SWF文件中的具体方法因开发环境而异。
在Flash中使用嵌入的声音文件
Flash创作工具可导入多种声音格式的声音并将其作为元件存储在库中。然后,您可以将其
分配给时间轴上的帧或按钮状态的帧,通过行为来使用声音,或直接在ActionScript代码中
使用它们。本节说明如何在ActionScript代码中通过Flash创作工具来使用嵌入的声音。有
关在Flash中使用嵌入的声音的其它方法,请参阅《使用Flash》中的“导入声音”。
要在Flash影片中嵌入声音文件,请执行以下操作:
1.选择“文件”>“导入”>“导入到库”,然后选择一个声音文件并导入它。
2.在“库”面板中,右键单击导入的文件的名称,然后选择“属性”。单击“为ActionScript
导出”复选框。
3.在“类”字段中,输入一个名称,以便在ActionScript中引用此嵌入的声音时使用。
默认情况下,它将使用此字段中声音文件的名称。如果文件名包含句点(如名称
“DrumSound.mp3”),则必须将其更改为类似于“DrumSound”这样的名称;
ActionScript不允许在类名称中出现句点字符。“基类”字段应仍显示
flash.media.Sound。
4.单击“确定”。可能出现一个对话框,指出无法在类路径中找到该类的定义。单击“确
定”以继续。如果输入的类名称与应用程序的类路径中任何类的名称都不匹配,则会自
动生成从flash.media.Sound类继承的新类。
5.要使用嵌入的声音,请在ActionScript中引用该声音的类名称。例如,通过创建自动生
成的DrumSound类的一个新实例来启动以下代码:
vardrum:DrumSound=newDrumSound();
varchannel:SoundChannel=drum.play();
DrumSound是flash.media.Sound类的子类,所以它继承了Sound类的方法和属性,
包括上面显示的play()方法。
520
处理声音
处理声音流文件
如果在仍加载声音文件或视频文件数据的同时回放该文件,则认为是流式传输。通常,将对
从远程服务器加载的外部声音文件进行流式传输,以使用户不必等待加载完所有声音数据再
收听声音。
SoundMixer.bufferTime属性表示FlashPlayer在允许播放声音之前应收集多长时间的声
音数据(以毫秒为单位)。也就是说,如果将bufferTime属性设置为5000,在开始播放
声音之前,FlashPlayer将从声音文件中加载至少相当于5000毫秒的数据。
SoundMixer.bufferTime默认值为1000。
通过在加载声音时显式地指定新的bufferTime值,应用程序可以覆盖单个声音的全局
SoundMixer.bufferTime值。要覆盖默认缓冲时间,请先创建一个新的
SoundLoaderContext类实例,设置其bufferTime属性,然后将其作为参数传递给
Sound.load()方法,如下所示:
importflash.media.Sound;
importflash.media.SoundLoaderContext;
importflash.net.URLRequest;
vars:Sound=newSound();
varreq:URLRequest=newURLRequest("bigSound.mp3");
varcontext:SoundLoaderContext=newSoundLoaderContext(8000,true);
s.load(req,context);
s.play();
当回放继续进行时,FlashPlayer尝试将声音缓冲保持在相同大小或更大。如果声音数据的
加载速度比回放快,回放将继续进行而不会中断。但是,如果数据加载速率由于网络限制而
减慢,播放头可能会到达声音缓冲区的结尾。如果发生这种情况,将暂停回放,但会在加载
更多声音数据后自动恢复回放。
要查明暂停回放是否是由于FlashPlayer正在等待加载数据,请使用Sound.isBuffering
属性。
播放声音
播放加载的声音非常简便,您只需为Sound对象调用Sound.play()方法,如下所示:
varsnd:Sound=newSound(newURLRequest("smallSound.mp3"));
snd.play();
使用ActionScript3.0回放声音时,您可以执行以下操作:
■从特定起始位置播放声音
■暂停声音并稍后从相同位置恢复回放
■准确了解何时播放完声音
播放声音
521
■
■
跟踪声音的回放进度
在播放声音的同时更改音量或声相
要在回放期间执行这些操作,请使用SoundChannel、SoundMixer和SoundTransform类。
SoundChannel类控制一种声音的回放。可以将SoundChannel.position属性视为播放
头,以指示所播放的声音数据中的当前位置。
当应用程序调用Sound.play()方法时,将创建一个新的SoundChannel类实例来控制回放。
通过将特定起始位置(以毫秒为单位)作为Sound.play()方法的startTime参数进行传
递,应用程序可以从该位置播放声音。它也可以通过在Sound.play()方法的loops参数中
传递一个数值,指定快速且连续地将声音重复播放固定的次数。
使用startTime参数和loops参数调用Sound.play()方法时,每次将从相同的起始点重
复回放声音,如以下代码中所示:
varsnd:Sound=newSound(newURLRequest("repeatingSound.mp3"));
snd.play(1000,3);
在此示例中,从声音开始后的1秒起连续播放声音三次。
暂停和恢复播放声音
如果应用程序播放很长的声音(如歌曲或播客),您可能需要让用户暂停和恢复回放这些声
音。实际上,无法在ActionScript中的回放期间暂停声音;而只能将其停止。但是,可以从
任何位置开始播放声音。您可以记录声音停止时的位置,并随后从该位置开始重放声音。
例如,假定代码加载并播放一个声音文件,如下所示:
varsnd:Sound=newSound(newURLRequest("bigSound.mp3"));
varchannel:SoundChannel=snd.play();
在播放声音的同时,SoundChannel.position属性指示当前播放到的声音文件位置。应用程
序可以在停止播放声音之前存储位置值,如下所示:
varpausePosition:int=channel.position;
channel.stop();
要恢复播放声音,请传递以前存储的位置值,以便从声音以前停止的相同位置重新启动声音。
channel=snd.play(pausePosition);
522
处理声音
监视回放
应用程序可能需要了解何时停止播放某种声音,以便开始播放另一种声音,或者清除在以前
回放期间使用的某些资源。SoundChannel类在其声音完成播放时将调度
Event.SOUND_COMPLETE事件。应用程序可以侦听此事件并执行相应的动作,如下所示:
importflash.events.Event;
importflash.media.Sound;
importflash.net.URLRequest;
varsnd:Sound=newSound("smallSound.mp3");
varchannel:SoundChannel=snd.play();
s.addEventListener(Event.SOUND_COMPLETE,onPlaybackComplete);
publicfunctiononPlaybackComplete(event:Event)
{
trace(“Thesoundhasfinishedplaying.”);
}
SoundChannel类在回放期间不调度进度事件。要报告回放进度,应用程序可以设置其自己
的计时机制并跟踪声音播放头的位置。
要计算已播放的声音百分比,您可以将SoundChannel.position属性值除以所播放的声音
数据长度:
varplaybackPercent:uint=100(channel.position/snd.length);
但是,仅当在开始回放之前完全加载了声音数据,此代码才会报告精确的回放百分比。
Sound.length属性显示当前加载的声音数据的大小,而不是整个声音文件的最终大小。要
跟踪仍在加载的声音流的回放进度,应用程序应估计完整声音文件的最终大小,并在其计算
中使用该值。您可以使用Sound对象的bytesLoaded和bytesTotal属性来估计声音数据
的最终长度,如下所示:
varestimatedLength:int=
Math.ceil(snd.length/(snd.bytesLoaded/snd.bytesTotal));
varplaybackPercent:uint=100(channel.position/estimatedLength);
以下代码加载一个较大的声音文件,并使用Event.ENTER_FRAME事件作为其计时机制来显
示回放进度。它定期报告回放百分比,这是作为当前位置值除以声音数据的总长度来计算的:
importflash.events.Event;
importflash.media.Sound;
importflash.net.URLRequest;
varsnd:Sound=newSound();
varreq:URLRequest=new
URLRequest("http://av.adobe.com/podcast/csbu_dev_podcast_epi_2.mp3");
snd.load(req);
varchannel:SoundChannel;
channel=snd.play();
播放声音
523
addEventListener(Event.ENTER_FRAME,onEnterFrame);
snd.addEventListener(Event.SOUND_COMPLETE,onPlaybackComplete);
functiononEnterFrame(event:Event):void
{
varestimatedLength:int=
Math.ceil(snd.length/(snd.bytesLoaded/snd.bytesTotal));
varplaybackPercent:uint=
Math.round(100(channel.position/estimatedLength));
trace("Soundplaybackis"+playbackPercent+"%complete.");
}
functiononPlaybackComplete(event:Event)
{
trace("Thesoundhasfinishedplaying.");
removeEventListener(Event.ENTER_FRAME,onEnterFrame);
}
在开始加载声音数据后,此代码调用snd.play()方法,并将生成的SoundChannel对象存
储在channel变量中。随后,此代码在主应用程序中添加Event.ENTER_FRAME事件的事件
侦听器,并在SoundChannel对象中添加另一个事件侦听器,用于侦听在回放完成时发生
的Event.SOUND_COMPLETE事件。
每次应用程序到达其动画中的新帧时,将调用onEnterFrame()方法。onEnterFrame()方
法基于已加载的数据量来估计声音文件的总长度,然后计算并显示当前回放百分比。
当播放整个声音后,将执行onPlaybackComplete()方法来删除Event.ENTER_FRAME事件
的事件侦听器,以使其在完成回放后不会尝试显示进度更新。
可以每秒多次调度Event.ENTER_FRAME事件。在某些情况下,您不需要频繁显示回放进度。
在这些情况下,应用程序可以使用flash.util.Timer类来设置其自己的计时机制;请参阅
第159页的“处理日期和时间”。
停止声音流
在进行流式传输的声音(即,在播放的同时仍在加载声音)的回放过程中,有一个奇怪的现
象。当应用程序对回放声音流的SoundChannel实例调用SoundChannel.stop()方法时,
声音回放在一个帧处停止,随后在下一帧处从声音开头重新回放。发生这种情况是因为,声
音加载过程仍在进行当中。要停止声音流加载和回放,请调用Sound.close()方法。
524
处理声音
加载和播放声音时的安全注意事项
可以根据FlashPlayer安全模型来限制应用程序访问声音数据的功能。每种声音受两种不同
的安全沙箱的限制:内容本身的沙箱(“内容沙箱”)以及加载和播放声音的应用程序或对
象的沙箱(“所有者沙箱”)。要了解有关常用FlashPlayer安全模型的详细信息以及沙箱
定义,请参阅第649页的“FlashPlayer安全性”。
内容沙箱控制使用id3属性还是SoundMixer.computeSpectrum()方法从声音提取详细声
音数据。它不会限制声音文件本身的加载或播放。
声音文件的原始域定义了内容沙箱的安全限制。一般来说,如果某个声音文件与加载该文件
的应用程序或对象的SWF文件位于相同的域或文件夹中,则应用程序或对象具有该声音文
件的完全访问权限。如果声音来自与应用程序不同的域,仍可以使用跨域策略文件将其加载
到内容沙箱中。
应用程序可以将带有checkPolicyFile属性的SoundLoaderContext对象作为参数传递给
Sound.load()方法。如果将checkPolicyFile属性设置为true,则会通知FlashPlayer在
从中加载声音的服务器上查找跨域策略文件。如果存在跨域策略文件,并且它为执行加载的
SWF文件所在的域授予了访问权限,则该SWF文件可以加载声音文件、访问Sound对象
的id3属性以及为加载的声音调用SoundMixer.computeSpectrum()方法。
所有者沙箱控制声音的本地回放。所有者沙箱是由开始播放声音的应用程序或对象定义的。
只要当前播放的所有SoundChannel对象中的声音符合以下条件,SoundMixer.stopAll()
方法就会将它们静音:
■声音是由相同所有者沙箱中的对象启动的。
■声音来自具有跨域策略文件(为调用SoundMixer.stopAll()方法的应用程序或对象所
在的域授予访问权限)的源。
要查明SoundMixer.stopAll()方法是否确实停止了所有播放的声音,应用程序可以调用
SoundMixer.areSoundsInaccessible()方法。如果该方法返回值true,则当前所有者沙
箱无法控制播放的某些声音,SoundMixer.stopAll()方法不会将其停止。
SoundMixer.stopAll()方法还会阻止播放头继续播放从外部文件加载的所有声音。但是,
如果动画移动到一个新帧,FLA文件中嵌入的声音以及使用Flash创作工具附加到时间轴
中的帧上的声音可能会重新开始播放。
加载和播放声音时的安全注意事项
525
控制音量和声相
单个SoundChannel对象控制声音的左和右立体声声道。如果mp3声音是单声道声音,
SoundChannel对象的左和右立体声声道将包含完全相同的波形。
可通过使用SoundChannel对象的leftPeak和rightPeak属性来查明所播放的声音的每
个立体声声道的波幅。这些属性显示声音波形本身的峰值波幅。它们并不表示实际回放音
量。实际回放音量是声音波形的波幅以及SoundChannel对象和SoundMixer类中设置的
音量值的函数。
在回放期间,可以使用SoundChannel对象的pan属性为左和右声道分别指定不同的音量
级别。pan属性可以具有范围从-1到1的值,其中,-1表示左声道以最大音量播放,而右
声道处于静音状态;1表示右声道以最大音量播放,而左声道处于静音状态。介于-1和1之
间的数值为左和右声道值设置一定比例的值,值0表示两个声道以均衡的中音量级别播放。
以下代码示例使用volume值0.6和pan值-1创建一个SoundTransform对象(左声道为
最高音量,右声道没有音量)。此代码将SoundTransform对象作为参数传递给play()方
法,此方法将该SoundTransform对象应用于为控制回放而创建的新SoundChannel对象。
varsnd:Sound=newSound(newURLRequest("bigSound.mp3"));
vartrans:SoundTransform=newSoundTransform(0.6,-1);
varchannel:SoundChannel=snd.play(0,1,trans);
可以在播放声音的同时更改音量和声相,方法是:设置SoundTransform对象的pan或
volume属性,然后将该对象作为SoundChannel对象的soundTransform属性进行应用。
也可以通过使用SoundMixer类的soundTransform属性,同时为所有声音设置全局音量和
声相值,如以下示例所示:
SoundMixer.soundTransform=newSoundTransform(1,-1);
也可以使用SoundTransform对象为Microphone对象(请参阅第532页的“捕获声音
输入”)、Sprite对象和SimpleButton对象设置音量和声相值。
以下示例在播放声音的同时将声音从左声道移到右声道,然后再移回来,并交替进行这一
过程。
importflash.events.Event;
importflash.media.Sound;
importflash.media.SoundChannel;
importflash.media.SoundMixer;
importflash.net.URLRequest;
varsnd:Sound=newSound();
varreq:URLRequest=newURLRequest("bigSound.mp3");
snd.load(req);
varpanCounter:Number=0;
vartrans:SoundTransform;
526
处理声音
trans=newSoundTransform(1,0);
varchannel:SoundChannel=snd.play(0,1,trans);
channel.addEventListener(Event.SOUND_COMPLETE,onPlaybackComplete);
addEventListener(Event.ENTER_FRAME,onEnterFrame);
functiononEnterFrame(event:Event):void
{
trans.pan=Math.sin(panCounter);
channel.soundTransform=trans;//orSoundMixer.soundTransform=trans;
panCounter+=0.05;
}
functiononPlaybackComplete(event:Event):void
{
removeEventListener(Event.ENTER_FRAME,onEnterFrame);
}
此代码先加载一个声音文件,然后将volume设置为1(最大音量)并将pan设置为0(声
音在左和右声道之间均衡地平均分布)以创建一个新的SoundTransform对象。接下来,此
代码调用snd.play()方法,以将SoundTransform对象作为参数进行传递。
在播放声音时,将反复执行onEnterFrame()方法。onEnterFrame()方法使用Math.sin()
函数来生成介于-1和1之间的值,此范围对应于可接受的SoundTransform.pan属性值。
此代码将SoundTransform对象的pan属性设置为新值,然后设置声道的soundTransform
属性以使用更改后的SoundTransform对象。
要运行此示例,请用本地mp3文件的名称替换文件名bigSound.mp3。然后,运行该示例。
当右声道音量变小时,您应会听到左声道音量变大,反之亦然。
在此示例中,可通过设置SoundMixer类的soundTransform属性来获得同样的效果。但
是,这会影响当前播放的所有声音的声相,而不是只影响此SoundChannel对象播放的一
种声音。
处理声音元数据
使用mp3格式的声音文件可以采用ID3标签格式来包含有关声音的其它数据。
并非每个mp3文件都包含ID3元数据。当Sound对象加载mp3声音文件时,如果该声
音文件包含ID3元数据,它将调度Event.ID3事件。要防止出现运行时错误,应用程序应
等待接收Event.ID3事件后,再访问加载的声音的Sound.id3属性。
以下代码说明了如何识别何时加载了声音文件的ID3元数据:
importflash.events.Event;
importflash.media.ID3Info;
importflash.media.Sound;
处理声音元数据
527
vars:Sound=newSound();
s.addEventListener(Event.ID3,onID3InfoReceived);
s.load("mySound.mp3");
functiononID3InfoReceived(event:Event)
{
varid3:ID3Info=event.target.id3;
trace("ReceivedID3Info:");
for(varpropName:Stringinid3)
{
trace(propName+"="+id3[propName]);
}
}
此代码先创建一个Sound对象并通知它侦听Event.ID3事件。加载了声音文件的ID3元
数据后,将调用onID3InfoReceived()方法。传递给onID3InfoReceived()方法的Event
对象的目标是原始Sound对象,因此,该方法随后获取Sound对象的id3属性,然后循环
访问所有命名属性以跟踪它们的值。
访问原始声音数据
通过使用SoundMixer.computeSpectrum()方法,应用程序可以读取当前所播放的波形的原
始声音数据。如果当前播放多个SoundChannel对象,SoundMixer.computeSpectrum()方
法将显示混合在一起的每个SoundChannel对象的组合声音数据。
声音数据是作为ByteArray对象(包含512个字节的数据)返回的,其中的每个字节包含
一个介于-1和1之间的浮点值。这些值表示所播放的声音波形中的点的波幅。这些值是分
为两个组(每组包含256个值)提供的,第一个组用于左立体声声道,第二个组用于右立
体声声道。
如果将FFTMode参数设置为true,SoundMixer.computeSpectrum()方法将返回频谱数
据,而非波形数据。频谱显示按声音频率(从最低频率到最高频率)排列的波幅。可以使用
快速傅立叶变换(FFT)将波形数据转换为频谱数据。生成的频谱值范围介于0和约1.414
(2的平方根)之间。
528
处理声音
下图比较了将FFTMode参数设置为true和false时从computeSpectrum()方法返回的数
据。此图所用数据的声音在左声道中包含很大的低音;而在右声道中包含击鼓声。
computeSpectrum()方法也可以返回已在较低比特率重新采样的数据。通常,这会产生更
平滑的波形数据或频率数据,但会以牺牲细节为代价。stretchFactor参数控制
computeSpectrum()方法数据的采样率。如果将stretchFactor参数设置为0(默认值),
则以采样率44.1kHz采集声音数据样本。stretchFactor参数值每连续增加1,采样率就
减小一半,因此,值1指定采样率22.05kHz,值2指定采样率11.025kHz,依此类推。
当使用较高的stretchFactor值时,computeSpectrum()方法仍会为每个立体声声道返回
256个字节。
SoundMixer.computeSpectrum()方法具有一些限制:
■由于来自麦克风或RTMP流的声音数据不是通过全局SoundMixer对象传递的,因
此,SoundMixer.computeSpectrum()方法不会从这些源返回数据。
■如果播放的一种或多种声音来自当前内容沙箱以外的源,安全限制将导致
SoundMixer.computeSpectrum()方法引发错误。有关SoundMixer.computeSpectrum()
方法的安全限制的更多详细信息,请参阅第525页的“加载和播放声音时的安全注意
事项”和第671页的“作为数据访问加载的媒体”。
访问原始声音数据
529
构建简单的声音可视化程序
以下示例使用SoundMixer.computeSpectrum()方法来显示声音波形图(它对每个帧进行
动画处理):
importflash.display.Graphics;
importflash.events.Event;
importflash.media.Sound;
importflash.media.SoundChannel;
importflash.media.SoundMixer;
importflash.net.URLRequest;
constPLOT_HEIGHT:int=200;
constCHANNEL_LENGTH:int=256;
varsnd:Sound=newSound();
varreq:URLRequest=newURLRequest("bigSound.mp3");
snd.load(req);
varchannel:SoundChannel;
channel=snd.play();
addEventListener(Event.ENTER_FRAME,onEnterFrame);
snd.addEventListener(Event.SOUND_COMPLETE,onPlaybackComplete);
varbytes:ByteArray=newByteArray();
functiononEnterFrame(event:Event):void
{
SoundMixer.computeSpectrum(bytes,false,0);
varg:Graphics=this.graphics;
g.clear();
g.lineStyle(0,0x6600CC);
g.beginFill(0x6600CC);
g.moveTo(0,PLOT_HEIGHT);
varn:Number=0;
//leftchannel
for(vari:int=0;i {
n=(bytes.readFloat()PLOT_HEIGHT);
g.lineTo(i2,PLOT_HEIGHT-n);
}
g.lineTo(CHANNEL_LENGTH2,PLOT_HEIGHT);
g.endFill();
//rightchannel
g.lineStyle(0,0xCC0066);
530
处理声音
}
g.beginFill(0xCC0066,0.5);
g.moveTo(CHANNEL_LENGTH2,PLOT_HEIGHT);
for(i=CHANNEL_LENGTH;i>0;i--)
{
n=(bytes.readFloat()PLOT_HEIGHT);
g.lineTo(i2,PLOT_HEIGHT-n);
}
g.lineTo(0,PLOT_HEIGHT);
g.endFill();
functiononPlaybackComplete(event:Event)
{
removeEventListener(Event.ENTER_FRAME,onEnterFrame);
}
此示例先加载并播放一个声音文件,然后在播放声音的同时侦听将触发onEnterFrame()方法
的Event.ENTER_FRAME事件。onEnterFrame()方法先调用SoundMixer.computeSpectrum()
方法,后者将声音波形数据存储在bytesByteArray对象中。
声音波形是使用矢量绘图API绘制的。for循环将循环访问第一批256个数据值(表示左
立体声声道),然后使用Graphics.lineTo()方法绘制一条从每个点到下一个点的直线。第
二个for循环将循环访问下一批256个值,此时按相反的顺序(从右到左)对它们进行绘
制。生成的波形图可能会产生非常有趣的镜像图像效果,如以下图像中所示。
访问原始声音数据
531
捕获声音输入
应用程序可通过Microphone类连接到用户系统上的麦克风或其它声音输入设备,并将输入
音频广播到该系统的扬声器,或者将音频数据发送到远程服务器,如FlashMediaServer。
访问麦克风
Microphone类没有构造函数方法。相反,应使用静态Microphone.getMicrophone()方法
来获取新的Microphone实例,如下所示:
varmic:Microphone=Microphone.getMicrophone();
不使用参数调用Microphone.getMicrophone()方法时,将返回在用户系统上发现的第一
个声音输入设备。
系统可能连接了多个声音输入设备。应用程序可以使用Microphone.names属性来获取所有
可用声音输入设备名称的数组。然后,它可以使用index参数(与数组中的设备名称的索
引值相匹配)来调用Microphone.getMicrophone()方法。
系统可能没有连接麦克风或其它声音输入设备。可以使用Microphone.names属性或
Microphone.getMicrophone()方法来检查用户是否安装了声音输入设备。如果用户未安装
声音输入设备,则names数组的长度为零,并且getMicrophone()方法返回值null。
当应用程序调用Microphone.getMicrophone()方法时,FlashPlayer将显示“Flash
Player设置”对话框,它提示用户允许或拒绝FlashPlayer对系统上的摄像头和麦克风的
访问。在用户单击此对话框中的“允许”或“拒绝”按钮后,将调度StatusEvent。该
StatusEvent实例的code属性指示是允许还是拒绝对麦克风的访问,如下例所示:
importflash.media.Microphone;
varmic:Microphone=Microphone.getMicrophone();
mic.addEventListener(StatusEvent.STATUS,this.onMicStatus);
functiononMicStatus(event:StatusEvent):void
{
if(event.code=="Microphone.Unmuted")
{
trace("Microphoneaccesswasallowed.");
}
elseif(event.code=="Microphone.Muted")
(
trace("Microphoneaccesswasdenied.");
}
}
532
处理声音
如果允许访问,StatusEvent.code属性将包含“Microphone.Unmuted”;如果拒绝访
问,则包含“Microphone.Muted”。
意
当用户允许或拒绝对麦克风的访问时,Microphone.muted属性将被分别设置为true或
false。但是,在调度StatusEvent之前,不会在Microphone实例上设置muted属性,因
此,应用程序还应等待调度StatusEvent.STATUS事件后再检查Microphone.muted属性。
将麦克风音频传送到本地扬声器
可以使用参数值true调用Microphone.setLoopback()方法,以将来自麦克风的音频输入
传送到本地系统扬声器。
如果将来自本地麦克风的声音传送到本地扬声器,则会存在创建音频回馈循环的风险,这可
能会导致非常大的振鸣声,并且可能会损坏声音硬件。使用参数值true调用
Microphone.setUseEchoSuppression()方法可降低发生音频回馈的风险,但不会完全消
除该风险。Adobe建议您始终在调用Microphone.setLoopback(true)之前调用
Microphone.setUseEchoSuppression(true),除非您确信用户使用耳机来回放声音,或者
使用除扬声器以外的某种设备。
以下代码说明了如何将来自本地麦克风的音频传送到本地系统扬声器:
varmic:Microphone=Microphone.getMicrophone();
mic.setUseEchoSuppression(true);
mic.setLoopBack(true);
更改麦克风音频
应用程序可以使用两种方法更改来自麦克风的音频数据。第一,它可以更改输入声音的增益,
这会有效地将输入值乘以指定的数值以创建更大或更小的声音。Microphone.gain属性接受
介于0和100之间的数值(含0和100)。值50相当于乘数1,它指定正常音量。值0相
当于乘数0,它可有效地将输入音频静音。大于50的值指定的音量高于正常音量。
应用程序也可以更改输入音频的采样率。较高的采样率可提高声音品质,但它们也会创建更密
集的数据流(使用更多的资源进行传输和存储)。Microphone.rate属性表示以千赫(kHz)为
单位测量的音频采样率。默认采样率是8kHz。如果麦克风支持较高的采样率,您可以将
Microphone.rate属性设置为高于8kHz的值。例如,如果将Microphone.rate属性设置为
值11,则会将采样率设置为11kHz;如果将其设置为22,则会将采样率设置为22kHz,
依此类推。
捕获声音输入
533
检测麦克风活动
为节省带宽和处理资源,FlashPlayer将尝试检测何时麦克风不传输声音。当麦克风的活动
级别处于静音级别阈值以下一段时间后,FlashPlayer将停止传输音频输入,并调度一个简
单的ActivityEvent。
Microphone类的以下三个属性用于监视和控制活动检测:
■activityLevel只读属性指示麦克风检测的音量,范围从0到100。
■silenceLevel属性指定激活麦克风并调度ActivityEvent.ACTIVITY事件所需的音量。
silenceLevel属性也使用从0到100的范围,默认值为10。
■silenceTimeout属性描述活动级别处于静音级别以下多长时间(以毫秒为单位)后,才
会调度ActivityEvent.ACTIVITY事件以指示麦克风现在处于静音状态。silenceTimeout
默认值是2000。
Microphone.silenceLevel属性和Microphone.silenceTimeout属性都是只读的,但可以
使用Microphone.setSilenceLevel()方法来更改它们的值。
在某些情况下,在检测到新活动时激活麦克风的过程可能会导致短暂的延迟。通过将麦克风始
终保持活动状态,可以消除此类激活延迟。应用程序可以调用Microphone.setSilenceLevel()
方法并将silenceLevel参数设置为零,以通知FlashPlayer将麦克风保持活动状态并持续收
集音频数据,即使未检测到任何声音也是如此。反之,如果将silenceLevel参数设置为100,
则可以完全禁止激活麦克风。
以下示例显示了有关麦克风的信息,并报告Microphone对象调度的活动事件和状态事件:
importflash,events.ActivityEvent;
importflash,events.StatusEvent;
importflash.media.Microphone;
vardeviceArray:Array=Microphone.names;
trace("Availablesoundinputdevices:");
for(vari:int=0;i {
trace(""+deviceArray[i]);
}
varmic:Microphone=Microphone.getMicrophone();
mic.gain=60;
mic.rate=11;
mic.setUseEchoSuppression(true);
mic.setLoopBack(true);
mic.setSilenceLevel(5,1000);
mic.addEventListener(ActivityEvent.ACTIVITY,this.onMicActivity);
mic.addEventListener(StatusEvent.STATUS,this.onMicStatus);
varmicDetails:String="Soundinputdevicename:"+mic.name+''\n'';
534
处理声音
micDetails+="Gain:"+mic.gain+''\n'';
micDetails+="Rate:"+mic.rate+"kHz"+''\n'';
micDetails+="Muted:"+mic.muted+''\n'';
micDetails+="Silencelevel:"+mic.silenceLevel+''\n'';
micDetails+="Silencetimeout:"+mic.silenceTimeout+''\n'';
micDetails+="Echosuppression:"+mic.useEchoSuppression+''\n'';
trace(micDetails);
functiononMicActivity(event:ActivityEvent):void
{
trace("activating="+event.activating+",activityLevel="+
mic.activityLevel);
}
functiononMicStatus(event:StatusEvent):void
{
trace("status:level="+event.level+",code="+event.code);
}
在运行上面的示例时,对着系统麦克风说话或发出噪音,并观察所生成的、显示在控制台或
调试窗口中的trace语句。
向媒体服务器发送音频以及从中接收音频
将ActionScript与FlashMediaServer等流媒体服务器配合使用时,可以使用额外的音频
功能。
特别地,应用程序可以将Microphone对象附加到NetStream对象上,并将数据直接从用
户麦克风传输到服务器。也可以将音频数据从服务器流式传输到Flash或Flex应用程序,并
将其作为MovieClip的一部分或使用Video对象进行回放。
有关详细信息,请参阅http://livedocs.macromedia.com上提供的在线FlashMediaServer
文档。
示例:PodcastPlayer
播客是通过Internet以按需方式或订阅方式分发的声音文件。播客通常是作为系列的一部
分发布的,此系列也称为播客频道。由于播客节目的持续时间从一分钟到数小时不等,因此,
通常在播放的同时对其进行流式传输。播客节目(也称为项目)通常是以mp3文件格式提
供的。视频播客也非常受欢迎,但此范例应用程序仅播放使用mp3文件的音频播客。
此示例并不是一个功能完备的播客聚合器应用程序。例如,它不能管理对特定播客的订
阅,或在下次运行应用程序时记住用户已收听的播客。它可用作功能更完备的播客聚合器
的起点。
示例:PodcastPlayer
535
PodcastPlayer示例说明了以下ActionScript编程方法:
■读取外部RSS新闻频道并分析其XML内容
■创建SoundFacade类以简化加载和回放声音文件的过程
■显示声音回放进度
■暂停和恢复声音回放
要获取该范例的应用程序文件,请访问
www.adobe.com/go/learn_programmingAS3samples_flash_cn。PodcastPlayer应用程
序文件位于文件夹Samples/PodcastPlayer中。该应用程序包含以下文件:
文件描述
PodcastPlayer.mxml适用于Flex(MXML)或Flash(FLA)的应用程序的
或用户界面。
PodcastPlayer.fla
RSSBase.as为RSSChannel类和RSSItem类提供公共属性和
方法的基类。
RSSChannel.as保存RSS频道的相关数据的ActionScript类。
RSSItem.as保存RSS项目的相关数据的ActionScript类。
SoundFacade.as应用程序的主ActionScript类。它封装Sound类和
SoundChannel类的方法和事件,并添加对回放暂
停和恢复的支持。
URLService.as从远程URL检索数据的ActionScript类。
playerconfig.xml这是一个XML文件,其中包含表示播客频道的
RSS新闻频道列表。
读取播客频道的RSS数据
PodcastPlayer应用程序先读取一些播客频道及其节目的相关信息:
1.首先,应用程序读取包含播客频道列表的XML配置文件,并向用户显示该频道列表。
2.当用户选择其中的一个播客频道时,它将读取该频道的RSS新闻频道并显示频道节目
列表。
此示例使用URLLoader实用程序类,从远程位置或本地文件检索基于文本的数据。
PodcastPlayer先创建一个URLLoader对象,以便从playerconfig.xml文件中获取采用
XML格式的RSS新闻频道列表。接下来,当用户从列表中选择特定新闻频道时,将创建一
个新的URLLoader对象以从该新闻频道的URL中读取RSS数据。
536
处理声音
使用SoundFacade类简化声音加载和回放
ActionScript3.0声音体系结构功能强大,但非常复杂。如果应用程序只需要基本的声音加
载和回放功能,可使用通过提供一组更简单的方法调用和事件来隐藏某些复杂性的类。在软
件设计模式领域中,这样的类称为“外观”。
SoundFacade类表示用于执行以下任务的单个接口:
■使用Sound对象、SoundLoaderContext对象以及SoundMixer类来加载声音文件
■使用Sound对象和SoundChannel对象来播放声音文件
■调度回放进度事件
■使用Sound对象和SoundChannel对象来暂停和恢复声音回放
SoundFacade类尝试以更简化的方式提供ActionScriptSound类的大部分功能。
以下代码显示了类声明、类属性以及SoundFacade()构造函数方法:
publicclassSoundFacadeextendsEventDispatcher
{
publicvars:Sound;
publicvarsc:SoundChannel;
publicvarurl:String;
publicvarbufferTime:int=1000;
publicvarisLoaded:Boolean=false;
publicvarisReadyToPlay:Boolean=false;
publicvarisPlaying:Boolean=false;
publicvarisStreaming:Boolean=true;
publicvarautoLoad:Boolean=true;
publicvarautoPlay:Boolean=true;
publicvarpausePosition:int=0;
publicstaticconstPLAY_PROGRESS:String="playProgress";
publicvarprogressInterval:int=1000;
publicvarplayTimer:Timer;
publicfunctionSoundFacade(soundUrl:String,autoLoad:Boolean=true,
autoPlay:Boolean=true,streaming:Boolean=true,
bufferTime:int=-1):void
{
this.url=soundUrl;
//设置决定此对象行为的布尔值
this.autoLoad=autoLoad;
this.autoPlay=autoPlay;
this.isStreaming=streaming;
//采用默认全局bufferTime值
if(bufferTime<0)
示例:PodcastPlayer
537
{
}
bufferTime=SoundMixer.bufferTime;
}
//将缓冲时间保持在合理的范围内:介于0和30秒之间
this.bufferTime=Math.min(Math.max(0,bufferTime),30000);
if(autoLoad)
{
load();
}
SoundFacade类扩展了EventDispatcher类,以使其能够调度自己的事件。类代码先声明
Sound对象和SoundChannel对象的属性。该类还会存储声音文件URL的值以及对声音
进行流式传输时使用的bufferTime属性。此外,它还接受某些影响加载和回放行为的布尔
参数值:
■autoLoad参数通知对象,应在创建此对象后立即启动声音加载。
■autoPlay参数指示在加载了足够多的声音数据后应立即启动声音播放。如果这是声音流,
在加载了足够多的数据(由bufferTime属性指定)后将立即开始回放。
■streaming参数指示可以在加载完成之前开始播放此声音文件。
bufferTime参数的默认值为-1。如果构造函数方法在bufferTime参数中检测到负值,它
会将bufferTime属性设置为SoundMixer.bufferTime的值。这样,应用程序便可根据需要
默认使用全局SoundMixer.bufferTime值。
如果将autoLoad参数设置为true,构造函数方法将立即调用以下load()方法来开始加载
声音文件:
publicfunctionload():void
{
if(this.isPlaying)
{
this.stop();
this.s.close();
}
this.isLoaded=false;
this.s=newSound();
this.s.addEventListener(ProgressEvent.PROGRESS,onLoadProgress);
this.s.addEventListener(Event.OPEN,onLoadOpen);
this.s.addEventListener(Event.COMPLETE,onLoadComplete);
this.s.addEventListener(Event.ID3,onID3);
this.s.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
this.s.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onIOError);
varreq:URLRequest=newURLRequest(this.url);
538
处理声音
}
varcontext:SoundLoaderContext=newSoundLoaderContext(this.bufferTime,
true);
this.s.load(req,this.slc);
load()方法创建一个新的Sound对象,然后为所有重要的声音事件添加侦听器。接下来,
它通知Sound对象使用SoundLoaderContext对象传入bufferTime值以加载声音文件。
由于可以更改url属性,因此,可以使用SoundFacade实例来连续播放不同的声音文件:
只需更改url属性并调用load()方法,即可加载新的声音文件。
以下三个事件侦听器方法说明了SoundFacade对象如何跟踪加载进度并确定何时开始播放
声音:
publicfunctiononLoadOpen(event:Event):void
{
if(this.isStreaming)
{
this.isReadyToPlay=true;
if(autoPlay)
{
this.play();
}
}
this.dispatchEvent(event.clone());
}
publicfunctiononLoadProgress(event:ProgressEvent):void
{
this.dispatchEvent(event.clone());
}
publicfunctiononLoadComplete(event:Event):void
{
this.isReadyToPlay=true;
this.isLoaded=true;
this.dispatchEvent(evt.clone());
if(autoPlay&&!isPlaying)
{
play();
}
}
在开始加载声音时,将执行onLoadOpen()方法。如果可以使用流模式播放声音,
onLoadComplete()方法会立即将isReadyToPlay标志设置为true。isReadyToPlay标志
确定应用程序能否开始播放声音,这可能为了响应用户动作,如单击“播放”按钮。
SoundChannel类管理声音数据的缓冲,因此在调用play()方法之前,不需要显式地检查
是否加载了足够多的数据。
示例:PodcastPlayer
539
在加载过程中,将定期执行onLoadProgress()方法。它仅调度其ProgressEvent对象的克
隆,该对象由使用此SoundFacade对象的代码使用。
当完全加载了声音数据后,将执行onLoadComplete()方法,以便为非声音流调用play()
方法(如果需要)。下面显示了play()方法本身。
publicfunctionplay(pos:int=0):void
{
if(!this.isPlaying)
{
if(this.isReadyToPlay)
{
this.sc=this.s.play(pos);
this.sc.addEventListener(Event.SOUND_COMPLETE,onPlayComplete);
this.isPlaying=true;
this.playTimer=newTimer(this.progressInterval);
this.playTimer.addEventListener(TimerEvent.TIMER,onPlayTimer);
this.playTimer.start();
}
}
}
如果已准备好播放声音,play()方法将调用Sound.play()方法。生成的SoundChannel
对象存储在sc属性中。play()方法随后创建一个Timer对象,该对象用于按固定间隔调
度回放进度事件。
显示回放进度
创建Timer对象以实现回放监视是一个很复杂的操作,您只需对其编码一次。通过在可重用
的类(如SoundFacade类)中封装此Timer逻辑,应用程序可以在加载和播放声音时侦听
相同类型的进度事件。
由SoundFacade.play()方法创建的Timer对象每秒调度一个TimerEvent实例。每当新
的TimerEvent到达时,就会执行以下onPlayTimer()方法:
publicfunctiononPlayTimer(event:TimerEvent):void
{
varestimatedLength:int=
Math.ceil(this.s.length/(this.s.bytesLoaded/this.s.bytesTotal));
varprogEvent:ProgressEvent=
newProgressEvent(PLAY_PROGRESS,false,false,this.sc.position,
estimatedLength);
this.dispatchEvent(progEvent);
}
onPlayTimer()方法可实现第523页的“监视回放”一节中描述的大小估计方法。然后,
它创建一个事件类型为SoundFacade.PLAY_PROGRESS的新ProgressEvent实例,并将
bytesLoaded属性设置SoundChannel对象的当前位置,而将bytesTotal属性设置为估
计的声音数据长度。
540
处理声音
暂停和恢复回放
以前显示的SoundFacade.play()方法接受pos参数,该参数与声音数据中的起始位置相对
应。如果pos值为零,则从开头开始播放声音。
SoundFacade.stop()方法也接受pos参数,如下所示:
publicfunctionstop(pos:int=0):void
{
if(this.isPlaying)
{
this.pausePosition=pos;
this.sc.stop();
this.playTimer.stop();
this.isPlaying=false;
}
}
每当调用SoundFacade.stop()方法时,它都会设置pausePosition属性,以便当用户要恢
复回放相同的声音时应用程序知道将播放头放置在什么位置。
下面显示的SoundFacade.pause()和SoundFacade.resume()方法分别调用
SoundFacade.stop()和SoundFacade.play()方法,以便每次传递pos参数值。
publicfunctionpause():void
{
stop(this.sc.position);
}
publicfunctionresume():void
{
play(this.pausePosition);
}
pause()方法将当前的SoundChannel.position值传递给play()方法,后者将该值存储
在pausePosition属性中。resume()方法通过使用pausePosition值作为起点再次开始
播放相同的声音。
扩展PodcastPlayer示例
此示例呈现了一个框架PodcastPlayer,用于说明如何使用可重用的SoundFacade类。您
可以添加其它功能以改进此应用程序的用途,其中包括以下功能:
■将新闻频道列表和有关每个节目的使用信息存储在SharedObject实例中,下次用户运
行应用程序时便可以使用它们。
■允许用户将其自己的RSS新闻频道添加到播客频道列表中。
■当用户停止或离开节目时,记住播放头的位置,以便下次用户运行应用程序时能够从该
位置重新开始播放。
下载节目的mp3文件,以便用户在没有连接到Internet时可以脱机收听。
添加订阅功能,以便定期检查播客频道中的新节目并自动更新节目列表。
使用来自播客托管服务(如Odeo.com)的API添加播客搜索和浏览功能
注
|
|