function [InstantaneousSpecificLoudnessLeft, InstantaneousSpecificLoudnessRight] = moore2016_monauralinstspecloudness(signal, Fs, dBMax)
%MOORE2016_MONAURALINSTSPECLOUDNESS calculates instantaneous specific loudness over time
%
% Input parameter:
% signal : input signal
% fs : sampling frequency
% dbMax : the RMS SPL of a sinusoid with a peak amplitude of 1.
%
% Output parameter:
% InstantaneousSpecificLoudnessLeft : instantaneous specific loudness left ear
% InstantaneousSpecificLoudnessRight : instantaneous specific loudness right ear
%
% (left, right) signal and sampling rate Fs must be passed. Fs must be 32 kHz,
% reading of the wav file and resampling must be done before calling this function.
% The signal must contain two columns.
%
% Url: http://amtoolbox.sourceforge.net/amt-0.10.0/doc/modelstages/moore2016_monauralinstspecloudness.php
% Copyright (C) 2009-2020 Piotr Majdak and the AMT team.
% This file is part of Auditory Modeling Toolbox (AMT) version 1.0.0
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
npts = Fs / 1000 * 64; % points for FFT, 2048
nSegmentDuration = 1; % duration of segment in ms
nSamplesPerSegment = Fs / 1000 * nSegmentDuration; % 32
nSegmentsInSignal = floor( (length(signal) - npts) / Fs * 1000 / nSegmentDuration );
% Hann windows for 6 FFTs; 1st column 64 ms, 6th column 2 ms
wHann = zeros(npts,6);
for i = 1:6
wHann(:,i) = [ zeros( (1 - 1/2^(i-1) ) / 2 * npts, 1 ); hann( npts / 2^(i-1) ); zeros( (1 - 1/2^(i-1) ) / 2 * npts, 1 ) ];
end
% indices which shall be used from the ffts, 20-80 Hz from the first...
vLimitingF = [20 80 500 1250 2540 4050 15000];
vLimitingIndices = zeros(1,7);
for i=1:7
vLimitingIndices(i) = floor( vLimitingF(i) / (Fs/npts) ) + 1;
end
InstantaneousSpecificLoudnessLeft = zeros(nSegmentsInSignal + 1, length(1.75:0.25:39) );
InstantaneousSpecificLoudnessRight = zeros(nSegmentsInSignal + 1, length(1.75:0.25:39) );
%% loop: window segment, apply stationary loudness model, move window
%% by 1 ms
% tic
for iSegment = 0:nSegmentsInSignal
%
% if ( mod(iSegment,50) == 0 )
% disp([num2str(iSegment) ' ms of ' num2str(nSegmentsInSignal) ' ms analyzed'])
% end
[fLeftRelevant, LLeftRelevant, fRightRelevant, LRightRelevant] = moore2016_spectrum(signal( (iSegment*nSamplesPerSegment+1) : (iSegment*nSamplesPerSegment+npts), : ), Fs, dBMax, wHann, vLimitingIndices);
if ( isempty( LLeftRelevant ) )
SpecificLoudnessLeft = zeros(1,150);
else
ExcitationLevelsLeft = moore2016_excitationpattern(fLeftRelevant', LLeftRelevant');
SpecificLoudnessLeft = moore2016_specloudnessbinaural( ExcitationLevelsLeft );
end
if ( isempty( LRightRelevant ) )
SpecificLoudnessRight = zeros(1,150);
else
ExcitationLevelsRight = moore2016_excitationpattern(fRightRelevant', LRightRelevant');
SpecificLoudnessRight = moore2016_specloudnessbinaural( ExcitationLevelsRight );
end
% [ ThisSpecificLoudness, ThisLoudness ] = MonauralSpecificLoudness2BinauralSpecificLoudness025( SpecificLoudnessLeft, SpecificLoudnessRight );
InstantaneousSpecificLoudnessLeft(iSegment+1,:) = SpecificLoudnessLeft;
InstantaneousSpecificLoudnessRight(iSegment+1,:) = SpecificLoudnessRight;
% InstantaneousLoudness(iSegment+1) = ThisLoudness;
end
% toc
end
function out = moore2016_specloudnessbinaural( ExcitationLevels )
% version for TVL 2016 based on ANSI S3.4-2007 and Moore & Glasberg (2007)
% Calculate the specific loudness out of excitation patterns at 0.25-ERB
% steps, using the constant C of the model that accounts for binaural
% loudness
% ERB-scale
ERBc = 1.75:0.25:39;
fc = erb2fc(ERBc);
% Parameters
C = 0.06267;
C = 0.063026;
C = 0.0631;
G = get_G(fc);
Alpha = get_Alpha(fc);
A = get_A(fc);
% Excitation and threshold in linear power units
Excitation = 10 .^ ( ExcitationLevels ./ 10 );
Threshold = excitationthreshold(fc);
Threshold = 10 .^ ( Threshold ./ 10 );
% 3 ranges - calculate all for each case (computationally cheap)
N1 = C .* ( ( G .* Excitation + A ) .^ Alpha - A .^Alpha );
N2 = C .* ( 2 .* Excitation ./ ( Excitation + Threshold ) ) .^ 1.5 .* ( ( G .* Excitation + A ) .^ Alpha - A .^Alpha );
N3 = C .* ( Excitation ./ 1.0707 ) .^ 0.2;
out = ( Excitation > Threshold & Excitation < 10^10 ) .* N1 + ( Excitation <= Threshold ) .* N2 + (Excitation >= 10^10 ) .* N3;
% figure;
% hold on;
% semilogy(ExcitationLevels, out);
% xlim([0 110]);
% ylim([0.005 10]);
end
%end
function out = get_Alpha(f)
TableG2Alpha = [ -25.0 -20.0 -15.0 -10.0 -5.0 0.0;
0.26692 0.25016 0.23679 0.22228 0.21055 0.20000];
G = get_G(f);
G = 10 .* log(G) ./ log(10);
out = interpolation(TableG2Alpha(1,:), TableG2Alpha(2,:), G,'linear');
end
function out = get_A(f)
TableG2A = [ -24.54531 -23.78397 -22.78169 -21.76854 -20.74442 -19.78305 -18.90431 -18.01605 -17.11816 -16.21055 -15.32375 -14.59341 ...
-13.91727 -13.29726 -12.73537 -12.23364 -11.75255 -11.23866 -10.75136 -10.29164 -9.86051 -9.45902 -9.08823 -8.72191 ...
-8.35715 -8.01199 -7.68715 -7.38338 -7.10145 -6.84213 -6.60623 -6.39458 -6.14589 -5.89392 -5.65071 -5.41661 ...
-5.19198 -4.97718 -4.77258 -4.57857 -4.39555 -4.20148 -4.00538 -3.81442 -3.62882 -3.27454 -3.10633 -2.94438 ...
-2.78894 -2.64027 -2.50042 -2.37015 -2.24820 -2.13487 -2.03046 -1.93531 -1.84973 -1.77405 -1.70863 -1.65382 ...
-1.60997 -1.57745 -1.51786 -1.44522 -1.37466 -1.30624 -1.24006 -1.17621 -1.11478 -1.05587 -0.99956 -0.94596 ...
-0.89518 -0.84731 -0.80246 -0.75663 -0.69834 -0.64029 -0.58251 -0.52501 -0.46783 -0.41099 -0.35451 -0.29842 ...
-0.24274 -0.18750 -0.13273 -0.07845 -0.02470 0.00000;
8.85200 8.63150 8.35840 8.10120 7.85850 7.65258 7.49124 7.32853 7.16458 6.99954 6.83957 6.70559 ...
6.58115 6.46869 6.36813 6.27970 6.19583 6.10719 6.02404 5.94640 5.87876 5.82490 5.77551 5.72719 ...
5.67939 5.63443 5.59236 5.55322 5.51708 5.48399 5.45402 5.42723 5.39588 5.36425 5.33386 5.30472 ...
5.27688 5.25064 5.22800 5.20667 5.18660 5.16539 5.14401 5.12326 5.10314 5.06490 5.04681 5.02944 ...
5.01280 4.99693 4.98203 4.96818 4.95524 4.94324 4.93219 4.92215 4.91312 4.90515 4.89827 4.89251 ...
4.88790 4.88449 4.87824 4.87063 4.86324 4.85609 4.84918 4.84252 4.83611 4.82998 4.82412 4.81854 ...
4.81327 4.80830 4.80365 4.79890 4.79286 4.78685 4.78088 4.77494 4.76904 4.76318 4.75736 4.75159 ...
4.74586 4.74019 4.73456 4.72899 4.72349 4.72096 ];
G = get_G(f);
G = 10 .* log(G) ./ log(10);
out = interpolation(TableG2A(1,:), TableG2A(2,:), G);
end
function out = get_G(f)
%addpath(fullfile (pwd, 'functions'));
% low level gain of the cochlear amplifier relative to the gain at 500 Hz
LinearThreshold = 10.^( excitationthreshold(f) ./ 10 );
out = 10^(3.63/10) ./ LinearThreshold;
end
function out = excitationthreshold( f )
% version for TVL 2016 based on ANSI S3.4-2007 and Moore & Glasberg (2007)
Above500 = 3.63;
Threshold = [ 50 63 80 100 125 160 200 250 315 400 500 630 750 800 1000;
28.18 23.90 19.20 15.68 12.67 10.09 8.08 6.30 5.30 4.50 3.63 3.63 3.63 3.63 3.63 ];
Below500 = interpolation(Threshold(1,:), Threshold(2,:), f, 'linear');
out = ( f < 500 ) .* Below500 + ( f >= 500 ) .* Above500;
end