comparison loudness.js @ 793:261d92ea87e1

Automatic Loudness normalisation to -23 LUFS
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Wed, 16 Dec 2015 12:15:18 +0000
parents 7b522c145516
children 8f88db0c38b5
comparison
equal deleted inserted replaced
792:7b522c145516 793:261d92ea87e1
4 * Allows for automatic calculation of loudness of Web Audio API Buffer objects, 4 * Allows for automatic calculation of loudness of Web Audio API Buffer objects,
5 * return gain values to correct for a target loudness or match loudness between 5 * return gain values to correct for a target loudness or match loudness between
6 * multiple objects 6 * multiple objects
7 */ 7 */
8 8
9 function getLoudness(buffer, result, timescale, offlineContext) 9 var interval_cal_loudness_event = null;
10
11 function calculateLoudness(buffer, timescale, target, offlineContext)
10 { 12 {
11 // This function returns the EBU R 128 specification loudness model 13 // This function returns the EBU R 128 specification loudness model and sets the linear gain required to match -23 LUFS
12 // buffer -> Web Audio API Buffer object 14 // buffer -> Web Audio API Buffer object
13 // timescale -> M or Momentary (returns Array), S or Short (returns Array), 15 // timescale -> M or Momentary (returns Array), S or Short (returns Array),
14 // I or Integrated (default, returns number) 16 // I or Integrated (default, returns number)
17 // target -> default is -23 LUFS but can be any LUFS measurement.
15 18
16 // Create the required filters 19 if (buffer == undefined)
17 if (buffer == undefined || result == undefined)
18 { 20 {
19 return 0; 21 return 0;
20 } 22 }
21 if (timescale == undefined) 23 if (timescale == undefined)
22 { 24 {
23 timescale = "I"; 25 timescale = "I";
24 } 26 }
27 if (target == undefined)
28 {
29 target = -23;
30 }
25 if (offlineContext == undefined) 31 if (offlineContext == undefined)
26 { 32 {
27 offlineContext = new OfflineAudioContext(buffer.numberOfChannels, buffer.length, buffer.sampleRate); 33 offlineContext = new OfflineAudioContext(buffer.numberOfChannels, buffer.length, buffer.sampleRate);
28 } 34 }
35 // Create the required filters
29 var KFilter = offlineContext.createBiquadFilter(); 36 var KFilter = offlineContext.createBiquadFilter();
30 KFilter.type = "highshelf"; 37 KFilter.type = "highshelf";
31 KFilter.gain.value = 4; 38 KFilter.gain.value = 4;
32 KFilter.frequency.value = 1480; 39 KFilter.frequency.value = 1480;
33 40
43 KFilter.connect(HPFilter); 50 KFilter.connect(HPFilter);
44 HPFilter.connect(offlineContext.destination); 51 HPFilter.connect(offlineContext.destination);
45 processSource.start(); 52 processSource.start();
46 offlineContext.startRendering().then(function(renderedBuffer) { 53 offlineContext.startRendering().then(function(renderedBuffer) {
47 // Have the renderedBuffer information, now continue processing 54 // Have the renderedBuffer information, now continue processing
48 console.log(renderedBuffer);
49 switch(timescale) 55 switch(timescale)
50 { 56 {
51 case "I": 57 case "I":
52 var blockEnergy = calculateProcessedLoudness(renderedBuffer, 400, 0.75); 58 var blockEnergy = calculateProcessedLoudness(renderedBuffer, 400, 0.75);
53 // Apply the absolute gate 59 // Apply the absolute gate
85 relgateEnergy[c].push(blockEnergy[c][i]); 91 relgateEnergy[c].push(blockEnergy[c][i]);
86 } 92 }
87 } 93 }
88 } 94 }
89 var overallRelLoudness = calculateOverallLoudnessFromChannelBlocks(relgateEnergy); 95 var overallRelLoudness = calculateOverallLoudnessFromChannelBlocks(relgateEnergy);
90 result[0] = overallRelLoudness; 96 buffer.lufs = overallRelLoudness;
97 var diff = -23 -overallRelLoudness;
98 buffer.gain = decibelToLinear(diff);
91 } 99 }
92 }).catch(function(err) { 100 }).catch(function(err) {
93 console.log(err); 101 console.log(err);
94 result[0] = 1; 102 buffer.lufs = 1;
95 }); 103 });
96 } 104 }
97 105
98 function calculateProcessedLoudness(buffer, winDur, overlap) 106 function calculateProcessedLoudness(buffer, winDur, overlap)
99 { 107 {