Как реализовать пространственный звук с помощью Swift на IOS 18?IOS

Программируем под IOS
Ответить
Anonymous
 Как реализовать пространственный звук с помощью Swift на IOS 18?

Сообщение Anonymous »

У меня возникла проблема с реализацией пространственных звуковых эффектов в моем приложении для iOS 18. Я пробовал несколько подходов для достижения эффекта 3D-звука, но результат никогда не был достаточно хорошим или вообще не работал.
Проблема, которая меня больше всего беспокоит, заключается в том, что я заметил, что у меня есть AirPods. не распознаю мое приложение как приложение с пространственным звуком. В настройках звука отображается сообщение «Пространственное аудио не воспроизводится», что заставляет меня думать, что мое приложение не использует потенциал пространственного звука.
Возможно, уместно упомянуть, что я использую личную команду. учетную запись.
Первый подход использует AVAudioEnviromentNode с AVAudioEngine. Несмотря на настройку параметров playerNode.position и прослушивателя, пространственные эффекты, похоже, не работают. Изменение ListenerPosition или playerNode.position не оказывает заметного влияния на воспроизведение.
Вот упрощенный пример инициализации AVAudioEngine:
import Foundation
import AVFoundation

class AudioManager: ObservableObject {
// important class variables
var audioEngine: AVAudioEngine!
var environmentNode: AVAudioEnvironmentNode!
var playerNode: AVAudioPlayerNode!
var audioFile: AVAudioFile?
...
//Sound set up
func setupAudio() {
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playback, mode: .default, options: [])
try session.setActive(true)
} catch {
print("Failed to configure AVAudioSession: \(error.localizedDescription)")
}

audioEngine = AVAudioEngine()
environmentNode = AVAudioEnvironmentNode()
playerNode = AVAudioPlayerNode()
audioEngine.attach(environmentNode)
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: environmentNode, format: nil)
audioEngine.connect(environmentNode, to: audioEngine.mainMixerNode, format: nil)
environmentNode.listenerPosition = AVAudio3DPoint(x: 0, y: 0, z: 0)
environmentNode.listenerAngularOrientation = AVAudio3DAngularOrientation(yaw: 0, pitch: 0, roll: 0)
environmentNode.distanceAttenuationParameters.referenceDistance = 1.0 environmentNode.distanceAttenuationParameters.maximumDistance = 100.0
environmentNode.distanceAttenuationParameters.rolloffFactor = 2.0
// example.mp3 is mono sound
guard let audioURL = Bundle.main.url(forResource: "example", withExtension: "mp3") else {
print("Audio file not found")
return
}

do {
audioFile = try AVAudioFile(forReading: audioURL)
} catch {
print("Failed to load audio file: \(error)")
}
}
...
//Playing sound
func playSpatialAudio(pan: Float ) {
guard let audioFile = audioFile else { return }
// left side
playerNode.position = AVAudio3DPoint(x: pan, y: 0, z: 0)
playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)

do {
try audioEngine.start()
playerNode.play()
} catch {
print("Failed to start audio engine: \(error)")
}
...
}

Второй подход более сложен с использованием PHASE — он работает лучше. Я создал образцовое приложение, которое позволяет игрокам перемещать источник звука в трехмерном пространстве. Я добавил реверберацию и ползунки, изменяющие положение звука на расстоянии до 10 метров в каждом направлении от слушателя, но кажется, что звук действительно меняется только слева направо (ось X) - опять же, я думаю, что это может быть проблема с тем, что приложение не распознается как пространственное (AirPods в настройках по-прежнему отображается сообщение «Пространственное аудио не воспроизводится»).
Вот пример настройки:
class PHASEAudioController: ObservableObject{
//Crucial class Variables:
private var soundSourcePosition: simd_float4x4 = matrix_identity_float4x4
private var audioAsset: PHASESoundAsset!
private let phaseEngine: PHASEEngine
private let params = PHASEMixerParameters()
private var soundSource: PHASESource
private var phaseListener: PHASEListener!
private var soundEventAsset: PHASESoundEventNodeAsset?

// Initialization of PHASE
init{
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playback, mode: .default, options: [])

try session.setActive(true)
} catch {
print("Failed to configure AVAudioSession: \(error.localizedDescription)")
}
// Init PHASE Engine
phaseEngine = PHASEEngine(updateMode: .automatic)
phaseEngine.defaultReverbPreset = .mediumHall
phaseEngine.outputSpatializationMode = .automatic //nothing helps
// Set listener position to (0,0,0) in World space
let origin: simd_float4x4 = matrix_identity_float4x4
phaseListener = PHASEListener(engine: phaseEngine)
phaseListener.transform = origin
phaseListener.automaticHeadTrackingFlags = .orientation
try! self.phaseEngine.rootObject.addChild(self.phaseListener)
do{
try self.phaseEngine.start();
}
catch {
print("Could not start PHASE engine")
}

audioAsset = loadAudioAsset()
// Create sound Source
// Sphere
soundSourcePosition.translate(z:3.0)
let sphere = MDLMesh.newEllipsoid(withRadii: vector_float3(0.1,0.1,0.1), radialSegments: 14, verticalSegments: 14, geometryType: MDLGeometryType.triangles, inwardNormals: false, hemisphere: false, allocator: nil)
let shape = PHASEShape(engine: phaseEngine, mesh: sphere)
soundSource = PHASESource(engine: phaseEngine, shapes: [shape])
soundSource.transform = soundSourcePosition
print(soundSourcePosition)
do {
try phaseEngine.rootObject.addChild(soundSource)
}
catch {
print ("Failed to add a child object to the scene.")
}
let simpleModel = PHASEGeometricSpreadingDistanceModelParameters()
simpleModel.rolloffFactor = rolloffFactor
soundPipeline.distanceModelParameters = simpleModel

let samplerNode = PHASESamplerNodeDefinition(
soundAssetIdentifier: audioAsset.identifier,
mixerDefinition: soundPipeline,
identifier: audioAsset.identifier + "_SamplerNode")
samplerNode.playbackMode = .looping
do {soundEventAsset = try
phaseEngine.assetRegistry.registerSoundEventAsset(
rootNode: samplerNode,
identifier: audioAsset.identifier + "_SoundEventAsset")
} catch {
print("Failed to register a sound event asset.")
soundEventAsset = nil
}
}

//Playing sound
func playSound(){
// Fire new sound event with currently set properties
guard let soundEventAsset else { return }

params.addSpatialMixerParameters(
identifier: soundPipeline.identifier,
source: soundSource,
listener: phaseListener)
let soundEvent = try! PHASESoundEvent(engine: phaseEngine,
assetIdentifier: soundEventAsset.identifier,
mixerParameters: params)
soundEvent.start(completion: nil)
}
...
}

Я также экспериментировал с RealityKit, но надеюсь найти решение без использования AR-представления. PHASE кажется лучшим вариантом, если оно работает так, как задумано.
Чего я ожидаю
Я надеюсь, что мое приложение будет правильно позиционировать звук в трехмерном пространстве по всем осям, как в некоторых других пространственных приложениях, доступных на iOS, и приложение будет распознаваться как приложение с поддержкой пространственного звука например, AirPods.


Подробнее здесь: https://stackoverflow.com/questions/793 ... -on-ios-18
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»