AVFoundation連續(xù)系列之五為音樂文件添加音效

AVFoundation連續(xù)系列之五為音樂文件添加音效

咱們再次回顧下咱們的AVAudioNode迫悠,它是咱們AVAudioEngine工作的時候最小的一個元素類,咱們上季講的是它里面的一個音頻單位(AVAudioUnit)中的AVAudioUnitEffect闻蛀,繼續(xù)看下這張圖:


咱們上季講的AVAudioUnitEffect既可以用于實時音頻,也可以用于給音頻文件添加音效,這季咱們看下崩掘,怎么給音頻文件添加音效吼驶。

要給咱們音頻文件添加音效惩激,就需要使用咱們另外一個音頻節(jié)點了-AVAudioPlayerNode(音頻播放器節(jié)點)。

一蟹演、AVAudioPlayerNode

1.介紹

音頻播放器節(jié)點可以播放音頻的buffer风钻、也可以播放音頻文件的一段。

播放音頻文件的某段酒请,需要傳入咱們的AVAudioFile

當咱們指定播放的內(nèi)容后骡技,就是咱們一系列播放的控制了,如預播放羞反、播放布朦、停止、暫停昼窗、播放指定位置是趴。

咱們看下音頻播放器節(jié)點的常用方法屬性

1.1設(shè)置播放內(nèi)容和完成的操作

播放音頻流

public funcscheduleBuffer(buffer:AVAudioPCMBuffer, completionHandler:AVAudioNodeCompletionHandler?)

public funcscheduleBuffer(buffer:AVAudioPCMBuffer, atTime when:AVAudioTime?, options:AVAudioPlayerNodeBufferOptions, completionHandler:AVAudioNodeCompletionHandler?)

播放音頻文件

public funcscheduleFile(file:AVAudioFile, atTime when:AVAudioTime?, completionHandler:AVAudioNodeCompletionHandler?)

public funcscheduleSegment(file:AVAudioFile, startingFrame startFrame:AVAudioFramePosition, frameCount numberFrames:AVAudioFrameCount, atTime when:AVAudioTime?, completionHandler:AVAudioNodeCompletionHandler?)

1.2播放器的操作

public funcstop()

public funcprepareWithFrameCount(frameCount:AVAudioFrameCount)

public funcplay()

public func playAtTime(when:AVAudioTime?)

public func pause()

public func nodeTimeForPlayerTime(playerTime:AVAudioTime) ->AVAudioTime?

public func playerTimeForNodeTime(nodeTime:AVAudioTime) ->AVAudioTime?

public var playing:Bool{ get }

2.實現(xiàn)

2.1咱們先看看它的簡單實現(xiàn)吧!

lazyvarengine =AVAudioEngine()

lazyvarplayer =AVAudioPlayerNode()

overridefuncviewDidLoad() {

super.viewDidLoad()

//音頻文件的路徑

letpath =NSBundle.mainBundle().pathForResource("short", ofType:"mp3")

leturl =NSURL.init(string: path!)

//創(chuàng)建音頻文件對象

letaudioFile =try!AVAudioFile.init(forReading: url!)

//將音頻播放器節(jié)點附著到音頻引擎

engine.attachNode(player)

//設(shè)置音頻播放器節(jié)點

player.scheduleFile(audioFile, atTime:nil, completionHandler:nil)

player.volume=1.0

//音頻引擎連接節(jié)點

engine.connect(player, to:engine.outputNode, format: audioFile.processingFormat)

}

@IBActionfuncplayOrStop(sender:AnyObject) {

try!engine.start()

player.play()

}

2.2為音頻文件添加音效

上面是沒有給音頻文件添加音效的澄惊,大家猜測下唆途,怎么給音頻文件添加音效呢?

這就是我讓大家看上面那張圖的原因掸驱,音頻播放器節(jié)點肛搬,他也是一個普通的節(jié)點,咱們要想給音頻文件添加音效毕贼,可以直接把音效附著到咱們的音頻引擎上温赔,連接的時候,把音頻播放器鬼癣、音效等節(jié)點連接到一起陶贼,這樣音效就添加好了。

但是連接的時候待秃,大家一定要注意連接的順序骇窍,這也是咱們在講音頻引擎的時候就重點提出要注意的。還是看一下這前面的另一張圖:


看到圖咱們連接的順序也就出來了锥余,音頻輸入->效果器->輸出

好腹纳!咱們看下添加音效的案例:

lazyvarengine =AVAudioEngine()

lazyvarplayer =AVAudioPlayerNode()

overridefuncviewDidLoad() {

super.viewDidLoad()

//音頻文件的路徑

letpath =NSBundle.mainBundle().pathForResource("short", ofType:"mp3")

leturl =NSURL.init(string: path!)

//創(chuàng)建音頻文件對象

letaudioFile =try!AVAudioFile.init(forReading: url!)

//將音頻播放器節(jié)點附著到音頻引擎

engine.attachNode(player)

//設(shè)置音頻播放器節(jié)點

player.scheduleFile(audioFile, atTime:nil, completionHandler:nil)

player.volume=1.0

//初始化并設(shè)置混響效果器節(jié)點

letreverb =AVAudioUnitReverb()

reverb.loadFactoryPreset(.MediumHall)

reverb.wetDryMix=80

engine.attachNode(reverb)

//音頻引擎連接節(jié)點

engine.connect(player, to: reverb, format: audioFile.processingFormat)

engine.connect(reverb, to:engine.outputNode, format: audioFile.processingFormat)

}

