comparison loudness.js @ 486:3bcee92d95ab Dev_main

Fixed loudness. Now passes all EBU 3341 tests for Integrated loudness. Fixed WAVE decoder error for non-mono sources.
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Tue, 26 Jan 2016 11:01:55 +0000
parents d39c99d83891
children ea2c4e515f44
comparison
equal deleted inserted replaced
485:92f26057b934 486:3bcee92d95ab
60 renderedBuffer = renderedBuffer.renderedBuffer; 60 renderedBuffer = renderedBuffer.renderedBuffer;
61 } 61 }
62 switch(timescale) 62 switch(timescale)
63 { 63 {
64 case "I": 64 case "I":
65 var blockEnergy = calculateProcessedLoudness(renderedBuffer, 400, 0.75); 65 // Calculate the Mean Squared of a signal
66 // Apply the absolute gate 66 var MS = calculateMeanSquared(renderedBuffer,0.4,0.75);
67 var loudness = calculateLoudnessFromChannelBlocks(blockEnergy); 67 // Calculate the Loudness of each block
68 var absgatedEnergy = new Array(blockEnergy.length); 68 var MSL = calculateLoudnessFromBlocks(MS);
69 for (var c=0; c<blockEnergy.length; c++) 69 // Get blocks from Absolute Gate
70 { 70 var LK = loudnessGate(MSL,MS,-70);
71 absgatedEnergy[c] = []; 71 // Calculate Loudness
72 } 72 var LK_gate = loudnessOfBlocks(LK);
73 for (var i=0; i<loudness.length; i++) 73 // Get blocks from Relative Gate
74 { 74 var RK = loudnessGate(MSL,MS,LK_gate-10);
75 if (loudness[i] >= -70) 75 var RK_gate = loudnessOfBlocks(RK);
76 { 76 buffer.buffer.lufs = RK_gate;
77 for (var c=0; c<blockEnergy.length; c++)
78 {
79 absgatedEnergy[c].push(blockEnergy[c][i]);
80 }
81 }
82 }
83 var overallAbsLoudness = calculateOverallLoudnessFromChannelBlocks(absgatedEnergy);
84
85 //applying the relative gate 8 dB down from overallAbsLoudness
86 var relGateLevel = overallAbsLoudness - 8;
87 var relgateEnergy = new Array(blockEnergy.length);
88 for (var c=0; c<blockEnergy.length; c++)
89 {
90 relgateEnergy[c] = [];
91 }
92 for (var i=0; i<loudness.length; i++)
93 {
94 if (loudness[i] >= relGateLevel)
95 {
96 for (var c=0; c<blockEnergy.length; c++)
97 {
98 relgateEnergy[c].push(blockEnergy[c][i]);
99 }
100 }
101 }
102 var overallRelLoudness = calculateOverallLoudnessFromChannelBlocks(relgateEnergy);
103 buffer.buffer.lufs = overallRelLoudness;
104 buffer.ready();
105 } 77 }
106 }; 78 };
107 offlineContext.startRendering(); 79 offlineContext.startRendering();
108 } 80 }
109 81
110 function calculateProcessedLoudness(buffer, winDur, overlap) 82 function calculateMeanSquared(buffer,frame_dur,frame_overlap)
111 { 83 {
112 // Buffer Web Audio buffer node 84 frame_size = Math.floor(buffer.sampleRate*frame_dur);
113 // winDur Window Duration in milliseconds 85 step_size = Math.floor(frame_size*(1.0-frame_overlap));
114 // overlap Window overlap as normalised (0.5 = 50% overlap); 86 num_frames = Math.floor((buffer.length-frame_size)/step_size);
115 if (buffer == undefined) 87
116 { 88 MS = Array(buffer.numberOfChannels);
117 return 0; 89 for (var c=0; c<buffer.numberOfChannels; c++)
118 } 90 {
119 if (winDur == undefined) 91 MS[c] = new Float32Array(num_frames);
120 { 92 var data = buffer.getChannelData(c);
121 winDur = 400; 93 for (var no=0; no<num_frames; no++)
122 } 94 {
123 if (overlap == undefined) 95 MS[c][no] = 0.0;
124 { 96 for (var ptr=0; ptr<frame_size; ptr++)
125 overlap = 0.5; 97 {
126 } 98 var sample = data[no*step_size+ptr];
127 var winSize = buffer.sampleRate*winDur/1000; 99 MS[c][no] += sample*sample;
128 var olapSize = (1-overlap)*winSize; 100 }
129 var numberOfFrames = Math.floor(buffer.length/olapSize - winSize/olapSize + 1); 101 MS[c][no] /= frame_size;
130 var blockEnergy = new Array(buffer.numberOfChannels); 102 }
131 for (var channel = 0; channel < buffer.numberOfChannels; channel++) 103 }
132 { 104 return MS;
133 blockEnergy[channel] = new Float32Array(numberOfFrames);
134 var data = buffer.getChannelData(channel);
135 for (var i=0; i<numberOfFrames; i++)
136 {
137 var sigma = 0;
138 for (var n=i*olapSize; n < i*olapSize+winSize; n++)
139 {
140 sigma += Math.pow(data[n],2);
141 }
142 blockEnergy[channel][i] = sigma/winSize;
143 }
144 }
145 return blockEnergy;
146 } 105 }
147 function calculateLoudnessFromChannelBlocks(blockEnergy) 106
107 function calculateLoudnessFromBlocks(blocks)
148 { 108 {
149 // Loudness 109 var num_frames = blocks[0].length;
150 var loudness = new Float32Array(blockEnergy[0].length); 110 var num_channels = blocks.length;
151 for (var i=0; i<blockEnergy[0].length; i++) 111 var MSL = Array(num_frames);
152 { 112 for (var n=0; n<num_frames; n++)
153 var sigma = 0; 113 {
154 for (var channel = 0; channel < blockEnergy.length; channel++) 114 var sum = 0;
155 { 115 for (var c=0; c<num_channels; c++)
156 var G = 1.0; 116 {
157 if (channel >= 4) {G = 1.41;} 117 var G = 1.0;
158 sigma += blockEnergy[channel][i]*G; 118 if(G >= 3){G = 1.41;}
159 } 119 sum += blocks[c][n]*G;
160 loudness[i] = -0.691 + 10*Math.log10(sigma); 120 }
161 } 121 MSL[n] = -0.691 + 10*Math.log10(sum);
162 return loudness; 122 }
123 return MSL;
163 } 124 }
164 function calculateOverallLoudnessFromChannelBlocks(blockEnergy) 125
126 function loudnessGate(blocks,source,threshold)
165 { 127 {
166 // Loudness 128 var num_frames = source[0].length;
167 var summation = 0; 129 var num_channels = source.length;
168 for (var channel = 0; channel < blockEnergy.length; channel++) 130 var LK = Array(num_channels);
169 { 131 for (var c=0; c<num_channels; c++)
170 var G = 1.0; 132 {
171 if (channel >= 4) {G = 1.41;} 133 LK[c] = [];
172 var sigma = 0; 134 }
173 for (var i=0; i<blockEnergy[0].length; i++) 135
174 { 136 for (var n=0; n<num_frames; n++)
175 sigma += blockEnergy[channel][i]; 137 {
176 } 138 if (blocks[n] > threshold)
177 sigma /= blockEnergy[0].length; 139 {
178 sigma *= G; 140 for (var c=0; c<num_channels; c++)
179 summation+= sigma; 141 {
180 } 142 LK[c].push(source[c][n]);
181 return -0.691 + 10*Math.log10(summation);; 143 }
144 }
145 }
146 return LK;
182 } 147 }
148
149 function loudnessOfBlocks(blocks)
150 {
151 var num_frames = blocks[0].length;
152 var num_channels = blocks.length;
153 var loudness = 0.0;
154 for (var n=0; n<num_frames; n++)
155 {
156 var sum = 0;
157 for (var c=0; c<num_channels; c++)
158 {
159 var G = 1.0;
160 if(G >= 3){G = 1.41;}
161 sum += blocks[c][n]*G;
162 }
163 sum /= num_frames;
164 loudness += sum;
165 }
166 loudness = -0.691 + 10 * Math.log10(loudness);
167 return loudness;
168 }