Skip to content

Commit

Permalink
Merge pull request #1 from facebookresearch/master
Browse files Browse the repository at this point in the history
Incorporated new equalization options to make reverb eq process more robust.
  • Loading branch information
svamengualgari authored Nov 17, 2021
2 parents df0500a + 2d4446b commit ffc0773
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 31 deletions.
10 changes: 7 additions & 3 deletions Src/Examples/Demo_BinauralSDM_QuantizedDOA_andRTModAP.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
% as a single direction independent reverb tail and AP rendering will be applied.
DOASmooth = 16; % Window length (in samples) for smoothing of DOA information. 16 samples is a good compromise for noise
% reduction and time resolution.
BRIRLength = 0.7; % Duration of the rendered BRIRs (in seconds)
BRIRLength = 0.5; % Duration of the rendered BRIRs (in seconds)
DenoiseFlag = 1; % Flag to perform noise floor compensation on the multichannel RIR. This ensures that the RIR decays
% progressively and removes rendering artifacts due to high noise floor in the RIR.
FilterRawFlag = 1; % Flag to perform band pass filtering on the multichannel RIR prior to DOA estimation. If active, only
Expand Down Expand Up @@ -111,6 +111,8 @@
AzOrient = (-180:2:180)'; % Render BRIRs every 2 degrees in azimuth
ElOrient = (-90:5:90)'; % Render BRIRs every 5 degrees in elevation
DestinationPath = 'C:/Data/RenderedBRIRs/'; % Folder where the resulting BRIRs will be saved
BandsPerOctave = 1; % Bands per octave used for RT60 equalization
EqTxx = 20; % Txx used for RT60 equalization. For very small rooms or low SNR measurements, T20 is recommended. Otherwise, T30 is recommended.

% Initialize re-synthesized BRIR struct
BRIR_data = create_BRIR_data('MixingTime',MixingTime,...
Expand All @@ -125,7 +127,9 @@
'QuantizeDOAFlag',QuantizeDOAFlag,...
'DOADirections',DOADirections,...
'DestinationPath',DestinationPath,...
'fs',fs);
'fs',fs,...
'BandsPerOctave',1,...
'EqTxx',20);

% Read HRTF dataset for re-synthesis
HRTF = Read_HRTF(BRIR_data);
Expand Down Expand Up @@ -164,7 +168,7 @@

% Get the desired T30 from the Pressure RIR and the actual T30 from one
% rendered BRIR
[DesiredT30, OriginalT30, RTFreqVector] = GetReverbTime(SRIR_data, PreBRIR,3);
[DesiredT30, OriginalT30, RTFreqVector] = GetReverbTime(SRIR_data, PreBRIR,BRIR_data.BandsPerOctave,BRIR_data.EqTxx);

% -----------------------------------------------------------------------
% 4. Render BRIRs with RTMod compensation for the specified directions
Expand Down
8 changes: 4 additions & 4 deletions Src/GetReverbTime.m
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
% Copyright (c) Facebook, Inc. and its affiliates.

function [DesiredT30, OriginalT30, freqVector] = GetReverbTime(SRIR_data, preBRIR, bandsperoctave)
function [DesiredT30, OriginalT30, freqVector] = GetReverbTime(SRIR_data, preBRIR, bandsperoctave, Tn)

[DesiredT30, freqVector] = getLundebyFOB(SRIR_data.P_RIR, SRIR_data.fs,bandsperoctave);
[DesiredT30, freqVector] = getLundebyFOB(SRIR_data.P_RIR, SRIR_data.fs,bandsperoctave, Tn);
DesiredT30 = DesiredT30';
freqVector = freqVector';

