as3 加載外部聲音文件問題詳細(xì)剖析

理解聲音的結(jié)構(gòu)
應(yīng)用程序可以從4個地方加載聲音:
運(yùn)行時從外部聲音文件里加載
內(nèi)嵌到SWF文件里的聲音資源
從連接到用戶系統(tǒng)的麥克風(fēng)上獲取聲音數(shù)據(jù)
從遠(yuǎn)程多媒體服務(wù)器,比如Flash Media Server獲取聲音流
可以等到聲音全部加載后再播放,也可以邊加載邊播放。
ActionScript 3.0和Flash Player支持以mp3格式存儲的聲音。它們不能直接加載或播放其他格式的聲音,比如WAV或AIFF。
使用Adobe Flash CS3 Professional,可以導(dǎo)入WAV或AIFF格式的聲音,然后就可以把它們以MP3的格式嵌入到SWF文件中。Flash開發(fā)工具可以壓縮嵌入的聲音文件以減少文件大小,不過這樣需要以降低聲音質(zhì)量的代價。更多信息查看 "Importing Sounds" in Using Flash.
ActionScript3.0聲音使用flash.media包中的下列類
類 |
描述 |
flash.media.Sound |
Sound類用來加載聲音,管理聲音的基本屬性以及使聲音開始播放 |
flash.media.SoundChannel |
當(dāng)程序播放一個聲音對象的時候,會創(chuàng)建一個新的SoundChannel對象控制播放。SoundChannel對象同時控制聲音的左右頻道。每個播放的聲音都有自己的SoundChannel對象。 |
flash.media.SoundLoaderContext |
SoundLoaderContext類指定當(dāng)加載一個聲音的時候使用多少秒的緩沖區(qū),以及從服務(wù)器加載文件的時候FlashPlayer是否查找跨域策略文件。SoundLoaderContext對象作為Sound.load() 方法的參數(shù)使用。 |
flash.media.SoundMixer |
SoundMixer類控制程序中所有聲音的回放及安全屬性。實(shí)際上,多個聲音頻道通過一個共同的SoundMixer對象混合在一起,因此,SoundMixer對象的屬性會影響正在播放的所有SoundChannel對象。 |
flash.media.SoundTransform |
SoundTransform類包含用于控制音量和平衡的值。SoundTransform對象可以應(yīng)用到一個單獨(dú)的SoundChannel對象,全局的SoundMixer對象或者一個Microphone對象。 |
flash.media.ID3Info |
ID3Info對象包含mp3文件中的ID3元數(shù)據(jù)信息。 |
flash.media.Microphone |
Microphone類表示連接到用戶電腦上的麥克風(fēng)或者其他聲音輸入設(shè)備。從麥克風(fēng)輸入的音頻可以傳送到本地喇叭上或者遠(yuǎn)程服務(wù)器上。Microphone對象控制它自己聲音流的取樣率。 |
每個加載和播放的聲音都需要它自己的Sound類和SoundChannel類。從多個SoundChannel實(shí)例輸出的聲音在播放中通過全局的SoundMixer混合在一起。
Sound,SoundChannel和SoundMixer類不能用在從麥克風(fēng)或者流媒體服務(wù)器獲取的聲音上。
加載外部聲音文件
Sound類的每個實(shí)例都用來加載和回放指定的聲音。應(yīng)用程序不能重復(fù)使用一個Sound對象加載多于一個的聲音。如果想加載一個新的聲音,需要創(chuàng)建一個新的聲音對象。
如果加載一個小的聲音文件,比如要附加在按鈕上的點(diǎn)擊聲音,可以像下面這樣創(chuàng)建一個新的Sound,然后讓它自動加載聲音文件:
ActionScript Code:
var req:URLRequest = new URLRequest("click.mp3");
var s:Sound = new Sound(req);
Sound()構(gòu)造函數(shù)使用一個URLRequest對象作為第一個參數(shù)。當(dāng)指定了URLRequest參數(shù)的時候,Sound對象就開始自動加載指定的聲音文件。
除了這個最簡單的情況之外,應(yīng)用程序都應(yīng)該注意聲音的加載過程并監(jiān)視加載過程中出現(xiàn)的錯誤。比如,如果這個點(diǎn)擊聲音特別的大,可能在用戶點(diǎn)擊按鈕觸發(fā)這個聲音的時候這個聲音文件還沒有完全加載完。試圖播放一個未加載完的聲音可能導(dǎo)致一個運(yùn)行期錯誤。安全的做法是等聲音完全加載后再允許用戶的那些可能導(dǎo)致聲音播放的行為。
在聲音加載過程中,Sound對象會發(fā)送幾個不同的事件。應(yīng)用程序可以監(jiān)聽這些事件來跟蹤加載過程以確保聲音在完全加載后才能播放。下表列出了聲音對象可能發(fā)送的事件。
事件 |
描述 |
open (Event.OPEN) |
在聲音加載操作剛開始時發(fā)送。 |
progress (ProgressEvent.PROGRESS) |
當(dāng)從文件或者流中接收到數(shù)據(jù)的時候周期性的發(fā)送。 |
id3 (Event.ID3) |
當(dāng)一個mp3聲音的ID3數(shù)據(jù)可用時發(fā)送。 |
complete (Event.COMPLETE) |
當(dāng)聲音的所有數(shù)據(jù)加載完后發(fā)送。 |
ioError (IOErrorEvent.IO_ERROR) |
如果聲音文件不能定位或者加載過程中在所有數(shù)據(jù)接收完之前被中斷的時候發(fā)送。 |
下面的代碼演示了如何在聲音加載完后播放一個聲音:
ActionScript Code:
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
var s:Sound = new Sound();
s.addEventListener(Event.COMPLETE, onSoundLoaded);
var req:URLRequest = new URLRequest("bigSound.mp3");
s.load(req);
function onSoundLoaded(event:Event):void
{
var localSound:Sound = event.target as Sound;
localSound.play();
}
首先,這段示例代碼創(chuàng)建了一個新的Sound對象,但并沒有指定URLRequest參數(shù)。然后,它監(jiān)聽Sound對象的Event.COMPLETE事件,當(dāng)所有聲音數(shù)據(jù)加載完后執(zhí)行onSoundLoaded()方法。接下來,它使用一個新的URLRequest值調(diào)用Sound.load()方法。
當(dāng)聲音全部加載完后執(zhí)行onSoundLoaded()方法。Event對象的target屬性是Sound對象的引用。調(diào)用Sound對象的play()方法開始播放聲音。
監(jiān)視聲音加載過程
聲音可能非常大,加載需要相當(dāng)長的時間。FlashPlayer允許在聲音全部加載完前就能播放,你可能想想給用戶一個顯示聲音加載了多少以及播放了多少。
Sound類的兩個事件使得顯示加載進(jìn)度變得相當(dāng)容易: ProgressEvent.PROGRESS和Event.COMPLETE. 下面的代碼展示了如何使用這些事件顯示聲音的加載進(jìn)度:
ActionScript Code:
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.media.Sound;
import flash.net.URLRequest;
var s:Sound = new Sound();
s.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
s.addEventListener(Event.COMPLETE, onLoadComplete);
s.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
var req:URLRequest = new URLRequest("bigSound.mp3");
s.load(req);
function onLoadProgress(event:ProgressEvent):void
{
var loadedPct:uint = Math.round(100 * (event.bytesLoaded / event.bytesTotal));
trace("The sound is " + loadedPct + "% loaded.");
}
function onLoadComplete(event:Event):void
{
var localSound:Sound = event.target as Sound;
localSound.play();
}
function onIOError(event:IOErrorEvent)
{
trace("The sound could not be loaded: " + event.text);
}
這段代碼首先創(chuàng)建了一個Sound對象,然后為事件ProgressEvent.PROGRESS和Event.COMPLETE添加監(jiān)聽器。在調(diào)用了Sound.load()方法及收到第一組數(shù)據(jù)后,開始出現(xiàn)ProgressEvent.PROGRESS事件,觸發(fā)onSoundLoadProgress() 方法。
聲音加載的百分比等于ProgressEvent對象的bytesLoaded屬性除以bytesTotal屬性。在Sound對象上同樣可以獲取bytesLoaded和bytesTotal。上面的代碼簡單展示了聲音加載信息,但是你可以使用bytesLoaded和bytesTotal值來控制進(jìn)度條組件。
這段代碼同樣展示了如何組織和響應(yīng)加載中發(fā)生的錯誤。比如,如果無法定位指定的聲音文件,會發(fā)送Event.IO_ERROR事件。前面代碼中當(dāng)發(fā)生錯誤時會調(diào)用onIOError()方法顯示簡單的錯誤信息。
使用嵌入的聲音
好了,下面我們把聲音導(dǎo)入到庫里使用。
打開Flash CS3,選擇文件->導(dǎo)入到庫,選擇好聲音,然后確定后會導(dǎo)入聲音。打開庫面板,找到我們導(dǎo)入的聲音,右鍵,選擇”linkage…”菜單
< XMLNAMESPACE PREFIX ="V" />
會彈出如下框,選擇Export for ActionScript注意觀察這個彈出框
它與AS2中明顯不同的是,標(biāo)識符欄(identifier欄)不能填寫,而類(Class)和基類(Base class)欄必須填寫。類的名字默認(rèn)是聲音的文件名,但是名字中只能能有字母數(shù)字,且以字母開頭,因此圖中的名字01.mp3是不合格的,可以改為mp3或其他符合規(guī)則的名字?;惥褪莊lash.media.Sound。我們點(diǎn)確定,會彈出下框:
大意是指定的類”mp3″在類路徑下找不到,在SWF文件導(dǎo)出時會自動為你創(chuàng)建一個類。點(diǎn)確定就可以了。
在幀上寫如下代碼:
ActionScript Code:
var drum:mp3 = new mp3();
var channel:SoundChannel = drum.play();
導(dǎo)出,就可以聽到聲音了。
[as3]播放聲音
播放一個加載的聲音可以簡單的調(diào)用Sound對象的Sound.play()方法,就像下面這樣:
ActionScript Code:
var snd:Sound = new Sound(new URLRequest("smallSound.mp3"));
snd.play();
當(dāng)使用ActionScript3.0播放聲音的時候,你可以實(shí)現(xiàn)下列操作:
從一個指定的位置播放聲音(不一定是最開始)
暫停聲音,然后從暫停的位置處重新開始播放
可以精確的知道聲音什么時候播放完了
跟蹤聲音的播放進(jìn)度
當(dāng)聲音播放的時候改變音量或者均衡
要在播放過程中實(shí)現(xiàn)這些效果,使用SoundChannel, SoundMixer, 和 SoundTransform 類.
SoundChannel控制一個單獨(dú)的聲音的播放.SoundChannel.position屬性可以被當(dāng)作播放頭,用來指示數(shù)據(jù)播放的位置.
當(dāng)程序調(diào)用Sound.play()方法時,會創(chuàng)建一個新的SoundChannel實(shí)例來控制播放.
程序可以為Sound.play()方法指定它的startTime參數(shù),該參數(shù)接收以毫秒為單位的數(shù)字,這樣就可以使聲音從指定的位置開始播放.
如果同時指定了Sound.play()方法的startTime參數(shù)和loops參數(shù),那么當(dāng)聲音會從相同的起始位置重復(fù)播放就像下面這樣:
ActionScript Code:
var snd:Sound = new Sound(new URLRequest("repeatingSound.mp3"));
snd.play(1000, 3);
在這個例子中,聲音會接連從離開始1秒的位置播放3次.
暫停和重新開始聲音
如果你的程序播放一個長聲音,比如一首歌或者播客(podcasts,暫譯為播客),你可能想允許用戶可以暫停,然后繼續(xù)播放這個聲音.然后聲音并不能像字面意思那樣實(shí)現(xiàn)暫停,它只能停止(從字面意思上來講,暫停跟停止是不同的,我們想實(shí)現(xiàn)暫停效果,但是沒有直接的ActionScript語句可以實(shí)現(xiàn)暫停).但是,聲音可以從任何位置處播放.因此你可以記錄下它停止的位置,然后從這個位置后面開始播放,就實(shí)現(xiàn)了暫停效果.
比如,首先像下面這樣加載并播放一個聲音:
ActionScript Code:
var snd:Sound = new Sound(new URLRequest("bigSound.mp3"));
var channel:SoundChannel = snd.play();
當(dāng)聲音播放的時候SoundChannel.position屬性顯示聲音當(dāng)前的播放位置.程序可以像下面這個例子一樣,在停止它之前記錄下它的位置:
ActionScript Code:
var pausePosition:int = channel.position;
channel.stop();
要重新播放聲音,傳遞之前記錄的播放位置數(shù)據(jù)來使聲音從它停止的地方重新開始播放.
ActionScript Code:
channel = snd.play(pausePosition);
監(jiān)視播放
你的程序可能需要知道什么時候它停止了播放,以便去播放另一個聲音,或者清除在播放過程中使用的一些資源.當(dāng)聲音播放完畢的時候SoundChannel類發(fā)送一個Event.SOUND_COMPLETE事件. 你的程序可以監(jiān)聽這個事件并作出適當(dāng)?shù)膭幼?就像下面這樣:
ActionScript Code:
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
var snd:Sound = new Sound("smallSound.mp3");
var channel:SoundChannel = snd.play();
s.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
public function onPlaybackComplete(event:Event)
{
trace("The sound has finished playing.");
}
SoundChannel類在播放中并不發(fā)送進(jìn)度事件.要報(bào)告播放進(jìn)度,你可以自己設(shè)置一個時間進(jìn)制并跟蹤播放頭的位置.
可以使用SoundChannel.position屬性值除以聲音長度來計(jì)算已播放的百分?jǐn)?shù):
ActionScript Code:
var playbackPercent:uint = 100 * (channel.position / snd.length);
但是,只有在播放前聲音全部加載完了,這段代碼才能精確顯示播放的百分比.Sound.length屬性顯示的是當(dāng)前已加載的聲音長度,而不是聲音文件的的真實(shí)長度.你可以使用Sound對象的bytesLoaded和bytesTotal屬性估計(jì)聲音的長度:
ActionScript Code:
var estimatedLength:int =
Math.ceil(snd.length / (snd.bytesLoaded / snd.bytesTotal));
var playbackPercent:uint = 100 * (channel.position / estimatedLength);
下面的代碼加載一個比較大的聲音文件,并使用Event.ENTER_FRAME事件作為顯示播放進(jìn)度的時間機(jī)制.它周期性的報(bào)告播放的百分比,這個百分比是用當(dāng)前位置除以聲音總長度計(jì)算出來的:
ActionScript Code:
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
var snd:Sound = new Sound();
var req:URLRequest = new
URLRequest("http://av.adobe.com/podcast/csbu_dev_podcast_epi_2.mp3");
snd.load(req);
var channel:SoundChannel;
channel = snd.play();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
snd.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
function onEnterFrame(event:Event):void
{
var estimatedLength:int =
Math.ceil(snd.length / (snd.bytesLoaded / snd.bytesTotal));
var playbackPercent:uint =
Math.round(100 * (channel.position / estimatedLength));
trace("Sound playback is " + playbackPercent + "% complete.");
}
function onPlaybackComplete(event:Event)
{
trace("The sound has finished playing.");
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
在開始加載聲音數(shù)據(jù)后,調(diào)用方法snd.play()并把結(jié)果保存在類型為SoundChannel,名子為channel的變量中. 然后為主程序添加了Event.ENTER_FRAME事件的監(jiān)聽器,為SoundChannel對象的Event.SOUND_COMPLETE事件也添加了監(jiān)聽器.
在動畫中每到達(dá)一個新幀的時候,onEnterFrame()方法就會被調(diào)用.onEnterFrame()根據(jù)已經(jīng)加載的數(shù)據(jù)估算聲音的總長度,然后顯示當(dāng)前播放的百分?jǐn)?shù).
當(dāng)整個聲音播放完后,會執(zhí)行onPlaybackComplete()方法,移除Event.ENTER_FRAME事件的監(jiān)聽器,因?yàn)椴シ磐旰缶筒恍枰趫?bào)告播放進(jìn)度了.
Event.ENTER_FRAME事件每秒會發(fā)送好幾次.在某些情況下,你可能不想發(fā)送的這么頻繁.那么,你就可以使用flash.util.Timer類設(shè)置自己的時間機(jī)制.
停止流聲音
流聲音(指的是在完全加載之前就播放的聲音)在播放過程中有一個特點(diǎn)需要注意.當(dāng)你的程序調(diào)用SoundChannel.stop()方法的時候,聲音會停止一幀,而在下一幀它會從開始的地方重新開始播放. 之所以發(fā)生這種情況,是因?yàn)槁曇羧匀辉诩虞d中.要停止加載和播放,使用Sound.close()方法.
解決聲音以數(shù)據(jù)流形式放到時間軸上導(dǎo)出后音質(zhì)變差的問題
[關(guān)鍵字]Flash 數(shù)據(jù)流 聲音 音質(zhì)變差 立體聲轉(zhuǎn)換成單聲道
[問題描述]:將聲音放到時間軸上,選擇數(shù)據(jù)流的同步方式,在Flash中聽聲音沒有發(fā)現(xiàn)問題,但是導(dǎo)出后音質(zhì)變的奇差,基本上不能用,雖然將聲音同步方式選擇開始或者事件可以解決這個問題,但是有時是非要用數(shù)據(jù)流同步方式不可的(因?yàn)橐貌シ艜和?刂?,因?yàn)橛羞M(jìn)度條控制)。
[解決辦法]:這是由于在導(dǎo)出時,F(xiàn)lash會以MP3的形式壓縮聲音,一般會把聲音壓縮成比特率低于22Kbps的聲音,同時將立體聲轉(zhuǎn)換成了單聲道聲音,很多聲音都是因?yàn)閷⒘Ⅲw聲轉(zhuǎn)換成單聲道后音質(zhì)變差的。因此我們要去掉次選項(xiàng)。
如果Flash中有很多聲音,那么我們要更改發(fā)布設(shè)置。
1、打開發(fā)布設(shè)置,點(diǎn)開”Flash”選項(xiàng)卡,找到音頻流設(shè)置的項(xiàng),如下圖
2、點(diǎn)開設(shè)置按鈕,
3、將比特率選擇24kbps(或者其他的高于22kbps的項(xiàng),因?yàn)橹挥羞@樣才能更改”將立體聲轉(zhuǎn)換成單聲道”)
4、勾掉”將立體聲轉(zhuǎn)換成單聲道”前面的勾,然后確定就可以了
然后再導(dǎo)出,基本上就沒有問題了。
相關(guān)文章
flash cs6鼠標(biāo)跟隨效果實(shí)現(xiàn)代碼分享
flash cs6想要實(shí)現(xiàn)鼠標(biāo)跟隨效果?該怎么制作呢?今天我們就來看看使用as2.0實(shí)現(xiàn)鼠標(biāo)跟隨效果的教程,需要的朋友可以參考下2019-05-19- Flash cs6怎么使用代碼輸入中英文文本?Flash cs6中可以使用文字工具直接輸入文本,也可以使用代碼來輸入文本,該怎么使用代碼輸入文本呢?請看下文詳細(xì)的教程,需要的朋友2018-03-11
- flash as3.0抽象類怎么定義? as3.0中有很多抽象類,該怎么定義抽象類和抽象方法呢?下面我們就來看看簡單的例子,需要的朋友可以參考下http://www.dbjr.com.cn/softs/408402.2018-02-28
flash cs6中怎么使用ActionScript3.0?
flash cs6中怎么使用ActionScript3.0?flash cs6中想要使用ActionScript3.0功能,該怎么使用呢?下面我們就來看看詳細(xì)的教程,需要的朋友可以參考下2018-01-25Flash中怎么實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊決定圖像位置?
本教程給大家分享一個Flash小教程,教大家在Flash CS6中怎么實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊決定圖像位置?方法很簡單,感興趣的朋友歡迎前來一起分享學(xué)習(xí)2018-01-12- 本教程教腳本之家的ActionScript教程學(xué)習(xí)者在Flash中如何用代碼將圖片放在自己想要的舞臺位置,教程講解的詳細(xì),感興趣的朋友歡迎前來分享學(xué)習(xí)2017-11-20
在Flash CS6中使用with函數(shù)繪制背景圖教程
本教程教腳本之家的ActionScript教程學(xué)習(xí)者如何在Flash CS6中使用with函數(shù)繪制背景圖?教程一步步講解的挺詳細(xì),方法也不難,非常適合Flash新手入門學(xué)習(xí)2017-11-18Flash怎么設(shè)置元件坐標(biāo)?flash使用代碼設(shè)置元件的坐標(biāo)的教程
Flash怎么設(shè)置元件坐標(biāo)?flash中導(dǎo)如的元件需要添加坐標(biāo),該怎么定位元件坐標(biāo)呢?下面我們就來看看flash使用代碼設(shè)置元件的坐標(biāo)的教程,需要的朋友可以參考下2017-10-11- Flash怎么制作來回?fù)u擺的花朵的動畫?Flash中想要給花朵制作一段搖擺的動畫效果,該怎么制作呢?下面我們就來看看詳細(xì)的教程,很簡單,需要的朋友可以參考下2017-05-23
- Flash怎么制作流動七彩色的文字?想要讓文字動起來,該怎么使用flash給文字制作一個流動七彩色的動畫呢?下面我們就來看看詳細(xì)的教程,需要的朋友可以參考下2017-04-23