xref: /aosp_15_r20/external/flac/src/utils/loudness/loudness.sci (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1*600f14f4SXin Li// Equal Loudness Filter
2*600f14f4SXin Li//
3*600f14f4SXin Li// Adapted from original MATLAB code written by David Robinson
4*600f14f4SXin Li//
5*600f14f4SXin Li//      http://replaygain.hydrogenaudio.org/proposal/equal_loudness.html
6*600f14f4SXin Li//      http://replaygain.hydrogenaudio.org/proposal/mfiles/equalloudfilt.m
7*600f14f4SXin Li
8*600f14f4SXin Li// *****************************************************************************
9*600f14f4SXin Li// Print Filter Coefficients
10*600f14f4SXin Li//
11*600f14f4SXin Li// This function takes a vector of filter tap settings, and prints
12*600f14f4SXin Li// each tap setting from least significant to most significant.
13*600f14f4SXin Li
14*600f14f4SXin Lifunction c=printcoeff(p)
15*600f14f4SXin Li
16*600f14f4SXin Li  c=coeff(p);
17*600f14f4SXin Li  c=c($:-1:1);
18*600f14f4SXin Li
19*600f14f4SXin Li  for ix = 1:1:length(c)
20*600f14f4SXin Li    if ix > 1
21*600f14f4SXin Li        printf(" ")
22*600f14f4SXin Li    end
23*600f14f4SXin Li    printf("%.14f", c(ix));
24*600f14f4SXin Li  end
25*600f14f4SXin Li
26*600f14f4SXin Liendfunction
27*600f14f4SXin Li
28*600f14f4SXin Li// *****************************************************************************
29*600f14f4SXin Li// Equal Loudness Filter
30*600f14f4SXin Li//
31*600f14f4SXin Li// This function is adapted from David Robison's original MATLAB code.
32*600f14f4SXin Li// Apart from changes to port it to scilab, the other change is to
33*600f14f4SXin Li// use a single specification of the frequency points in the 80dB Equal
34*600f14f4SXin Li// Loudness curve.
35*600f14f4SXin Li//
36*600f14f4SXin Li// The original code had different curves for different sampling
37*600f14f4SXin Li// frequencies. This code dynamically computes the current data
38*600f14f4SXin Li// points to use as determined by the Nyquist frequency.
39*600f14f4SXin Li
40*600f14f4SXin Lifunction [a1,b1,a2,b2]=equalloudfilt(fs);
41*600f14f4SXin Li// Design a filter to match equal loudness curves
42*600f14f4SXin Li// 9/7/2001
43*600f14f4SXin Li
44*600f14f4SXin Li[%nargout,%nargin]=argn(0);
45*600f14f4SXin Li
46*600f14f4SXin Li// If the user hasn't specified a sampling frequency, use the CD default
47*600f14f4SXin Liif %nargin<1 then
48*600f14f4SXin Li   fs=44100;
49*600f14f4SXin Liend
50*600f14f4SXin Li
51*600f14f4SXin Li// Specify the 80 dB Equal Loudness curve
52*600f14f4SXin LiEL80=[0,120;20,113;30,103;40,97;50,93;60,91;70,89;80,87;90,86; ..
53*600f14f4SXin Li      ..
54*600f14f4SXin Li      100,85;200,78;300,76;400,76;500,76;600,76;700,77;800,78;900,79.5; ..
55*600f14f4SXin Li      ..
56*600f14f4SXin Li      1000,80;1500,79;2000,77;2500,74;3000,71.5;3700,70;4000,70.5; ..
57*600f14f4SXin Li      5000,74;6000,79;7000,84;8000,86;9000,86; ..
58*600f14f4SXin Li      ..
59*600f14f4SXin Li      10000,85;12000,95;15000,110;20000,125;24000,140];
60*600f14f4SXin Li
61*600f14f4SXin Lifor ex = 1:1:length(EL80(:,1))
62*600f14f4SXin Li  if EL80(ex,1) > fs/2
63*600f14f4SXin Li    EL80 = [ EL80(1:ex-1,:); fs/2, EL80(ex-1,2) ];
64*600f14f4SXin Li    break
65*600f14f4SXin Li  elseif EL80(ex,1) == fs/2
66*600f14f4SXin Li    EL80 = EL80(1:ex,:);
67*600f14f4SXin Li    break
68*600f14f4SXin Li  end
69*600f14f4SXin Li  if ex == length(EL80(:,1))
70*600f14f4SXin Li    EL80 = [ EL80(1:$, :); fs/2, EL80($,2) ];
71*600f14f4SXin Li  end
72*600f14f4SXin Liend
73*600f14f4SXin Li
74*600f14f4SXin Li// convert frequency and amplitude of the equal loudness curve into format suitable for yulewalk
75*600f14f4SXin Lif=EL80(:,1)./(fs/2);
76*600f14f4SXin Lim=10.^((70-EL80(:,2))/20);
77*600f14f4SXin Li
78*600f14f4SXin Li// Use a MATLAB utility to design a best bit IIR filter
79*600f14f4SXin Li[b1,a1]=yulewalk(10,f,m);
80*600f14f4SXin Li
81*600f14f4SXin Li// Add a 2nd order high pass filter at 150Hz to finish the job
82*600f14f4SXin Lihz=iir(2,'hp','butt',[150/fs,0],[1e-3 1e-3]);
83*600f14f4SXin Lib2=numer(hz); // b2=b2($:-1:1);
84*600f14f4SXin Lia2=denom(hz); // a2=a2($:-1:1);
85*600f14f4SXin Li
86*600f14f4SXin Liendfunction
87*600f14f4SXin Li
88*600f14f4SXin Li// *****************************************************************************
89*600f14f4SXin Li// Generate Filter Taps
90*600f14f4SXin Li//
91*600f14f4SXin Li// Generate the filter taps for each of the desired frequencies.
92*600f14f4SXin Li
93*600f14f4SXin Liformat('v', 16);
94*600f14f4SXin Li
95*600f14f4SXin Lifreqs = [  8000 11025 12000 16000 18900 22050 24000 ..
96*600f14f4SXin Li          28000 32000 36000 37800 44100 48000 ];
97*600f14f4SXin Li
98*600f14f4SXin Lifor fx = 1:1:length(freqs)
99*600f14f4SXin Li
100*600f14f4SXin Li  printf("\n%d\n", freqs(fx));
101*600f14f4SXin Li
102*600f14f4SXin Li  [a1,b1,a2,b2] = equalloudfilt(freqs(fx));
103*600f14f4SXin Li
104*600f14f4SXin Li  printf("{ "); bb=printcoeff(b1); printf(" }\n");
105*600f14f4SXin Li  printf("{ "); aa=printcoeff(a1); printf(" }\n");
106*600f14f4SXin Li
107*600f14f4SXin Li  printf("{ "); printcoeff(b2); printf(" }\n");
108*600f14f4SXin Li  printf("{ "); printcoeff(a2); printf(" }\n");
109*600f14f4SXin Li
110*600f14f4SXin Li// freqz_fwd(bb,aa,1024,freqs(fx));
111*600f14f4SXin Li
112*600f14f4SXin Liend
113*600f14f4SXin Li
114*600f14f4SXin Li
115*600f14f4SXin Liquit
116