[UncorrectedLeftT30, ~] = getLundebyFOB(preBRIR(:,1), SRIR_data.fs,bandsperoctave);
[UncorrectedRightT30, ~] = getLundebyFOB(preBRIR(:,2), SRIR_data.fs,bandsperoctave);
[UncorrectedLeftT30, ~] = getLundebyFOB(preBRIR(:,1), SRIR_data.fs,bandsperoctave, Tn);
[UncorrectedRightT30, ~] = getLundebyFOB(preBRIR(:,2), SRIR_data.fs,bandsperoctave, Tn);
OriginalT30 = mean([UncorrectedLeftT30' UncorrectedRightT30'],2);
2 changes: 1 addition & 1 deletion Src/ModifyReverbSlope.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
if length(BRIR_TimeData) > length(BRIR_Data.FilterBank_g)
BRIR_Data.FilterBank_snfft = length(BRIR_TimeData);
[BRIR_Data.G,BRIR_Data.FilterBank_g,BRIR_Data.FilterBank_f1,BRIR_Data.FilterBank_f2] = ...
oneOver_n_OctBandFilter(2*BRIR_Data.FilterBank_snfft, BRIR_Data.FilterBank_bandsperoctave,...
oneOver_n_OctBandFilter(2*BRIR_Data.FilterBank_snfft, BRIR_Data.BandsPerOctave,...
BRIR_Data.fs, BRIR_Data.FilterBank_minFreq , BRIR_Data.FilterBank_maxFreq);
end

Expand Down
2 changes: 1 addition & 1 deletion Src/PreProcess_Synthesize_SDM_Binaural.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@
BRIR_data.FilterBank_snfft = (BRIR_data.MixingTime+BRIR_data.TimeGuard)*BRIR_data.fs;

[BRIR_data.G,BRIR_data.FilterBank_g,BRIR_data.FilterBank_f1,BRIR_data.FilterBank_f2] = ...
oneOver_n_OctBandFilter(2*BRIR_data.FilterBank_snfft, BRIR_data.FilterBank_bandsperoctave, BRIR_data.fs, BRIR_data.FilterBank_minFreq , BRIR_data.FilterBank_maxFreq);
oneOver_n_OctBandFilter(2*BRIR_data.FilterBank_snfft, BRIR_data.BandsPerOctave, BRIR_data.fs, BRIR_data.FilterBank_minFreq , BRIR_data.FilterBank_maxFreq);

1 change: 1 addition & 0 deletions Src/Read_HRTF.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

if strcmp(BRIR_data.HRTF_Type, 'FRL_HRTF')
HRTF_data = load(BRIR_data.HRTF_Path);
HRTF_data = HRTF_data.hrtf_data;
elseif strcmp(BRIR_data.HRTF_Type, 'SOFA')
HRTF_data = SOFAload(BRIR_data.HRTF_Path);
else
Expand Down
6 changes: 5 additions & 1 deletion Src/SaveBRIR.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ function SaveBRIR(SRIR_data, BRIR_data, DS_BRIR, early_BRIR, ER_BRIR, late_BRIR,
% Author: Sebastià V. Amengual
% Last modified: 4/22/19

Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' SRIR_data.Room '_' SRIR_data.SourcePos '_' SRIR_data.ReceiverPos];
if isfield(BRIR_data,'customPath')
Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' BRIR_data.customPath];
else
Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' SRIR_data.Room '_' SRIR_data.SourcePos '_' SRIR_data.ReceiverPos];
end

if ~exist([Save_Path filesep BRIR_data.RenderingCondition filesep], 'dir')
mkdir([Save_Path filesep BRIR_data.RenderingCondition filesep]);
Expand Down
6 changes: 5 additions & 1 deletion Src/SaveRenderingStructs.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ function SaveRenderingStructs(SRIR_data, BRIR_data)
% Author: Sebastià V. Amengual
% Last modified: 7/11/19

Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' SRIR_data.Room '_' SRIR_data.SourcePos '_' SRIR_data.ReceiverPos];
if isfield(BRIR_data,'customPath')
Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' BRIR_data.customPath];
else
Save_Path = [BRIR_data.DestinationPath regexprep(BRIR_data.HRTF_Subject,' ','_'), '\' SRIR_data.Room '_' SRIR_data.SourcePos '_' SRIR_data.ReceiverPos];
end

if ~exist([Save_Path filesep BRIR_data.RenderingCondition filesep], 'dir')
mkdir([Save_Path filesep BRIR_data.RenderingCondition filesep]);
Expand Down
6 changes: 3 additions & 3 deletions Src/create_BRIR_data.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
% Check input arguments
listNames = {'fs','HRTF_Subject','HRTF_Type','HRTF_Path',...
'DestinationPath','Length','Split','MixingTime','AzOrient','ElOrient',...
'RenderingCondition','Attenuation','QuantizeDOAFlag','DOADirections'};
'RenderingCondition','Attenuation','QuantizeDOAFlag','DOADirections','BandsPerOctave','EqTxx'};

for i = 1:2:length(varargin)
if ~any(strcmpi(listNames,varargin{i}))
Expand Down Expand Up @@ -87,7 +87,8 @@

BRIR_data.RenderingCondition = 'Original';

BRIR_data.FilterBank_bandsperoctave = 3;
BRIR_data.BandsPerOctave = 3;
BRIR_data.EqTxx = 30;

BRIR_data.QuantizeDOAFlag = 0;
BRIR_data.DOADirections = 50;
Expand Down Expand Up @@ -118,7 +119,6 @@
else
disp([listNames{i} ' initialized with default values']);
end
i
end

[rot_az, rot_el] = meshgrid(BRIR_data.AzOrient,BRIR_data.ElOrient);
Expand Down
2 changes: 1 addition & 1 deletion Src/create_FIR_eq.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
F_upsampled = logspace(0,log10(fs/2),200)/(fs/2);
F_upsampled(1) = 0;
F_upsampled(end) = 1;
A_upsampled = interp1(F,A,F_upsampled,'cubic');
A_upsampled = interp1(F,A,F_upsampled,'linear');
else
F_upsampled = F;
A_upsampled = A;
Expand Down
8 changes: 8 additions & 0 deletions Src/create_MicGeometry.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@
0 -0.7071 -0.7071
0 0.7071 -0.7071
0 0 0]*0.096/2;
case 'FRL_10cm_CustomPath'
micpos = [1 0 0 ;
-1 0 0;
0 -0.7071 0.7071
0 0.7071 0.7071
0 -0.7071 -0.7071
0 0.7071 -0.7071
0 0 0]*0.096/2;
otherwise
error('You are trying to create the geometry of a non-existent array :(')
end
Expand Down
5 changes: 4 additions & 1 deletion Src/create_SRIR_data.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
'DOASmooth','RandomDOA','MicArray','ArrayGeometry','Method','Length',...
'Split','MixingTime','Denoise','DenoiseLowFreq','DenoiseHighFreq','PlotDenoisedRIR',...
'OmniMicLag','DS_idx','FilterRaw','FilterRawLowFreq','FilterRawHighFreq',...
'Database_Path','DiffComponent','DiffWinLen','DiffN','DiffFunc','AlignDOA'};
'Database_Path','DiffComponent','DiffWinLen','DiffN','DiffFunc','AlignDOA','CustomPath'};

