Export audio file after adding an effect
Asked Answered
U

1

14

I have an audio file that I want to process using some effects (like pitch effect) and then write the final result to a file.

Before I process the file and save it to disc I let the user play with the pitch effect and listen to the changes in real time.

this is how I do the real time stuff:

let audioSession = AVAudioSession.sharedInstance()
audioSession.setCategory(AVAudioSessionCategoryPlayback, error: nil)
audioSession.setActive(true, error: nil)

audioEngine = AVAudioEngine()
audioFile = AVAudioFile(forReading: audioUrl!, error: nil)

audioPlayerNode = AVAudioPlayerNode()
audioEngine.attachNode(audioPlayerNode)

changePitchEffect = AVAudioUnitTimePitch()
changePitchEffect.pitch = 1.0 // default
audioEngine.attachNode(changePitchEffect)

audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)

let frameCapacity = UInt32(audioFile.length)
let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: frameCapacity)
if audioFile.readIntoBuffer(buffer, error: nil) {

    audioEngine.startAndReturnError(nil)

    audioPlayerNode.scheduleBuffer(buffer, atTime: nil, options: .Loops, completionHandler: nil)

    audioPlayerNode.play() // start playing in a loop
}

then using a UISlider I let the user change the value of the pitch while listening to the audio in a loop.

So when the user finishes playing with the pitch and taps the next button, I need to save the audio file with the chosen pitch value.

My question is, how do I create a new audio file with the pitch effect?

I don't want to record while the user is listening to the audio and play with the pitch effect, I only want to export the final result (without playing the file of course)

Unconscious answered 16/8, 2015 at 14:19 Comment(0)
A
6

Since using AVAudioSession is not an explicit requirement in the title of the question, there are 2 possible answers:

Play through the node (with AVAudioSession)

Install a tap on the node. See AV Foundation Framework Reference.

audioPlayerNode.installTapOnBus(0, bufferSize:frameLength, format: audioInputNode.outputFormatForBus(0), block: {(buffer, time) in
    let channels = UnsafeArray(start: buffer.floatChannelData, length: Int(buffer.format.channelCount))
    let floats = UnsafeArray(start: channels[0], length: Int(buffer.frameLength))

    for var i = 0; i < Int(self.audioBuffer.frameLength); i+=Int(self.audioMixerNode.outputFormatForBus(0).channelCount)
    {
        // process
    }
})

The AVAudioSession tap mechanism requires play though. More about recording while playing on the Stack Overflow answer by @matt.


Use AudioUnit (without AVAudioSession)

Initialize an AudioSession with AudioSessionInitialize to play & record, set up a read & write stream, and pass a AURenderCallbackStruct pointing to your data processing code. This, however, precludes you from capitalizing upon AVAudioUnitTimePitch. You can find out more about this solution in this How to do realtime recording with effect processing on iOS article.

Auvergne answered 20/8, 2015 at 21:23 Comment(1)
10x for yr comment but regarding the first option, as I wrote, I dont want to record while playing. the second option is not clear to me, and I understand I wont be able to use the pitch effectUnconscious

© 2022 - 2024 — McMap. All rights reserved.