Main Content

Esta página se ha traducido mediante traducción automática. Haga clic aquí para ver la última versión en inglés.

Representación de audio binaural mediante seguimiento de cabeza

Realice un seguimiento de la orientación de la cabeza fusionando los datos recibidos de una IMU y luego controle la dirección de llegada de una fuente de sonido aplicando funciones de transferencia relacionadas con la cabeza (HRTF).

En una configuración típica de realidad virtual, el sensor IMU se conecta a los auriculares o cascos de realidad virtual del usuario para que la posición percibida de una fuente de sonido sea relativa a una señal visual independiente de los movimientos de la cabeza. Por ejemplo, si se percibe que el sonido proviene del monitor, permanece así incluso si el usuario gira la cabeza hacia un lado.

Hardware requerido

  • ArduinoUno

  • Invensense MPU-9250

Conexión de hardware

Primero, conecte el Invensense MPU-9250 a la placa Arduino. Para obtener más detalles, consulte Estimating Orientation Using Inertial Sensor Fusion and MPU-9250 (Sensor Fusion and Tracking Toolbox).

Crear objeto sensor y filtro IMU

Cree un objeto arduino .

a = arduino;

Cree el objeto sensor Invensense MPU-9250.

imu = mpu9250(a);

Cree y establezca la frecuencia de muestreo del filtro de Kalman.

Fs = imu.SampleRate;
imufilt = imufilter('SampleRate',Fs);

Cargue el conjunto de datos ARI HRTF

Cuando el sonido viaja desde un punto en el espacio hasta sus oídos, puede localizarlo basándose en el tiempo interaural y las diferencias de nivel (ITD e ILD). Estos ITD e ILD dependientes de la frecuencia se pueden medir y representar como un par de respuestas de impulso para cualquier elevación y azimut de fuente determinada. El conjunto de datos ARI HRTF contiene 1550 pares de respuestas de impulso que abarcan acimutes de más de 360 ​​grados y elevaciones de -30 a 80 grados. Estas respuestas de impulso se utilizan para filtrar una fuente de sonido de modo que se perciba como proveniente de una posición determinada por la orientación del sensor. Si el sensor está conectado a un dispositivo en la cabeza del usuario, el sonido se percibe como proveniente de un lugar fijo a pesar de los movimientos de la cabeza.

Primero, cargue el conjunto de datos HRTF.

ARIDataset = load('ReferenceHRTF.mat');

Luego, obtenga los datos HRTF relevantes del conjunto de datos y colóquelos en un formato útil para nuestro procesamiento.

hrtfData = double(ARIDataset.hrtfData);
hrtfData = permute(hrtfData,[2,3,1]);

Obtenga las posiciones de origen asociadas. Los ángulos deben estar en el mismo rango que el sensor. Convierta los acimutes de [0,360] a [-180,180].

sourcePosition = ARIDataset.sourcePosition(:,[1,2]);
sourcePosition(:,1) = sourcePosition(:,1) - 180;

Cargar grabación monoaural

Cargue una grabación ambisónica de un helicóptero. Conserve sólo el primer canal, que corresponde a una grabación omnidireccional. Vuelva a muestrearlo a 48 kHz para compatibilidad con el conjunto de datos HRTF.

[heli,originalSampleRate] = audioread('Heli_16ch_ACN_SN3D.wav');
heli = 12*heli(:,1); % keep only one channel

sampleRate = 48e3;
heli = resample(heli,sampleRate,originalSampleRate);

Cargue los datos de audio en un objeto SignalSource . Establezca SamplesPerFrame en 0.1 segundos.

sigsrc = dsp.SignalSource(heli, ...
    'SamplesPerFrame',sampleRate/10, ...
    'SignalEndAction','Cyclic repetition');

Configurar el dispositivo de audio

Cree un audioDeviceWriter con la misma frecuencia de muestreo que la señal de audio.

deviceWriter = audioDeviceWriter('SampleRate',sampleRate);

Cree filtros FIR para los coeficientes HRTF

Cree un par de filtros FIR para realizar el filtrado HRTF binaural.

FIR = cell(1,2);
FIR{1} = dsp.FIRFilter('NumeratorSource','Input port');
FIR{2} = dsp.FIRFilter('NumeratorSource','Input port');

Inicializar el visor de orientación

Cree un objeto para realizar una visualización en tiempo real de la orientación del sensor IMU. Llame al filtro IMU una vez y muestre la orientación inicial.

orientationScope = HelperOrientationViewer;
data = read(imu);

qimu = imufilt(data.Acceleration,data.AngularVelocity);
orientationScope(qimu);

Bucle de procesamiento de audio

Ejecute el ciclo de procesamiento durante 30 segundos. Este bucle realiza los siguientes pasos:

  1. Leer datos del sensor IMU.

  2. Fusione los datos del sensor IMU para estimar la orientación del sensor. Visualice la orientación actual.

  3. Convierta la orientación de una representación de cuaternión a cabeceo y guiñada en ángulos de Euler.

  4. Utilice interpolateHRTF para obtener un par de HRTF en la posición deseada.

  5. Lea un cuadro de audio de la fuente de señal.

  6. Aplique los HRTF a la grabación mono y reproduzca la señal estéreo. Esto se experimenta mejor usando auriculares.

imuOverruns = 0;
audioUnderruns = 0;
audioFiltered = zeros(sigsrc.SamplesPerFrame,2);
tic
while toc < 30

    % Read from the IMU sensor.
    [data,overrun] = read(imu);
    if overrun > 0
        imuOverruns = imuOverruns + overrun;
    end
    
    % Fuse IMU sensor data to estimate the orientation of the sensor.
    qimu = imufilt(data.Acceleration,data.AngularVelocity); 
    orientationScope(qimu);
    
    % Convert the orientation from a quaternion representation to pitch and yaw in Euler angles.
    ypr = eulerd(qimu,'zyx','frame');
    yaw = ypr(end,1);
    pitch = ypr(end,2);
    desiredPosition = [yaw,pitch];
    
    % Obtain a pair of HRTFs at the desired position.
    interpolatedIR = squeeze(interpolateHRTF(hrtfData,sourcePosition,desiredPosition));
    
    % Read audio from file   
    audioIn = sigsrc();
             
    % Apply HRTFs
    audioFiltered(:,1) = FIR{1}(audioIn, interpolatedIR(1,:)); % Left
    audioFiltered(:,2) = FIR{2}(audioIn, interpolatedIR(2,:)); % Right    
    audioUnderruns = audioUnderruns + deviceWriter(squeeze(audioFiltered)); 
end

Limpiar

Liberar recursos, incluido el dispositivo de sonido.

release(sigsrc)
release(deviceWriter)
clear imu a