Saving sound after effect in iOS

I am developing an application so that people can record and change their voices through the application and share it. I basically have so many things, and now is the time to ask you for help. Here is my play function, which plays the recorded audio file and adds effects to it.

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() } 

I think the problem is that I am setting TapOnBus to audioPlayerNode, but the processed sound is on audioEngine.outputNode. However, I tried setting TapOnBus to audioEngine.outputNode, but it gives me an error. I also tried connecting effects to audioEngine.mixerNode but this is also not a solution. So, do you have experience in saving an audio file? How can I get this sound?

Any help is appreciated

thanks

+6
source share
3 answers

Here is my solution to the question:

 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() } 
+4
source

This seems to be incorrectly connected. I just learn all this myself, but found that the effects were added correctly when you connect them to the node mixer. Also, you want to click the mixer, not the output of the node engine. I just copied your code and made a few changes to take this into account.

 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() } 

I also failed to format the file correctly. I finally got it working when I changed my path to the output file from m4a to caf . Another suggestion is to not have nil for the format parameter. I used audioFile.processingFormat . Hope this helps. My sound effects / mixes are functional, although I did not link my effects. So feel free to ask questions.

+4
source

For those who have a problem playing the TWICE audio file in order to save it, I simply added the following line to the appropriate place and solved my problem. may help someone in the future.

PS: I used EXACTLY the same code as the verified answer above, just added this one line and solved my problem.

 //Do what you want to do here with effected Audio self.newAudio = try! AVAudioFile(forReading: tmpFileUrl) 
0
source

All Articles