for i = 1:2:length(varargin)
if ~any(strcmpi(listNames,varargin{i}))
Expand Down Expand Up @@ -129,6 +129,7 @@
SRIR_data.DiffWinLen = 128;
SRIR_data.DiffComponent = 0;
SRIR_data.DSonsetThreshold = 0.02;
SRIR_data.CustomPath = '';

% Apply input arguments on BRIR_data struct
for i = 1:length(listNames)
Expand All @@ -150,6 +151,8 @@
SRIR_data.Method = varargin{j+1};
elseif strcmp(listNames{i},'Database_Path')
SRIR_data.Database_Path = varargin{j+1};
elseif strcmp(listNames{i},'CustomPath')
SRIR_data.CustomPath = varargin{j+1};
end
else
disp([listNames{i} ' initialized with default values']);
Expand Down
4 changes: 2 additions & 2 deletions Src/getLundebyFOB.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
% Copyright (c) Facebook, Inc. and its affiliates.

function [RTs, fcentre] = getLundebyFOB(signal, Fs, bandsPerOctave)
function [RTs, fcentre] = getLundebyFOB(signal, Fs, bandsPerOctave, Tn)
% Returns the estimated Reverberation Time of a RIR in 1 or 1/3 octave
% bands.

Expand All @@ -23,7 +23,7 @@
H_freq = fft(signal,2*snfft);
G = fft(g,2*snfft);
sigFilt = real(ifft(G(:,iOb).*H_freq));
RTs(iOb) = getLundebyRT30(sigFilt, Fs);
RTs(iOb) = getLundebyRT30(sigFilt, Fs,0.02,Tn);
title(num2str(iOb))
end

