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

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

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


咱们上季讲的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为音频文件添加音效

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

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

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


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

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

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到音频文件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容