Modifying input audio

4 weeks ago 32
ARTICLE AD BOX

SwiftUI is not about audio at all, all effects are done in AVAudioEngine / Audio Units. What you did with reversing is offline buffer processing. A “robot” is done in roughly the same way, only instead of swap you pass the audio through a chain of effects and save the result.

Natively in AVFoundation this means running the file through effects and saving a new one

Docs

import AVFoundation final class AudioFX { enum Preset { case robot, radio, chipmunk, demon } func process(inputURL: URL, preset: Preset) throws -> URL { let inputFile = try AVAudioFile(forReading: inputURL) let engine = AVAudioEngine() let player = AVAudioPlayerNode() let pitch = AVAudioUnitTimePitch() let eq = AVAudioUnitEQ(numberOfBands: 2) let dist = AVAudioUnitDistortion() let reverb = AVAudioUnitReverb() engine.attach(player) engine.attach(pitch) engine.attach(eq) engine.attach(dist) engine.attach(reverb) let format = inputFile.processingFormat engine.connect(player, to: pitch, format: format) engine.connect(pitch, to: eq, format: format) engine.connect(eq, to: dist, format: format) engine.connect(dist, to: reverb, format: format) engine.connect(reverb, to: engine.mainMixerNode, format: format) configure(preset, pitch: pitch, eq: eq, dist: dist, reverb: reverb) let outURL = inputURL.deletingLastPathComponent() .appendingPathComponent("fx_\(preset)_\(inputURL.deletingPathExtension().lastPathComponent).caf") let outSettings: [String: Any] = [ AVFormatIDKey: kAudioFormatLinearPCM, AVSampleRateKey: format.sampleRate, AVNumberOfChannelsKey: format.channelCount, AVLinearPCMBitDepthKey: 32, AVLinearPCMIsFloatKey: true, AVLinearPCMIsNonInterleaved: true ] let outFile = try AVAudioFile(forWriting: outURL, settings: outSettings) let maxFrames: AVAudioFrameCount = 4096 let renderFormat = engine.mainMixerNode.outputFormat(forBus: 0) try engine.enableManualRenderingMode(.offline, format: renderFormat, maximumFrameCount: maxFrames) try engine.start() player.scheduleFile(inputFile, at: nil) player.play() let buffer = AVAudioPCMBuffer(pcmFormat: engine.manualRenderingFormat, frameCapacity: maxFrames)! while true { let status = try engine.renderOffline(maxFrames, to: buffer) switch status { case .success: try outFile.write(from: buffer) case .endOfStream: player.stop() engine.stop() engine.disableManualRenderingMode() return outURL case .cannotDoInCurrentContext, .insufficientDataFromInputNode: continue @unknown default: continue } } } private func configure(_ preset: Preset, pitch: AVAudioUnitTimePitch, eq: AVAudioUnitEQ, dist: AVAudioUnitDistortion, reverb: AVAudioUnitReverb) { pitch.rate = 1.0 pitch.pitch = 0 let hiPass = eq.bands[0] hiPass.filterType = .highPass hiPass.frequency = 250 hiPass.bypass = false let loPass = eq.bands[1] loPass.filterType = .lowPass loPass.frequency = 3500 loPass.bypass = false dist.wetDryMix = 0 reverb.wetDryMix = 0 switch preset { case .robot: dist.loadFactoryPreset(.speechRadioTower) dist.wetDryMix = 70 reverb.loadFactoryPreset(.mediumHall) reverb.wetDryMix = 12 case .radio: dist.loadFactoryPreset(.speechRadioTower) dist.wetDryMix = 45 case .chipmunk: pitch.pitch = 900 dist.loadFactoryPreset(.multiBrokenSpeaker) dist.wetDryMix = 15 case .demon: pitch.pitch = -700 dist.loadFactoryPreset(.speechGoldenPi) dist.wetDryMix = 20 } } }

If you mean a robot specifically as a vocoder, then AVFoundation does not have a ready-made vocoder out of the box, and here you either have to write your own Audio Unit or use a third-party library.

If you don’t want to deal with this yourself, AudioKit is an option.

It has convenient nodes and makes it easier to build effect chains. Repo

import AudioKit import SoundpipeAudioKit let engine = AudioEngine() let player = AudioPlayer(url: inputURL)! let shifter = PitchShifter(player) shifter.shift = 0 engine.output = shifter try engine.start() player.play()

You can simply apply an effect and save the file using native AVAudioEngine. If you want many effects and less manual work, use AudioKit. If you need a real vocoder, that’s already third-party DSP/AUv3 or your own Audio Unit.

Read Entire Article