Expand Down
151 changes: 151 additions & 0 deletions Src/getLundebyRT30.asv
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
% Copyright (c) Facebook, Inc. and its affiliates.

function [reverbTime, intersectionPoint, dirSoundLoc] = getLundebyRT30(roomIR, Fs, integrationWin, Tn)
%getLundebyRT calculates the truncated and energy compensated T30 using the
%Lundeby method (Acta Acoustica Vol. 81 1995)
% getLundebyRT takes in a single channel (N,1) impulse response, the
% sampling frequency, Fs, and an optional integration window parameter
% and returns the reverberation time (T30) in seconds and the
% intersection point in samples.
%
% Author: Peter Dodds (2019) with improvements to code based on ITA Toolbox
% and the acmus matlab package. Reimplemented by Joshua Marcley (2019)
% using algorithm described in https://pdfs.semanticscholar.org/5841/897c265b08addf22dbfaa6da969875e376e4.pdf




if nargin < 3
blockSize = round(0.02*Fs);
Tn = 30;
elseif
blockSize = round(Fs*integrationWin);
end


energyIR = roomIR.*roomIR;
numBlocks = floor(length(energyIR)/blockSize);

if numBlocks < 2
numBlocks = 2;
end

smoothIR = zeros(1,numBlocks);
smoothIR_dB = smoothIR;


% Code below will detect sound events in continuous signal, i.e. it
% WILL detect distortion artifcats in RIRs; however only the latest
% sound event is "stored," therefore at the conclusion of the for loop
% the only data of import will relate to the impulse response
eNoise = []; % instantiate var to store noise energy
ISE = false; % Is Sound Event bool
noiseUp = 5; % this is a tuned parameter
noiseDown = 0;
startSample = 1; % exclude first several block when energy is accumulating
for n = startSample:numBlocks
% Energy in this block
e = mean(energyIR((n-1)*blockSize+1:n*blockSize));

% Energy Level
e_dB = 10*log10(e);

% Store energy and energy level
smoothIR(n) = e;
smoothIR_dB(n) = e_dB;

% instantiate noiseEst
if n == startSample
noiseEst = e_dB;
end

% Block is new sound event
if e_dB > noiseEst + noiseUp && ~ISE
ISE = true;
segmentStart = n;
% continue;
% Block is continuing sound event
elseif e_dB > noiseEst + noiseUp && ISE
% continue;
% Block is end of sound event
elseif e_dB < noiseEst + noiseDown && ISE
segmentEnd = n;
ISE = false;
end


% Block is not in sound event
if ~ISE
% add block energy to noise energy
eNoise(end+1) = e;

% re-estimate noise level
noiseEst = 10*log10(mean(eNoise));
end

end

% plot(smoothIR_dB(segmentStart:segmentEnd))

% Find index of maximum (not necessarily index of direct sound)
[~,dirInd] = max(energyIR);

% Find index of direct sound
% First index BEFORE maximum that is greater than 30dB less than
% maximum; This will fail in any instance in which the direct sound is
% less than 30dB from the maximum
samplesToCut = find(10*log10(energyIR(1:dirInd)) > 10*log10(energyIR(dirInd))-30,1,'first');

% [slope, intercept] = linRegression(0:blockSize:((length(impulse_dB(samplesToCut:end))-1)*blockSize), impulse_dB(samplesToCut:end));
% %Calculate the energy compensation term
% energyCompensation = max(energyIR)*10^(intercept/10)*exp(slope/10/log10(exp(1))*crossPoint)/(-slope/10/log10(exp(1)));

