AVFoundation连续系列之五为音乐文件添加音效

AVFoundation连续系列之五为音乐文件添加音效

咱们再次回顾下咱们的AVAudioNode,它是咱们AVAudioEngine工作的时候最小的一个元素类,咱们上季讲的是它里面的一个音频单位(AVAudioUnit)中的AVAudioUnitEffect,继续看下这张图:


AVFoundation连续系列之五为音乐文件添加音效_第1张图片

咱们上季讲的AVAudioUnitEffect既可以用于实时音频,也可以用于给音频文件添加音效,这季咱们看下,怎么给音频文件添加音效。

要给咱们音频文件添加音效,就需要使用咱们另外一个音频节点了-AVAudioPlayerNode(音频播放器节点)。

一、AVAudioPlayerNode

1.介绍

音频播放器节点可以播放音频的buffer、也可以播放音频文件的一段。

播放音频文件的某段,需要传入咱们的AVAudioFile

当咱们指定播放的内容后,就是咱们一系列播放的控制了,如预播放、播放、停止、暂停、播放指定位置。

咱们看下音频播放器节点的常用方法属性

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.实现

2.1咱们先看看它的简单实现吧!

lazyvarengine =AVAudioEngine()

lazyvarplayer =AVAudioPlayerNode()

overridefuncviewDidLoad() {

super.viewDidLoad()

//音频文件的路径

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

leturl =NSURL.init(string: path!)

//创建音频文件对象

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

//将音频播放器节点附着到音频引擎

engine.attachNode(player)

//设置音频播放器节点

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

player.volume=1.0

//音频引擎连接节点

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

}

@IBActionfuncplayOrStop(sender:AnyObject) {

try!engine.start()

player.play()

}

2.2为音频文件添加音效

上面是没有给音频文件添加音效的,大家猜测下,怎么给音频文件添加音效呢?

这就是我让大家看上面那张图的原因,音频播放器节点,他也是一个普通的节点,咱们要想给音频文件添加音效,可以直接把音效附着到咱们的音频引擎上,连接的时候,把音频播放器、音效等节点连接到一起,这样音效就添加好了。

但是连接的时候,大家一定要注意连接的顺序,这也是咱们在讲音频引擎的时候就重点提出要注意的。还是看一下这前面的另一张图:


AVFoundation连续系列之五为音乐文件添加音效_第2张图片

看到图咱们连接的顺序也就出来了,音频输入->效果器->输出

好!咱们看下添加音效的案例:

lazyvarengine =AVAudioEngine()

lazyvarplayer =AVAudioPlayerNode()

overridefuncviewDidLoad() {

super.viewDidLoad()

//音频文件的路径

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

leturl =NSURL.init(string: path!)

//创建音频文件对象

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

//将音频播放器节点附着到音频引擎

engine.attachNode(player)

//设置音频播放器节点

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

player.volume=1.0

//初始化并设置混响效果器节点

letreverb =AVAudioUnitReverb()

reverb.loadFactoryPreset(.MediumHall)

reverb.wetDryMix=80

engine.attachNode(reverb)

//音频引擎连接节点

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初始化方式:

读取文件的创建

public init(forReading fileURL:NSURL)throws

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

写入文件的创建

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参数获取、设置

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"))

//创建音频文件对象

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)

})

//初始化并设置混响效果器节点

letreverb =AVAudioUnitReverb()

reverb.loadFactoryPreset(.MediumHall)

reverb.wetDryMix=80

engine.attachNode(reverb)

//音频引擎连接节点

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一样。如果你想得到一个添加完音效的音频文件发你哥们去炫耀,那请等下季分享。

好!这季咱们也就先玩到这!

下次见!

所有代码在这里:

播放器节点示例

写入buffer到音频文件

你可能感兴趣的:(AVFoundation连续系列之五为音乐文件添加音效)