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