%Calculate the T30 using compensated Schroeder integration
upperLim = -5;
lowerLim = (Tn + 5) * -1;

if exist('segmentEnd','var')
trimmedEnergy = energyIR(samplesToCut:segmentEnd*blockSize);
schrCrv = cumsum(flipud(trimmedEnergy));
schrCrv = schrCrv./max(schrCrv);
schrCrv = flipud(schrCrv);
schrCrv = real(10*log10(schrCrv));

upperLimPt = find(schrCrv < upperLim,1,'first');
lowerLimPt = find(schrCrv < lowerLim,1,'first');

LS_y = schrCrv(upperLimPt:lowerLimPt);
LS_n = length(LS_y);
LS_x = (1:LS_n)';

[rtSlope] = linRegression(LS_x, LS_y);

reverbTime = -60/rtSlope/Fs; %T30
intersectionPoint = (segmentEnd) * blockSize;
dirSoundLoc = samplesToCut;

% debug
% subplot(1,2,1)
% plot(schrCrv)
% subplot(1,2,2)
% plot(roomIR)
% hold on
else
reverbTime = NaN;
end
% plot([intersectionPoint, intersectionPoint], [-20, 50])
% plot([dirSoundLoc, dirSoundLoc], [-20, 50])

end

function [slope, intercept] = linRegression(x,y)

mx = mean(x);
my = mean(y);
mx2 = mean(x.^2);
mxy = mean(x.*y);

intercept = (mx2*my-mx*mxy)/(mx2-mx^2);
slope = (mxy - (mx*my))/(mx2-mx^2);

end
10 changes: 7 additions & 3 deletions Src/getLundebyRT30.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
% Copyright (c) Facebook, Inc. and its affiliates.

function [reverbTime, intersectionPoint, dirSoundLoc] = getLundebyRT30(roomIR, Fs, integrationWin)
function [reverbTime, intersectionPoint, dirSoundLoc] = getLundebyRT30(roomIR, Fs, integrationWin, Tn)
%getLundebyRT calculates the truncated and energy compensated T30 using the
%Lundeby method (Acta Acoustica Vol. 81 1995)
% getLundebyRT takes in a single channel (N,1) impulse response, the
Expand All @@ -17,10 +17,14 @@

if nargin < 3
blockSize = round(0.02*Fs);
else
Tn = 30;
elseif nargin == 3
blockSize = round(Fs*integrationWin);
Tn = 30;
else
blockSize = round(Fs*integrationWin);
end
Tn = 30;


energyIR = roomIR.*roomIR;
numBlocks = floor(length(energyIR)/blockSize);
Expand Down
14 changes: 13 additions & 1 deletion Src/read_RIR.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,22 @@
fs_P = fs_Raw;
case 'NoArray'
error('It seems that you have not selected a microphone array...');
case 'FRL_10cm_CustomPath'
SRIR_data.P_RIR_Path = SRIR_data.CustomPath;
SRIR_data.Raw_RIR_Path = SRIR_data.CustomPath;
[SRIR_data.Raw_RIR, fs_Raw] = audioread(SRIR_data.Raw_RIR_Path);
SRIR_data.P_RIR = SRIR_data.Raw_RIR(:,7);
fs_P = fs_Raw;
end

if fs_P ~= fs_Raw || SRIR_data.fs ~= fs_Raw || SRIR_data.fs ~= fs_P
error('Your sampling rates do not match! Check your SRIR struct or RIRs!');
warning('Your RIR sampling rate is different from the specified one. Resampling RIRs!');
if SRIR_data.fs ~= fs_Raw
SRIR_data.Raw_RIR = resample(SRIR_data.Raw_RIR, SRIR_data.fs, fs_Raw);
end
if SRIR_data.fs ~= fs_P
SRIR_data.P_RIR = resample(SRIR_data.P_RIR, SRIR_data.fs, fs_P);
end
else
SRIR_data.fs = fs_P;
end
Loading

0 comments on commit ffc0773

Please sign in to comment.