n@792: /** n@792: * loundess.js n@792: * Loudness module for the Web Audio Evaluation Toolbox n@792: * Allows for automatic calculation of loudness of Web Audio API Buffer objects, n@792: * return gain values to correct for a target loudness or match loudness between n@792: * multiple objects n@792: */ n@792: n@792: function getLoudness(buffer, result, timescale, offlineContext) n@792: { n@792: // This function returns the EBU R 128 specification loudness model n@792: // buffer -> Web Audio API Buffer object n@792: // timescale -> M or Momentary (returns Array), S or Short (returns Array), n@792: // I or Integrated (default, returns number) n@792: n@792: // Create the required filters n@792: if (buffer == undefined || result == undefined) n@792: { n@792: return 0; n@792: } n@792: if (timescale == undefined) n@792: { n@792: timescale = "I"; n@792: } n@792: if (offlineContext == undefined) n@792: { n@792: offlineContext = new OfflineAudioContext(buffer.numberOfChannels, buffer.length, buffer.sampleRate); n@792: } n@792: var KFilter = offlineContext.createBiquadFilter(); n@792: KFilter.type = "highshelf"; n@792: KFilter.gain.value = 4; n@792: KFilter.frequency.value = 1480; n@792: n@792: var HPFilter = offlineContext.createBiquadFilter(); n@792: HPFilter.type = "highpass"; n@792: HPFilter.Q.value = 0.707; n@792: HPFilter.frequency.value = 60; n@792: // copy Data into the process buffer n@792: var processSource = offlineContext.createBufferSource(); n@792: processSource.buffer = buffer; n@792: n@792: processSource.connect(KFilter); n@792: KFilter.connect(HPFilter); n@792: HPFilter.connect(offlineContext.destination); n@792: processSource.start(); n@792: offlineContext.startRendering().then(function(renderedBuffer) { n@792: // Have the renderedBuffer information, now continue processing n@792: console.log(renderedBuffer); n@792: switch(timescale) n@792: { n@792: case "I": n@792: var blockEnergy = calculateProcessedLoudness(renderedBuffer, 400, 0.75); n@792: // Apply the absolute gate n@792: var loudness = calculateLoudnessFromChannelBlocks(blockEnergy); n@792: var absgatedEnergy = new Array(blockEnergy.length); n@792: for (var c=0; c= -70) n@792: { n@792: for (var c=0; c= relGateLevel) n@792: { n@792: for (var c=0; c= 4) {G = 1.41;} n@792: sigma += blockEnergy[channel][i]*G; n@792: } n@792: loudness[i] = -0.691 + 10*Math.log10(sigma); n@792: } n@792: return loudness; n@792: } n@792: function calculateOverallLoudnessFromChannelBlocks(blockEnergy) n@792: { n@792: // Loudness n@792: var summation = 0; n@792: for (var channel = 0; channel < blockEnergy.length; channel++) n@792: { n@792: var G = 1.0; n@792: if (channel >= 4) {G = 1.41;} n@792: var sigma = 0; n@792: for (var i=0; i