From 49dbbd54dad7c10937207f96b0c4a3803508d26e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Apr 2023 14:29:05 +0300 Subject: [PATCH] Adding MASA SRIR examples. Includes SRIR analysis, SRIR normalization and SRIR MASA (FoA + Ext) usage examples. --- .../AnalyseNormalize_MASAExample.m | 132 ++++++++++++++++++ SRIR/MASA_Example/DCBlock.m | 13 ++ .../ExampleInput/FinnishMale_mono.wav | 3 + .../ExampleInput/RodeExtM5_Cardioid_Pos3.wav | 3 + .../ExampleInput/SennheiserAmbeo_FoA_Pos3.wav | 3 + SRIR/MASA_Example/ExampleInput/TargetMLS.wav | 3 + .../MASA_Example/ExampleInput/Test-26dbOV.wav | 3 + SRIR/MASA_Example/IVAS_rend.exe | 3 + SRIR/MASA_Example/WavToPCM.m | 43 ++++++ SRIR/MASA_Example/bs1770.m | 130 +++++++++++++++++ SRIR/MASA_Example/deco.bin | 3 + .../eigen_to_foa_cldfb_domain_filters.bin | 3 + .../eigen_to_hoa2_cldfb_domain_filters.bin | 3 + SRIR/MASA_Example/masaAnalyzer.exe | 3 + SRIR/MASA_Example/sector_filters.bin | 3 + SRIR/MASA_Example/vbap_51_table.bin | 3 + SRIR/MASA_Example/vbap_714_table.bin | 3 + SRIR/MASA_Example/vbap_bin_table.bin | 3 + 18 files changed, 360 insertions(+) create mode 100644 SRIR/MASA_Example/AnalyseNormalize_MASAExample.m create mode 100644 SRIR/MASA_Example/DCBlock.m create mode 100644 SRIR/MASA_Example/ExampleInput/FinnishMale_mono.wav create mode 100644 SRIR/MASA_Example/ExampleInput/RodeExtM5_Cardioid_Pos3.wav create mode 100644 SRIR/MASA_Example/ExampleInput/SennheiserAmbeo_FoA_Pos3.wav create mode 100644 SRIR/MASA_Example/ExampleInput/TargetMLS.wav create mode 100644 SRIR/MASA_Example/ExampleInput/Test-26dbOV.wav create mode 100644 SRIR/MASA_Example/IVAS_rend.exe create mode 100644 SRIR/MASA_Example/WavToPCM.m create mode 100644 SRIR/MASA_Example/bs1770.m create mode 100644 SRIR/MASA_Example/deco.bin create mode 100644 SRIR/MASA_Example/eigen_to_foa_cldfb_domain_filters.bin create mode 100644 SRIR/MASA_Example/eigen_to_hoa2_cldfb_domain_filters.bin create mode 100644 SRIR/MASA_Example/masaAnalyzer.exe create mode 100644 SRIR/MASA_Example/sector_filters.bin create mode 100644 SRIR/MASA_Example/vbap_51_table.bin create mode 100644 SRIR/MASA_Example/vbap_714_table.bin create mode 100644 SRIR/MASA_Example/vbap_bin_table.bin diff --git a/SRIR/MASA_Example/AnalyseNormalize_MASAExample.m b/SRIR/MASA_Example/AnalyseNormalize_MASAExample.m new file mode 100644 index 00000000..caf1cc6d --- /dev/null +++ b/SRIR/MASA_Example/AnalyseNormalize_MASAExample.m @@ -0,0 +1,132 @@ +% Example script on analysis and normalization of SRIR (Spatial Room +% Impulse Responses) from recordings. +% This script also shows how IVAS MASA format SRIR can be created and used for listening test processing. +% +% In order to fully run the script you need also +% IVAS_rend IVAS renderer +% masaAnalyzer IVAS MASA analyzer tool +% +% Windows binaries are included, but for Linux/Mac you need to add your own +% + +% +% Author: Anssi Rämö (Nokia Techonologies) +% Date: 10.4.2023 +% +% +% + +clear +fs=48000; % Sampling frequency +ms = fs/1000; % millisecond in samples +DC=1; % Preprocessing (DC-Block filtering may be useful, if lot of low frequency brum and recorded without high-pass filter) +PeakPos=2; % in ms (SRIR peak position, for the closest channel) +IR_Len=200; % in ms +FadeInOut=1; % Post-processing of SRIR +FadeInLength=24; % in samples. Sinusoidal FadeIn -length +FadeOutLength=60; % in samples. Cosine FadeOut -length + + +% Test signal that has been used for recordings +target=audioread('ExampleInput\TargetMLS.wav');target=target(:); + +% The recording(s) made in a room using the test signal +AmbeoFoA=audioread('ExampleInput\SennheiserAmbeo_FoA_Pos3.wav'); +ExtM5=audioread('ExampleInput\RodeExtM5_Cardioid_Pos3.wav'); + +% IVAS MASA format may utilise SRIR responses of form FoA + Ext transport (mono/stereo) +% FoA signal is created by VST-plugin while recording. If processing delay is not +% compensated during recording it has to be conmpensated in analysis + +% We have found out following delays for different ambisonic microphones +% These depend on the DAW used and their settings. +RodeNTSF1_DelayComp=1312+1+1024; % Delay compensation for Rode NT-SF1 VST plugin FoA analysis +SennheiserAmbeo_DelayComp=1312+1+128; % Delay compensation for Sennheiser Ambeo VST plugin FoA analysis +VoyageAudio_DelayComp=1312+1+512; % % Delay compensation for Voyage Audio plugin HoA2 analysis + +% Aling FoA + Ext audio signals for SRIR calculation +measurement=[AmbeoFoA(SennheiserAmbeo_DelayComp+1:end,:) ExtM5(1:end-SennheiserAmbeo_DelayComp,:)]; + +% Pre-process (DC-block, highpass filtering 30Hz) recorded signal, if needed +if (DC) + measurement=DCBlock(measurement); +end + +% Do the SRIR analysis +chn=min(size(measurement)); % Number of channels to analyze +len = length(target); +for i = 1:chn + Y=fft(measurement(:,i),(length(measurement)+size(target,2)-1)); + H=fft(target,(length(measurement)+size(target,2)-1)); + G=Y./(H); + SRIR_long(:,i)=ifft(G,'symmetric'); + [null,latencies(i)] = max(SRIR_long(1:fs,i)); % Peak has to be within first second, if not adjust your measurement signal range +end + +latency = min(latencies); % Put the closest microphone signal to PeakPos +SRIR_short = SRIR_long(latency-PeakPos*ms+1:latency+(IR_Len-PeakPos)*ms,:); + +% FadeIn, FadeOut +if (FadeInOut==1) + inwin=sin(pi*(0:FadeInLength-1)/(2*FadeInLength-2)).^2; + FadeIn=repmat(inwin',[1 chn]); + SRIR_short(1:FadeInLength,:)=SRIR_short(1:FadeInLength,:).*FadeIn; + outwin=cos(pi*(0:FadeOutLength-1)/(2*FadeOutLength-2)).^2; + FadeOut=repmat(outwin',[1 chn]); + SRIR_short(end-FadeOutLength+1:end,:)=SRIR_short(end-FadeOutLength+1:end,:).*FadeOut; +end +%plot(SRIR_short) + + +% Do SRIR normalization +% IVAS MASA input format FoA + Ext parts are best to be normalized separately +% for the FoA/HoA part and transport signals. + +% Test signal with short sequences of male & female speech and white & pink noise. All normalized to -26 dbOV +test26=audioread('ExampleInput\Test-26dbOV.wav'); + + +Tmp_Talker=zeros([length(test26) chn]); +% Make initial SRIR scaling something reasonable +SRIR_short=0.2*SRIR_short/max(max(abs(SRIR_short))); + +% Filter test signal with SRIR vectors +for t=1:chn + Tmp_Talker(:,t)=filter(SRIR_short(:,t),1,test26); +end + +% Normalize FoA part based on the binaural rendered signal. +% Render FoA to binaural with IVAS_rend-tool +audiowrite('FoA.wav',Tmp_Talker(:,1:4),48000,'BitsPerSample',16); +eval('!IVAS_rend.exe -i FoA.wav -if FOA -o BIN.wav -of BINAURAL'); +bin=audioread('BIN.wav'); +% Calculate BS.1770 loudness and scale to target level (-26 dBOv) +[level gain]=bs1770(bin,-26) +SRIR_short(:,1:4)=gain*SRIR_short(:,1:4); + +% Normalize transports, directly from the Ext-transport stereo signal +[leveltr gaintr]=bs1770(Tmp_Talker(:,5:6),-26) +SRIR_short(:,5:6)=gaintr*SRIR_short(:,5:6); + +% Write normalized SRIR to a file +audiowrite('Nokia_LargeRoom_Pos3_FoA+Ext_6hcn.wav',SRIR_short,48000,'BitsPerSample',16); + +% Render spatialized mono signal with stereo MASA FoA+Ext processing + +if (1) + SRIR=audioread('Nokia_LargeRoom_Pos3_FoA+Ext_6hcn.wav'); + speech=audioread('ExampleInput\FinnishMale_mono.wav'); + + SRIR_speech=zeros([length(speech) 6]); + for t=1:6 + SRIR_speech(:,t)=filter(SRIR(:,t),1,speech(:,1)); % Anssi + end + + audiowrite('FoAExt.wav',SRIR_speech,48000,'BitsPerSample',16); + WavToPCM('FoAExt.wav'); + + % Analyze FoA + stereo Ext signal with masaAnalyzer and create stereo.pcm and MASA metadata. + !masaAnalyzer -stereo -1dir -foaext FoAExt.pcm stereo.pcm 1dir.met + eval(['!IVAS_rend.exe -fs 48 -if MASA2 -im 1Dir.met -i stereo.pcm -of BINAURAL -o FinMale_Pos3_BIN.wav']); + +end \ No newline at end of file diff --git a/SRIR/MASA_Example/DCBlock.m b/SRIR/MASA_Example/DCBlock.m new file mode 100644 index 00000000..dddde568 --- /dev/null +++ b/SRIR/MASA_Example/DCBlock.m @@ -0,0 +1,13 @@ +function y = DCBlock ( x ) +% DC-block filtering. Default is 30Hz (-3 dB) +% a = 1-2^-11 = 0.99951171875 -3dB cut-off 3.8Hz, 20Hz atten. -0.004dB +% a = 1-2^-9 = 0.998046875 -3dB cut-off 15Hz, 20Hz atten. -1.9 dB +% a = 1-2^-8 = 0.9961 -3dB cut-off 30Hz, 20Hz atten. -5.1 dB +% a = 1-2^-7 = 0.9922 -3dB cut-off 60Hz, 20Hz atten. -10 dB +% a = 1-2^-6 ~= 0.985 -3dB cut-off 120Hz, 20Hz atten. -15? dB (ITU-T STL p50mnru default) + +c = 1-2^-8; % c - coefficient +b = [1 -1]; % filter coefficient b +a = [1 -c]; % filter coefficient a +y = filter (b,a,x); +end \ No newline at end of file diff --git a/SRIR/MASA_Example/ExampleInput/FinnishMale_mono.wav b/SRIR/MASA_Example/ExampleInput/FinnishMale_mono.wav new file mode 100644 index 00000000..127e609e --- /dev/null +++ b/SRIR/MASA_Example/ExampleInput/FinnishMale_mono.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a972f8cb4573efe356b391882e13f009f13eec8867c607291e60fbd36a983ee +size 238672 diff --git a/SRIR/MASA_Example/ExampleInput/RodeExtM5_Cardioid_Pos3.wav b/SRIR/MASA_Example/ExampleInput/RodeExtM5_Cardioid_Pos3.wav new file mode 100644 index 00000000..ca423da6 --- /dev/null +++ b/SRIR/MASA_Example/ExampleInput/RodeExtM5_Cardioid_Pos3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fed254345a3efdd6da725cbe146b722c0a548d64d0fe2e3a8c3a0dc2ae1daccf +size 3715244 diff --git a/SRIR/MASA_Example/ExampleInput/SennheiserAmbeo_FoA_Pos3.wav b/SRIR/MASA_Example/ExampleInput/SennheiserAmbeo_FoA_Pos3.wav new file mode 100644 index 00000000..221dead3 --- /dev/null +++ b/SRIR/MASA_Example/ExampleInput/SennheiserAmbeo_FoA_Pos3.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e3d96fc7dffa114e74eaf0d92254ecac1e67cfe0656e66e2f00db5890d6d6b8 +size 7430444 diff --git a/SRIR/MASA_Example/ExampleInput/TargetMLS.wav b/SRIR/MASA_Example/ExampleInput/TargetMLS.wav new file mode 100644 index 00000000..cc4cdae1 --- /dev/null +++ b/SRIR/MASA_Example/ExampleInput/TargetMLS.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21292960c4ee9b1a25165d37df79e966502e6dc1dac70512dfd29daa66d4d1f0 +size 786474 diff --git a/SRIR/MASA_Example/ExampleInput/Test-26dbOV.wav b/SRIR/MASA_Example/ExampleInput/Test-26dbOV.wav new file mode 100644 index 00000000..b43c0f9a --- /dev/null +++ b/SRIR/MASA_Example/ExampleInput/Test-26dbOV.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d534ea6edc1ef1c4bf6dda253aa378fdadabd899e84dd074feb97a15b3a7c618 +size 556780 diff --git a/SRIR/MASA_Example/IVAS_rend.exe b/SRIR/MASA_Example/IVAS_rend.exe new file mode 100644 index 00000000..cffc6f77 --- /dev/null +++ b/SRIR/MASA_Example/IVAS_rend.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38741d8cc9eca1e2fba8fcd24b2a24ae85ba9adf6aaee4fbfa7c7ab99b3ed9fb +size 5884928 diff --git a/SRIR/MASA_Example/WavToPCM.m b/SRIR/MASA_Example/WavToPCM.m new file mode 100644 index 00000000..d1c1efe1 --- /dev/null +++ b/SRIR/MASA_Example/WavToPCM.m @@ -0,0 +1,43 @@ +function WavToPCM(filename) +% Converts wavefile to PCM file for masaAnalyzer +% This function essentially strips the wave header out, +% resamples to 48 kHz sampling rate if necessary, and +% stores the result in signed 16-bit LEI PCM with interleaved +% channels. The input file is assumed to be a 32-channel +% Eigenmike recording in wave format. +%-------------------------------------------------------------------------------% +% MASA reference analyzer & renderer % +%----------------------------------- % +% C) 2019 Nokia Corporation. All rights reserved. Provided by Nokia Corporation % +% for exclusive use of the development and testing of MASA format solely in the % +% 3GPP SA WG4 IVAS codec standardization. Any other use is not permitted. % +% % +% Nokia Corporation makes no representation nor warranty in regard to % +% the accuracy, completeness or sufficiency of The Software, nor % +% shall Nokia Corporation be held liable for any damages whatsoever % +% relating to use of said Software. % +% % +%-------------------------------------------------------------------------------% + +masaFS = 48000; +[x, fs] = audioread(filename); + +% Convert sample rate if necessary +if (fs ~= masaFS) + warning('Sampling rate is not 48 kHz, resampling.'); + y = resample(x, masaFS, fs); +else + y = x; +end + +% Zeropad PCM to full frames if not +if (mod(size(y,1), 960)) + y = [y; zeros(960 - mod(size(y,1), 960), size(y,2))]; +end + +pcmData = int16(y .* double(intmax('int16')))'; +pcmFilename = [filename(1:end-4), '.pcm']; +fid = fopen(pcmFilename, 'wb'); +fwrite(fid, pcmData, 'int16'); +fclose(fid); + diff --git a/SRIR/MASA_Example/bs1770.m b/SRIR/MASA_Example/bs1770.m new file mode 100644 index 00000000..8b4b2d92 --- /dev/null +++ b/SRIR/MASA_Example/bs1770.m @@ -0,0 +1,130 @@ +function [lev_in, fac]=bs1770(x, lev_target) +%function level=bs1770(input,lev_target) +% Simplified ITU-R BS-1770-4 implementation +% Fs 48000 +% +% + +STEP_SIZE = 4800; % 100 ms step; +BLOCK_SIZE = 4*STEP_SIZE; % 400 ms gating block; + +default_conf = '000011000011000000000000'; + +% conf = default_conf; +%G = parse_conf(conf,nchan); +nchan=min(size(x)); +G = ones(nchan,1); % All channels are considered equal + +for k=1:nchan, + if ((k==5)||(k==6)||(k==11)||(k==12)) % + G(k)=1.41; + end +end + +%fp = fopen(input_file,'rb'); +%x = reshape(fread(fp,'short'),nchan,[])'/32768; +%fclose(fp); + +N = length(x); +M = floor(4 * (N - BLOCK_SIZE) / BLOCK_SIZE); + +% R-REC-BS.1770-2-201103.pdf, Table 1, Filter coefficients for stage 1 of the pre-filter to model a spherical head +b = [ 1.53512485958697 -2.69169618940638 1.19839281085285]; +a = [1 -1.69065929318241 0.73248077421585]; + +% R-REC-BS.1770-2-201103.pdf, Table 2, Filter coefficients for the RLB weighting curve +b2 = [1.0 -2.0 1.0]; +a2 = [1 -1.99004745483398 0.99007225036621]; + +y = zeros(size(x)); + +z = zeros(nchan,M); + +for i=1:nchan + y(:,i) = filter(b2,a2,filter(b,a,x(:,i))); + tmp = frame(y(:,i),BLOCK_SIZE,BLOCK_SIZE-STEP_SIZE); + tmp = tmp(:,1:M); + z(i,:) = sum(tmp.^2); +end +l = sum(z .* (G * ones(1,M)),1)/BLOCK_SIZE; + +[lev_in,lev_out,fac] = find_scaling_factor(l, lev_target); + +if isnan(lev_in) + lev_in=-128; +end; + +%fprintf('Input level: %.2f\n',lev_in); +%fprintf('Target level: %.2f\n',lev_target); +%fprintf('Obtained level: %.2f\n',lev_out); +%fprintf('Scaling factor: %.2f\n',fac); + +%fp = fopen(output_file,'wb'); +%fwrite(fp,x'*fac*32768,'short'); +%fclose(fp); + +function [lev_in,lev_out,fac] = find_scaling_factor(energy, lev_target) + +RELATIVE_DIFF = 0.0001; +MAX_ITERATIONS = 10; +last_fac = 100; +fac = 1; +itr = 0; + +while( (abs( 1.0 - fac / last_fac ) > RELATIVE_DIFF) && (itr < MAX_ITERATIONS) ) + I = find(-0.691 + 10*log10(energy*fac^2) > -70); + thr = -0.691 + 10*log10(mean(energy(I)*fac^2)) - 10; + I = find(-0.691 + 10*log10(energy*fac^2) > thr); + lev = -0.691 + 10*log10(mean(energy(I)*fac^2)); + last_fac = fac; + fac = fac * 10.0^((lev_target - lev) / 20 ); + if itr == 0 + lev_in = lev; + end + itr = itr + 1; +end + +lev_out = lev; + +function [F,N] = frame(X,len,overlap) + +if(nargin < 3) + overlap = 0; +end + +step = len - overlap; + +L = length(X); +N = ceil((L - len)/step); + +% Create index matrix +indx = ones(len,1) * (1:step:N*step+1) + (0:len-1)' * ones(1,N+1); + +% Pad with zeros at the end of the input vector if necessary +if(L < N*step+len) + X(N*step+len) = 0; +end + +% Form output using indices +F = X(indx); + +% Special case for single frame output +if(numel(F) == length(F)) + F = F'; +end + +N = size(indx,2); + +function G = parse_conf(conf,nchan) + +for i=1:nchan + if conf(i) == '1' + G(i) = 1.41; + else + if conf(i) == '0' + G(i) = 1; + else + fprintf('*** Invalid configuration %s, exiting..\n\n',conf); + end + end +end \ No newline at end of file diff --git a/SRIR/MASA_Example/deco.bin b/SRIR/MASA_Example/deco.bin new file mode 100644 index 00000000..3ea11b0f --- /dev/null +++ b/SRIR/MASA_Example/deco.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c24505426ee0d7f5eb019af6d918647eebb363dd96a45ae50be65a4aa2f809c0 +size 229376 diff --git a/SRIR/MASA_Example/eigen_to_foa_cldfb_domain_filters.bin b/SRIR/MASA_Example/eigen_to_foa_cldfb_domain_filters.bin new file mode 100644 index 00000000..3a9d67c0 --- /dev/null +++ b/SRIR/MASA_Example/eigen_to_foa_cldfb_domain_filters.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c3ebc3d9e031d2d640a32639132771da974874686a378fb323645b9dbb553fe +size 61440 diff --git a/SRIR/MASA_Example/eigen_to_hoa2_cldfb_domain_filters.bin b/SRIR/MASA_Example/eigen_to_hoa2_cldfb_domain_filters.bin new file mode 100644 index 00000000..4c586da3 --- /dev/null +++ b/SRIR/MASA_Example/eigen_to_hoa2_cldfb_domain_filters.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9097ecbf3b26b814abe141edadc701f1ffec5a141f2becc746926d6d32a7e58 +size 138240 diff --git a/SRIR/MASA_Example/masaAnalyzer.exe b/SRIR/MASA_Example/masaAnalyzer.exe new file mode 100644 index 00000000..423c2e6d --- /dev/null +++ b/SRIR/MASA_Example/masaAnalyzer.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f0684bd1b5998dd21f309388cbfb71f33a62ab9973bbd84871aaac15f067aeb0 +size 487424 diff --git a/SRIR/MASA_Example/sector_filters.bin b/SRIR/MASA_Example/sector_filters.bin new file mode 100644 index 00000000..88adf401 --- /dev/null +++ b/SRIR/MASA_Example/sector_filters.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4ff3f7d925b868aa98e366318c1bb2530ad9738ff53a187dafa5dcebcf3ec68 +size 288 diff --git a/SRIR/MASA_Example/vbap_51_table.bin b/SRIR/MASA_Example/vbap_51_table.bin new file mode 100644 index 00000000..2477f119 --- /dev/null +++ b/SRIR/MASA_Example/vbap_51_table.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5182e9d0d86d47871e34d8a2821ebef94d8f25d08c51cd0bd618d66a59e4fab +size 3620 diff --git a/SRIR/MASA_Example/vbap_714_table.bin b/SRIR/MASA_Example/vbap_714_table.bin new file mode 100644 index 00000000..1541c1fd --- /dev/null +++ b/SRIR/MASA_Example/vbap_714_table.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac34d9a81d62ac12094aab948047650017019377059fdf425614ef9f345954f7 +size 294668 diff --git a/SRIR/MASA_Example/vbap_bin_table.bin b/SRIR/MASA_Example/vbap_bin_table.bin new file mode 100644 index 00000000..1bf371c9 --- /dev/null +++ b/SRIR/MASA_Example/vbap_bin_table.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab7bfe8d1c01359213362e8dcce21f42b50c07ed7f7a4a8ff972f516283df027 +size 428608 -- GitLab