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

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

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


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

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

一、AVAudioPlayerNode

1.介紹

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

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

當咱們指定播放的內容后,就是咱們一系列播放的控制了,如預播放、播放、停止、暫停、播放指定位置。

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

1.1設置播放內容和完成的操作

播放音頻流

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)

//設置音頻播放器節(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)

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

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

player.volume=1.0

//初始化并設置混響效果器節(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ù)獲取、設置

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 獲得音頻幀的位置

咱們看到這個音頻文件的類中,包含了關于文件全面的操作。它里面包含寫入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)

})

//初始化并設置混響效果器節(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歌的案例一樣,咱們是錄制的時候添加的實時音效!但是錄制好的是原聲。就像咱們去KTV一樣。如果你想得到一個添加完音效的音頻文件發(fā)你哥們去炫耀,那請等下季分享。

好!這季咱們也就先玩到這!

下次見!

所有代碼在這里:

播放器節(jié)點示例

寫入buffer到音頻文件

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容