@IBActionfuncplayOrStop(sender:AnyObject) {

try!engine.start()

player.play()

}

這個就是咱們音頻播放器的基本操作了,咱們看下還沒有具體去看的音頻文件(AVAudioFile)這個類。

二:AVAudioFile

1.介紹

還是老習慣嘲恍,列舉下他常用的方法屬性

1.1初始化方式:

讀取文件的創(chuàng)建

public init(forReading fileURL:NSURL)throws

public init(forReading fileURL:NSURL, commonFormat format:AVAudioCommonFormat, interleaved:Bool)throws

寫入文件的創(chuàng)建

public init(forWriting fileURL:NSURL, settings: [String:AnyObject])throws

public init(forWriting fileURL:NSURL, settings: [String:AnyObject], commonFormat format:AVAudioCommonFormat, interleaved:Bool)throws

1.2參數(shù)獲取足画、設(shè)置

public func readIntoBuffer(buffer:AVAudioPCMBuffer)throws 讀取buffer實體

public func readIntoBuffer(buffer:AVAudioPCMBuffer, frameCount frames:AVAudioFrameCount)throws 讀取buffer中的一部分

public func writeFromBuffer(buffer:AVAudioPCMBuffer)throws 寫入buffer

public var url:NSURL{ get } 獲得文件的url

public var fileFormat:AVAudioFormat{ get } 獲得文件的格式

public var processingFormat:AVAudioFormat{ get } 獲得處理的格式

public var length:AVAudioFramePosition{ get } 獲得音頻幀的長度

public var framePosition:AVAudioFramePosition 獲得音頻幀的位置

咱們看到這個音頻文件的類中,包含了關(guān)于文件全面的操作佃牛。它里面包含寫入buffer的方法淹辞!是不是可以錄音呢浩姥?當然可以枫笛!

2.使用AVAudioFile寫入buffer

直接上代碼:

lazyvarengine =AVAudioEngine()

varaudioFile:AVAudioFile?

overridefuncviewDidLoad() {

super.viewDidLoad()

//音頻文件的路徑

letpath =NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask,true).first!asNSString

leturl =NSURL.init(string: path .stringByAppendingPathComponent("audio.caf"))

//創(chuàng)建音頻文件對象

audioFile=try!AVAudioFile.init(forWriting: url!, settings: [:])

letinput =engine.inputNode!

input.installTapOnBus(0, bufferSize:4096, format: input.inputFormatForBus(0), block: { (buffer, audioTime)in

//注意獲得到的是一個為添加音效的原聲

try!self.audioFile?.writeFromBuffer(buffer)

})

//初始化并設(shè)置混響效果器節(jié)點

letreverb =AVAudioUnitReverb()

reverb.loadFactoryPreset(.MediumHall)

reverb.wetDryMix=80

engine.attachNode(reverb)

//音頻引擎連接節(jié)點

engine.connect(input, to: reverb, format:audioFile!.processingFormat)

engine.connect(reverb, to:engine.outputNode, format:audioFile!.processingFormat)

}

@IBActionfuncplayOrStop(sender:AnyObject) {

letbutton = senderas!UIButton

button.selected= button.selected!=true?true:false

button.setTitle("stop", forState: .Selected)

ifbutton.selected==true{

print(NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask,true).first)

try!engine.start()

}else{

engine.inputNode?.removeTapOnBus(0)

engine.stop()

}

}

這里需要注意赫舒!這里就像是全民K歌的案例一樣讨便,咱們是錄制的時候添加的實時音效!但是錄制好的是原聲畏铆。就像咱們?nèi)TV一樣默伍。如果你想得到一個添加完音效的音頻文件發(fā)你哥們?nèi)レ乓酰钦埖认录痉窒怼?/p>

好惫东!這季咱們也就先玩到這莉给!

下次見!

所有代碼在這里:

播放器節(jié)點示例

寫入buffer到音頻文件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廉沮,一起剝皮案震驚了整個濱河市颓遏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滞时,老刑警劉巖叁幢,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坪稽,居然都是意外死亡遥皂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門刽漂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弟孟,你說我怎么就攤上這事贝咙。” “怎么了拂募?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵庭猩,是天一觀的道長。 經(jīng)常有香客問我陈症,道長蔼水,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任录肯,我火速辦了婚禮趴腋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己优炬,他們只是感情好颁井,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蠢护,像睡著了一般雅宾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上葵硕,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天眉抬,我揣著相機與錄音,去河邊找鬼懈凹。 笑死蜀变,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蘸劈。 我是一名探鬼主播昏苏,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼威沫!你這毒婦竟也來了贤惯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤棒掠,失蹤者是張志新(化名)和其女友劉穎孵构,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烟很,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡颈墅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了雾袱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恤筛。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芹橡,靈堂內(nèi)的尸體忽然破棺而出毒坛,到底是詐尸還是另有隱情,我是刑警寧澤林说,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布煎殷,位于F島的核電站,受9級特大地震影響腿箩,放射性物質(zhì)發(fā)生泄漏豪直。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一珠移、第九天 我趴在偏房一處隱蔽的房頂上張望弓乙。 院中可真熱鬧末融,春花似錦、人聲如沸唆貌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锨咙。三九已至语卤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酪刀,已是汗流浹背粹舵。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骂倘,地道東北人眼滤。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像历涝,于是被迫代替她去往敵國和親诅需。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容