I'm trying to setup a simple rotation of a 3D sound around a listener in iOS 12.3.1 using the AVAudioFramework. The idea is to have a listener in the center, a sound at 10m distance form the listener, and then rotate the listener.
I can get the sound to play, but not as spatial sound. Can someone point me where the problem might be ?
Here is my code so far:
import UIKit import AVFoundation
class ViewController: UIViewController {
var engine: AVAudioEngine!
var player: AVAudioPlayerNode!
var environment: AVAudioEnvironmentNode!
private var currentYaw: Float = 0
private var rotationSpeed: Float = 50.0 / 60.0 // 50 degrees per second, divided by 60 to get per frame at 60Hz
private var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
engine = AVAudioEngine()
player = AVAudioPlayerNode()
environment = AVAudioEnvironmentNode()
guard let fileURL = Bundle.main.url(forResource: "hello", withExtension: "wav") else {
fatalError("Could not find audio file!")
}
do {
let audioFile = try AVAudioFile(forReading: fileURL)
// Check the format of the audio file.
print("File format: \(audioFile.fileFormat)")
print("Processing format: \(audioFile.processingFormat)")
engine.attach(player)
engine.attach(environment)
let stereoFormat = AVAudioFormat(standardFormatWithSampleRate: audioFile.fileFormat.sampleRate, channels: 2)!
// Connect player to environment node and then to the main mixer using stereo format
engine.connect(player, to: environment, format: stereoFormat)
engine.connect(environment, to: engine.mainMixerNode, format: stereoFormat)
// Set the rendering algorithm on the environment node
environment.renderingAlgorithm = .HRTFHQ
// Position the player at the centre
if let positionalPlayer = player as? AVAudio3DMixing {
positionalPlayer.position = AVAudio3DPoint(x: 0, y: 0, z: 0)
}
// Position the sound 10m in front of the center
if let positionalEnvironment = environment as? AVAudio3DMixing {
positionalEnvironment.position = AVAudio3DPoint(x: 0, y: 0, z: 10)
}
player.scheduleFile(audioFile, at: nil, completionHandler: nil)
engine.prepare()
try engine.start()
player.play()
// Start the timer to update the listener's orientation
timer = Timer.scheduledTimer(timeInterval: 1.0/60.0, target: self, selector: #selector(updateListenerOrientation), userInfo: nil, repeats: true)
} catch let error {
fatalError("Error: \(error.localizedDescription)")
}
}
@objc func updateListenerOrientation() {
// Update yaw
currentYaw -= rotationSpeed
if currentYaw < -360 { currentYaw += 360 }
// Set the updated yaw to the listener's orientation
environment.listenerAngularOrientation = AVAudio3DAngularOrientation(yaw: currentYaw, pitch: 0, roll: 0)
// Print the updated value for debugging
print("Updated listenerAngularOrientation:", environment.listenerAngularOrientation)
}
deinit {
timer?.invalidate()
}
}