在 iOS 中保存音频 After Effect
Saving Audio After Effect in iOS
我正在开发一个应用程序,以便人们可以通过应用程序录制和改变他们的声音并分享它。基本上我有很多事情,现在是时候请你帮忙了。这是我的播放功能,它播放录制的音频文件并为其添加效果。
private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the platback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioEngine.outputNode, format: nil)
audioPlayerNode.stop()
let length = 4000
let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length))
buffer.frameLength = AVAudioFrameCount(length)
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a"))
do{
print(dirPaths)
let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)]
self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings)
audioEngine.outputNode.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioPlayerNode.outputFormatForBus(0)){
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in
print(self.newAudio.length)
print("=====================")
print(self.audioFile.length)
print("**************************")
if (self.newAudio.length) < (self.audioFile.length){
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioPlayerNode.removeTapOnBus(0)
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
我想问题是我正在将 TapOnBus 安装到 audioPlayerNode 但受影响的音频是 audioEngine.outputNode。但是我尝试将 TapOnBus 安装到 audioEngine.outputNode 但它给了我 error.Also 我已经试图将效果连接到 audioEngine.mixerNode 但它也不是解决方案。那么您在保存受影响的音频文件方面有什么经验吗?我怎样才能得到这个受影响的音频?
感谢任何帮助
谢谢
这似乎连接不正确。我只是自己学习这一切,但我发现当您将它们连接到混音器节点时,效果会正确添加。此外,您需要点击混音器,而不是引擎输出节点。我刚刚复制了您的代码并进行了一些修改以考虑到这一点。
private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the playback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Set up a mixer node
let audioMixer = AVAudioMixerNode()
audioEngine.attachNode(audioMixer)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioMixer, format: nil)
audioEngine.connect(audioMixer, to: audioEngine.outputNode, format: nil)
audioPlayerNode.stop()
let length = 4000
let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length))
buffer.frameLength = AVAudioFrameCount(length)
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a"))
do{
print(dirPaths)
let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)]
self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings)
audioMixer.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioMixer.outputFormatForBus(0)){
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in
print(self.newAudio.length)
print("=====================")
print(self.audioFile.length)
print("**************************")
if (self.newAudio.length) < (self.audioFile.length){
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioMixer.removeTapOnBus(0)
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
我也无法正确格式化文件。当我将输出文件的路径从 m4a
更改为 caf
时,我终于让它工作了。另一个建议是 format
参数不要有 nil
。我用的是audioFile.processingFormat
。我希望这有帮助。我的音频 effects/mixing 可以正常使用,尽管我没有链接我的效果器。所以请随时提问。
这是我对问题的解答:
func playAndRecord(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
// These are global variables . if you want you can just (let audioEngine = etc ..) init here these variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
playerB = AVAudioPlayerNode()
audioEngine.attachNode(playerB)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the platback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioEngine.mainMixerNode, format: nil)
// Good practice to stop before starting
audioPlayerNode.stop()
// Play the audio file
// this player is also a global variable AvAudioPlayer
if(player != nil){
player?.stop()
}
// audioFile here is our original audio
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: {
print("Complete")
})
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound2.m4a"))
//Save the tmpFileUrl into global varibale to not lose it (not important if you want to do something else)
filteredOutputURL = tmpFileUrl
do{
print(dirPaths)
self.newAudio = try! AVAudioFile(forWriting: tmpFileUrl, settings: [
AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless),
AVEncoderAudioQualityKey : AVAudioQuality.Low.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey: 2,
AVSampleRateKey : 44100.0
])
let length = self.audioFile.length
audioEngine.mainMixerNode.installTapOnBus(0, bufferSize: 1024, format: self.audioEngine.mainMixerNode.inputFormatForBus(0)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
print(self.newAudio.length)
print("=====================")
print(length)
print("**************************")
if (self.newAudio.length) < length {//Let us know when to stop saving the file, otherwise saving infinitely
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioEngine.mainMixerNode.removeTapOnBus(0)//if we dont remove it, will keep on tapping infinitely
//DO WHAT YOU WANT TO DO HERE WITH EFFECTED AUDIO
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
对于遇到必须播放两次音频文件才能保存它的问题的任何人,我只是在相应的位置添加了以下行,它解决了我的问题。
将来可能会对某人有所帮助。
P.S:我使用了与上面检查过的答案完全相同的代码,只是添加了这一行并解决了我的问题。
//Do what you want to do here with effected Audio
self.newAudio = try! AVAudioFile(forReading: tmpFileUrl)
我添加后得到了这个
self.newAudio = try! AVAudioFile(forReading: tmpFileUrl)
return 像这样
Error
Domain=com.apple.coreaudio.avfaudio
Code=1685348671 "(null)" UserInfo={failed
call=ExtAudioFileOpenURL((CFURLRef)fileUR
L, &_extAudioFile)}
只需将参数 unsigned int 从 kAudioFormatMPEG4AAC 更改为 kAudioFormatLinearPCM 并将文件类型更改为 .caf 它肯定会对我的朋友有所帮助
我正在开发一个应用程序,以便人们可以通过应用程序录制和改变他们的声音并分享它。基本上我有很多事情,现在是时候请你帮忙了。这是我的播放功能,它播放录制的音频文件并为其添加效果。
private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the platback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioEngine.outputNode, format: nil)
audioPlayerNode.stop()
let length = 4000
let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length))
buffer.frameLength = AVAudioFrameCount(length)
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a"))
do{
print(dirPaths)
let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)]
self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings)
audioEngine.outputNode.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioPlayerNode.outputFormatForBus(0)){
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in
print(self.newAudio.length)
print("=====================")
print(self.audioFile.length)
print("**************************")
if (self.newAudio.length) < (self.audioFile.length){
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioPlayerNode.removeTapOnBus(0)
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
我想问题是我正在将 TapOnBus 安装到 audioPlayerNode 但受影响的音频是 audioEngine.outputNode。但是我尝试将 TapOnBus 安装到 audioEngine.outputNode 但它给了我 error.Also 我已经试图将效果连接到 audioEngine.mixerNode 但它也不是解决方案。那么您在保存受影响的音频文件方面有什么经验吗?我怎样才能得到这个受影响的音频?
感谢任何帮助
谢谢
这似乎连接不正确。我只是自己学习这一切,但我发现当您将它们连接到混音器节点时,效果会正确添加。此外,您需要点击混音器,而不是引擎输出节点。我刚刚复制了您的代码并进行了一些修改以考虑到这一点。
private func playAudio(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the playback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Set up a mixer node
let audioMixer = AVAudioMixerNode()
audioEngine.attachNode(audioMixer)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioMixer, format: nil)
audioEngine.connect(audioMixer, to: audioEngine.outputNode, format: nil)
audioPlayerNode.stop()
let length = 4000
let buffer = AVAudioPCMBuffer(PCMFormat: audioPlayerNode.outputFormatForBus(0),frameCapacity:AVAudioFrameCount(length))
buffer.frameLength = AVAudioFrameCount(length)
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound.m4a"))
do{
print(dirPaths)
let settings = [AVFormatIDKey: NSNumber(unsignedInt: kAudioFormatMPEG4AAC), AVSampleRateKey: NSNumber(integer: 44100), AVNumberOfChannelsKey: NSNumber(integer: 2)]
self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings: settings)
audioMixer.installTapOnBus(0, bufferSize: (AVAudioFrameCount(self.player!.duration)), format: self.audioMixer.outputFormatForBus(0)){
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) in
print(self.newAudio.length)
print("=====================")
print(self.audioFile.length)
print("**************************")
if (self.newAudio.length) < (self.audioFile.length){
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioMixer.removeTapOnBus(0)
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
我也无法正确格式化文件。当我将输出文件的路径从 m4a
更改为 caf
时,我终于让它工作了。另一个建议是 format
参数不要有 nil
。我用的是audioFile.processingFormat
。我希望这有帮助。我的音频 effects/mixing 可以正常使用,尽管我没有链接我的效果器。所以请随时提问。
这是我对问题的解答:
func playAndRecord(pitch : Float, rate: Float, reverb: Float, echo: Float) {
// Initialize variables
// These are global variables . if you want you can just (let audioEngine = etc ..) init here these variables
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)
playerB = AVAudioPlayerNode()
audioEngine.attachNode(playerB)
// Setting the pitch
let pitchEffect = AVAudioUnitTimePitch()
pitchEffect.pitch = pitch
audioEngine.attachNode(pitchEffect)
// Setting the platback-rate
let playbackRateEffect = AVAudioUnitVarispeed()
playbackRateEffect.rate = rate
audioEngine.attachNode(playbackRateEffect)
// Setting the reverb effect
let reverbEffect = AVAudioUnitReverb()
reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
reverbEffect.wetDryMix = reverb
audioEngine.attachNode(reverbEffect)
// Setting the echo effect on a specific interval
let echoEffect = AVAudioUnitDelay()
echoEffect.delayTime = NSTimeInterval(echo)
audioEngine.attachNode(echoEffect)
// Chain all these up, ending with the output
audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
audioEngine.connect(echoEffect, to: audioEngine.mainMixerNode, format: nil)
// Good practice to stop before starting
audioPlayerNode.stop()
// Play the audio file
// this player is also a global variable AvAudioPlayer
if(player != nil){
player?.stop()
}
// audioFile here is our original audio
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: {
print("Complete")
})
try! audioEngine.start()
let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent("effectedSound2.m4a"))
//Save the tmpFileUrl into global varibale to not lose it (not important if you want to do something else)
filteredOutputURL = tmpFileUrl
do{
print(dirPaths)
self.newAudio = try! AVAudioFile(forWriting: tmpFileUrl, settings: [
AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless),
AVEncoderAudioQualityKey : AVAudioQuality.Low.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey: 2,
AVSampleRateKey : 44100.0
])
let length = self.audioFile.length
audioEngine.mainMixerNode.installTapOnBus(0, bufferSize: 1024, format: self.audioEngine.mainMixerNode.inputFormatForBus(0)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
print(self.newAudio.length)
print("=====================")
print(length)
print("**************************")
if (self.newAudio.length) < length {//Let us know when to stop saving the file, otherwise saving infinitely
do{
//print(buffer)
try self.newAudio.writeFromBuffer(buffer)
}catch _{
print("Problem Writing Buffer")
}
}else{
self.audioEngine.mainMixerNode.removeTapOnBus(0)//if we dont remove it, will keep on tapping infinitely
//DO WHAT YOU WANT TO DO HERE WITH EFFECTED AUDIO
}
}
}catch _{
print("Problem")
}
audioPlayerNode.play()
}
对于遇到必须播放两次音频文件才能保存它的问题的任何人,我只是在相应的位置添加了以下行,它解决了我的问题。 将来可能会对某人有所帮助。
P.S:我使用了与上面检查过的答案完全相同的代码,只是添加了这一行并解决了我的问题。
//Do what you want to do here with effected Audio
self.newAudio = try! AVAudioFile(forReading: tmpFileUrl)
我添加后得到了这个
self.newAudio = try! AVAudioFile(forReading: tmpFileUrl)
return 像这样
Error
Domain=com.apple.coreaudio.avfaudio
Code=1685348671 "(null)" UserInfo={failed
call=ExtAudioFileOpenURL((CFURLRef)fileUR
L, &_extAudioFile)}
只需将参数 unsigned int 从 kAudioFormatMPEG4AAC 更改为 kAudioFormatLinearPCM 并将文件类型更改为 .caf 它肯定会对我的朋友有所帮助