I want to do a simple "record user's microphone -> apply an effect -> save to wav file" chain using AudioKit in Swift.
Below is the code I'm trying to use. What I get instead is that I hear the output through the headphones (with pitch effect applied), but output file is empty. What am I doing wrong?
import AudioKit
import AVFoundation
import SoundpipeAudioKit
class AudioRecorder: ObservableObject {
let engine = AudioEngine()
var recoder: NodeRecorder?
private(set) lazy var outputFileURL: URL = {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsPath.appendingPathComponent("recording.wav")
}()
func startRecording() {
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print("Failed to set up recording session.")
return
}
guard let input = engine.input else {
print("No audio input found")
return
}
do {
recorder = try NodeRecorder(node: input, fileDirectoryURL: outputFileURL)
} catch let err {
fatalError("\(err)")
}
let pitchShifter = PitchShifter(input)
engine.output = pitchShifter
do {
try engine.start()
} catch {
print("Unable to start audio engine: \(error.localizedDescription)")
return
}
}
func stopRecording() {
engine.stop()
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch {
print("Failed to stop recording session.")
}
}
}
Try changing following to make it work:
Line var recoder: NodeRecorder?
Change to var recorder: NodeRecorder?
// missing r
Line return documentsPath.appendingPathComponent("recording.wav")
Change to return documentsPath
// NodeRecorder wants a directory, not a file in fileDirectoryURL
Add the pitchShifter
to the audiograph before adding the recorder, as you want to record the shifted audio.
Record and save to a .waf in two different steps. NodeRecorder records to a temporary .caf which you then can move or encode and send.
NodeRecorder has some built in file management, beware of shouldCleanupRecordings:
as it's default to true
--
let pitchShifter = PitchShifter(input)
do {
recorder = try NodeRecorder(node: pitchShifter, fileDirectoryURL: outputFileURL, shouldCleanupRecordings:false)
} catch let err {
fatalError("\(err)")
}
engine.output = pitchShifter
Furthermore check out the Cookbook of AudioKit, this example will help: https://github.com/AudioKit/Cookbook/blob/main/Cookbook/CookbookCommon/Sources/CookbookCommon/Recipes/MiniApps/Recorder.swift