Version: 2019.3
Plugin SDK del Audio Nativo de Unity
Audio Profiler (Perfilador de Audio)

Audio Spatializer SDK

Visión General

El audio spatializer SDK es una extensión del audio plugin SDK nativo que permite cambiar la manera que el audio se transmite de una fuente de audio al espacio alrededor. El panning integrado de las fuentes de audio se pueden tener en cuenta como una manera simple de espacialización en la que toma la fuente y regula los gains de las contribuciones del oído izquierdo y derecho basado en la distancia y ángulo entre el AudioListener y el AudioSource. Esto proporciona señales direccionales simples para el jugador en el plano horizontal.

Contexto

Con el advenimiento de los sistemas de realidad virtual y realidad aumentada, el método de espacialización se convierte cada vez más en un componente clave de la inmersión del jugador. Nuestros oídos y cerebros son muy conscientes de los retardos microscópicos entre el sonido recibido de una fuente en el oído izquierdo y derecho, respectivamente.

La oclusión de sonido es un problema muy difícil que resolver en términos de poder de computación. Dónde en global illumination (iluminación global) usted puede considerer el movimiento de la luz efectivamente instantáneo, el sonido se mueve muy lento. Por lo tanto calcular una manera que el sonido en realidad se mueva (como ondas) en un cuarto no es computacionalmente factible. Por la misma razón hay muchos enfoques hacia la espacialización en dónde se aborda diferentes problemas a diferentes niveles.

Algunas soluciones solamente están solucionando el problema HRTF. HTRF significa Head-Related Transfer Function, y una analogía aproximada de esto en el mundo de gráficos sería spherical harmonics: i.e un filtrado direccionalmente influenciado del sonido que aplicamos en ambas orejas que contiene el micro-retardo entre las orejas así como el filtrado direccional contribuido por las orejeras, la cabeza misma y los hombros. Agregar un filtrado HRTF ya mejora inmensamente la sensación de dirección sobre una solución convencional de filtración (un ejemplo típico y famoso de esto es la grabación binaural de la barbería virtual). El HRTF directo está algo limitado sin embargo, ya que solamente le importa la ruta directa del audio y no cómo es transmitida en el espacio.

La oclusión es el paso siguiente de esto en el que puede reflejar indirectamente el sonido rebotando las paredes. Para tomar otra aproximación equivalente del mundo de gráficos, esto se puede comparar a un specular reflection en la escena en el sentido que la ubicación de ambas la fuente y el listener determinan el resultado, y por supuesto cada onda direccional reflejada de sonido golpea cada oreja con una HRTF diferente y tiene un retardo diferente basado en la longitud de la trayectoria que ha recorrido la onda.

Finalmente hay reflejos de espacio que de muchas maneras corresponde a la parte difusa de una solución de global illumination (iluminación global) en que el sonido se emite en la habitación y se refleja en varias paredes antes de golpear las orejas como un campo de ondas superpuestas, cada una con una dirección diferente y un retraso acumulado relativo a la fuente de audio.

SDK y Ejemplo de Implementación

Con muchos problemas difíciles que resolver, existe una variedad de soluciones diferentes de audio spatialization (espacialización de audio). Nosotros encontramos que la mejor manera de soportar estas en Unity es crear una interfaz abierta, el Audio Spatializer SDK, la cual es una extensión encima del Native Audio Plugin SDK que permite el remplazo del panner estándar en Unity por uno más avanzado y le da acceso a meta-datos importantes sobre la fuente y el listener necesitado para la computación.

Una implementación ejemplo de un spatializer se proporciona aquí. Es intencionalmente simple en la manera que solo soporta un HRTF directo y necesita ser optimizado para su uso en producción. Acompañando el plugin hay un reverb (reverberación) simple, solo para mostrar cómo los datos de audio se pueden enrutar del plugin del spatializer al plugin de reverb (reverberación). El filtro de HRTF se basa en el conjunto de datos KEMAR, el cual es un conjunto de grabaciones de respuesta de impulsos por oído, realizadas en una cabeza dummy pro Bill Gardner, en el MIT Media Lab. Estas respuesta de impulso se convolucionan con la señal de entrada usando convolución rápida a través del Fast Fourier Transform. Los meta-datos de posición solamente se utilizan para recoger el conjunto de respuestas de impulso adecuado, a medida que el conjunto de datos consisten de unas respuestas de impulso arregladas de manera circular para ángulos elevados que oscilan entre –40 abajo a 90 grados encima de la cabeza.

