exponenta event banner

Бинауральный звуковой рендеринг с помощью отслеживания головы

Отслеживание ориентации головы путем сплавления данных, полученных от IMU, и затем управление направлением прихода источника звука путем применения связанных с головой передаточных функций (HRTF).

В типичной настройке виртуальной реальности IMU-датчик крепится к наушникам пользователя или VR-гарнитуре так, чтобы воспринимаемое положение источника звука было относительно визуального сигнала, не зависящего от движений головы. Например, если звук воспринимается как поступающий от монитора, он остается таким, даже если пользователь поворачивает голову в сторону.

Необходимое оборудование

  • Ардуино-Уно

  • Invensense MPU-9250

Аппаратное подключение

Сначала подключите MPU-9250 Invensense к плате Arduino. Дополнительные сведения см. в разделе Оценка ориентации с помощью слияния и MPU-9250 инерционных датчиков.

Создание объекта датчика и фильтра IMU

Создание arduino объект.

a = arduino;

Создайте объект датчика Invensense MPU-9250.

imu = mpu9250(a);

Создайте и установите частоту дискретизации фильтра Калмана.

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

Загрузить набор данных ARI HRTF

Когда звук перемещается из точки пространства в уши, его можно локализовать на основе межауральных различий во времени и уровнях (ITD и ILD). Эти зависящие от частоты ITD и ILD могут быть измерены и представлены в виде пары импульсных откликов для любой заданной высоты источника и азимута. Набор данных ARI HRTF содержит 1550 пар импульсных откликов, которые охватывают азимуты более 360 градусов и отметки от -30 до 80 градусов. Эти импульсные характеристики используются для фильтрации источника звука так, чтобы он воспринимался как поступающий из положения, определяемого ориентацией датчика. Если датчик прикреплен к устройству на голове пользователя, звук воспринимается как поступающий из одного фиксированного места, несмотря на движения головы.

Сначала загрузите набор данных HRTF.

ARIDataset = load('ReferenceHRTF.mat');

Затем получите соответствующие данные HRTF из набора данных и поместите их в полезный формат для нашей обработки.

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

Получение связанных исходных позиций. Углы должны находиться в том же диапазоне, что и у датчика. Преобразуйте азимуты из [0,360] в [-180,180].

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

Загрузка моноуральной записи

Загрузить амбисоническую запись вертолета. Сохранить только первый канал, который соответствует всенаправленной записи. Выполните повторную выборку до 48 кГц для совместимости с набором данных HRTF.

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

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

Загрузка аудиоданных в SignalSource объект. Установите SamplesPerFrame кому 0.1 секунд.

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

Настройка аудиоустройства

Создание audioDeviceWriter с той же частотой дискретизации, что и звуковой сигнал.

deviceWriter = audioDeviceWriter('SampleRate',sampleRate);

Создание фильтров FIR для коэффициентов HRTF

Создайте пару фильтров FIR для выполнения бинауральной фильтрации HRTF.

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

Инициализация средства просмотра ориентации

Создайте объект для визуализации ориентации датчика IMU в реальном времени. Вызовите фильтр IMU один раз и просмотрите начальную ориентацию.

orientationScope = HelperOrientationViewer;
data = read(imu);

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

Цикл обработки звука

Выполните цикл обработки в течение 30 секунд. Этот цикл выполняет следующие шаги:

  1. Считывание данных с датчика IMU.

  2. Чтобы оценить ориентацию датчика, запалите данные датчика IMU. Визуализация текущей ориентации.

  3. Преобразуйте ориентацию из представления кватерниона в шаг и рыскание в углах Эйлера.

  4. Использовать interpolateHRTF для получения пары HRTF в требуемом положении.

  5. Считывание кадра звука из источника сигнала.

  6. Примените HRTF к монозаписи и воспроизведите стереосигнал. Это лучше всего возможно с помощью наушников.

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

Очистка

Освободить ресурсы, включая звуковое устройство.

release(sigsrc)
release(deviceWriter)
clear imu a