Inicialización

Las diferencias principales entre un efecto de espacialización y los efectos del mezclador en Unity es que el spatializer se coloca justo después del decodificador de la fuente de audio que produce una transmisión de datos de audio para que cada fuente tenga su propia instancia de efecto procesando solamente el audio producido por la fuente. Esto es diferente de los plugins del audio mixer que procesan una mezcla de audio de varias fuentes de audio conectadas al grupo mezclador. Para habilitar que el plugin opere como esto es necesario configurar una flag en el campo de bits de descripción del efecto:

definition.flags |= UnityAudioEffectDefinitionFlags_IsSpatializer;

Configurar esta flag a penas en la inicialización le notifica a Unity durante la fase de escaneo de plugins que este es un spatializer, por lo que cuando una instancia de este plugin se crea, le va a signar la estructura de UnityAudioSpatializerData para la spatializerdata miembro de la estructura de UnityAudioEffectState.

Antes de ser capaz de utilizar el spatializer en el proyecto, esto se necesita que esté seleccionado en los Audio Project Settings (configuraciones de audio del proyecto):

Spatializer plugin selector
Spatializer plugin selector

En el AudioSource, la casilla de verificación Spatialize habilita que el spatializer se utilice. Esto también se puede controlar desde script mediante la propiedad AudioSource.spatialize. En un juego con muchos sonidos puede tener sentido solo habilitarlo con sonidos cercanos y utilizar un paneo tradicional en los distantes.

Casilla de verificación Spatializer en el AudioSource
Casilla de verificación Spatializer en el AudioSource

Meta-datos del efecto Spatializer

A diferencia de otros efectos que se ejecutan en el mezclador en una mezcla de sonidos, los spatializers se aplican directamente después que el AudioSource ha decodificado los datos de audio. Por lo tanto, cada instancia del efecto spatializer tiene su propia instancia de UnityAudioSpatializerData asociada con datos principalmente acerca del AudioSource.

struct UnityAudioSpatializerData
{
    float listenermatrix[16]; // Matrix that transforms sourcepos into the local space of the listener
    float sourcematrix[16];   // Transform matrix of audio source
    float spatialblend;       // Distance-controlled spatial blend
    float reverbzonemix;      // Reverb zone mix level parameter (and curve) on audio source
    float spread;             // Spread parameter of the audio source (0..360 degrees)
    float stereopan;          // Stereo panning parameter of the audio source (-1: fully left, 1: fully right)
                              // The spatializer plugin may override the distance attenuation in order to
                              // influence the voice prioritization (leave this callback as NULL to use the
                              // built-in audio source attenuation curve)
    UnityAudioEffect_DistanceAttenuationCallback distanceattenuationcallback;
};

La estructura contiene las matrices de transformación 4x4 completas para el listiner y la fuente. La matriz del listener ya ha sido invertida para que las dos matrices se puedan multiplicar para obtener un vector de dirección relativo. La matriz del listener siempre es orthonormal, por lo que la inversa es fácil de calcular. Adicionalmente, la estructura contiene campos correspondientes a las propiedades del audio source: Spatial Blend, Reverb Zone Mix, Spread y Stereo Pan. Es responsabilidad del spatializer en implementarlas correctamente, para cuando esté activo, el sistema de audio de Unity solamente proporcionará la fuente del sonido sin procesar como una señal stereo (incluso cuando la fuente sea mono o de varios canales, en tal caso el up- o down-mixing se utiliza).

Convenciones de matriz

El campo sourcematrix contiene una copia plena de la matriz de transformación asociada con el AudioSource. Para un audiosource simple en un game object que no está girado, será simplemente una matriz de translación donde la posición se codifica en los elementos 12, 13 y 14. El campo listenermatrix contiene la matriz de transformación inversa asociada con el AudioListener. Esto hace que sea muy conveniente determinar el vector de dirección del listener a la fuente así:

float dir_x = L[0] * S[12] + L[4] * S[13] + L[ 8] * S[14] + L[12];
float dir_y = L[1] * S[12] + L[5] * S[13] + L[ 9] * S[14] + L[13];
float dir_z = L[2] * S[12] + L[6] * S[13] + L[10] * S[14] + L[14];

dónde L es la listenermatrix y S es la sourcematrix. Si usted tiene un listenermatrix que no está girado y tiene una escala uniforme de 1 (las matrices de la cámara nunca se deben escalar), tenga en cuenta que la posición en (L[12], L[13], L[14]) es en realidad el valor negativo de lo que usted ve en el inspector de Unity. Esto se debe a que la listenermatrix es la matriz de transformación inversa de la cámara. Si la cámara también se girará, no seriamos capaz de leer las posiciones directamente de la matriz simplemente negando, pero tendría que deshacer el efecto de la rotación en primer lugar. Afortunadamente, es fácil invertir tales matrices de Transformación-Rotación-Escala como se describe aquí, por lo que necesitamos hacer es transponer la matriz de rotación izquierda 3x3 de L y calcular la posición así:

float listenerpos_x = -(L[0] * L[12] + L[ 1] * L[13] + L[ 2] * L[14]);
float listenerpos_y = -(L[4] * L[12] + L[ 5] * L[13] + L[ 6] * L[14]);
float listenerpos_z = -(L[8] * L[12] + L[ 9] * L[13] + L[10] * L[14]);

Curvas de atenuación y audibilidad

La única cosa que todavía se maneja por el sistema de audio de Unity es la atenuación de la distancia, la cual se aplica al sonido antes de que ingrese a la fase de spatialization, y esto es necesario para que el sistema de audio conozca la audibilidad aproximada de la fuente, la cual se puede utilizar para virtualizaciones dinámicas de sonidos basados en la importancia con el fin de que coincida con las Max Real Voices limit definidas por el usuario. Dado que se trata de un problema del huevo y la gallina, esta información no se recupera de las mediciones reales del nivel de la señal, sino que corresponde a la combinación de los valores que leemos de la curva de atenuación controlada por distancia, la propiedad de Volume y las atenuaciones aplicadas por el mezclador. Es, sin embargo, posible anular la curva de atenuación por si misma o utilizar el valor calculador por la curva del AudioSource como una base para modificar. Para hacer esto, hay un callback en la estructura del UnityAudioSpatializerData que puede ser implementada:

typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK* UnityAudioEffect_DistanceAttenuationCallback)(
    UnityAudioEffectState* state,
    float distanceIn,
    float attenuationIn,
    float* attenuationOut);

Una curva logaritmica simple personalizada se puede implementar así:

UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK SimpleLogAttenuation(
    UnityAudioEffectState* state,
    float distanceIn,
    float attenuationIn,
    float* attenuationOut)
{
    const float rollOffScale = 1.0f; // Similar to the one in the Audio Project Settings
    *attenuationOut = 1.0f / max(1.0f, rollOffScale * distanceIn);
    return UNITY_AUDIODSP_OK;
}

Script API

Complementing the native side there are also two new methods on the AudioSource that allow setting and getting parameters from the spatializer effect. These are named SetSpatializerFloat/GetSpatializerFloat and work similarly to the SetFloatParameter/GetFloatParameter used in the generic native audio plugin interface. The main difference is that SetSpatializerFloat/GetSpatializerFloat take and index to the parameter to be set/read whereas SetFloatParameter/GetFloatParameter refer to the parameters by name.

Adicionalmente, la propiedad boolean AudioSource.spatializer está vinculada a la casilla de verificación en el inspector del AudioSource y controla la instanciación y controla la instanciación y la desasignación del efecto spatializer (espacial) basándose en la selección de las configuraciones de audio del proyecto. Si la instancia de su efecto spatializer es muy costosa (en términos de asignaciones de memoria, precalculos etc) podría considerar mantener los enlaces de la interfaz del Unity plugin muy ligeros y asignar los efectos de un pool de manera dinámica para que la activación/desactivación no lleve a caías en el fram.

Limitaciones conocidas del plugin ejemplo

Debido al algoritmo de convolución rápida utilizado, moverse rápido causa que algunos problemas surjan los cuales se pueden quitar a través del uso de overlap-save convolution o cross-fading buffers. También el código no soporta girar la cabeza al lado, aunque esto debe ser fácil de arreglar. El conjunto de datos KEMAR es el único conjunto de datos utilizado en este demo. IRCAM tiene unos pocos conjuntos de datos disponibles que fueron obtenidos de sujetos humanos.

Plugin SDK del Audio Nativo de Unity
Audio Profiler (Perfilador de Audio)