me@1936: /** me@1936: * loundess.js me@1936: * Loudness module for the Web Audio Evaluation Toolbox me@1936: * Allows for automatic calculation of loudness of Web Audio API Buffer objects, me@1936: * return gain values to correct for a target loudness or match loudness between me@1936: * multiple objects me@1936: */ me@1936: me@1936: var interval_cal_loudness_event = null; me@1936: me@1936: if (typeof OfflineAudioContext == "undefined"){ me@1936: var OfflineAudioContext = webkitOfflineAudioContext; me@1936: } me@1936: me@1936: function calculateLoudness(buffer, timescale, target, offlineContext) me@1936: { me@1936: // This function returns the EBU R 128 specification loudness model and sets the linear gain required to match -23 LUFS me@1936: // buffer -> Web Audio API Buffer object me@1936: // timescale -> M or Momentary (returns Array), S or Short (returns Array), me@1936: // I or Integrated (default, returns number) me@1936: // target -> default is -23 LUFS but can be any LUFS measurement. me@1936: me@1936: if (buffer == undefined) me@1936: { me@1936: return 0; me@1936: } me@1936: if (timescale == undefined) me@1936: { me@1936: timescale = "I"; me@1936: } me@1936: if (target == undefined) me@1936: { me@1936: target = -23; me@1936: } me@1936: if (offlineContext == undefined) me@1936: { me@1936: offlineContext = new OfflineAudioContext(audioContext.destination.channelCount, buffer.buffer.duration*audioContext.sampleRate, audioContext.sampleRate); me@1936: } me@1936: // Create the required filters me@1936: var KFilter = offlineContext.createBiquadFilter(); me@1936: KFilter.type = "highshelf"; me@1936: KFilter.gain.value = 4; me@1936: KFilter.frequency.value = 1500; me@1936: me@1936: var HPFilter = offlineContext.createBiquadFilter(); me@1936: HPFilter.type = "highpass"; me@1936: HPFilter.Q.value = 0.5; me@1936: HPFilter.frequency.value = 38; me@1936: // copy Data into the process buffer me@1936: var processSource = offlineContext.createBufferSource(); me@1936: processSource.buffer = buffer.buffer; me@1936: me@1936: processSource.connect(KFilter); me@1936: KFilter.connect(HPFilter); me@1936: HPFilter.connect(offlineContext.destination); me@1936: offlineContext.oncomplete = function(renderedBuffer) { me@1936: // Have the renderedBuffer information, now continue processing me@1936: if (typeof renderedBuffer.renderedBuffer == 'object') { me@1936: renderedBuffer = renderedBuffer.renderedBuffer; me@1936: } me@1936: switch(timescale) me@1936: { me@1936: case "I": me@1936: // Calculate the Mean Squared of a signal me@1936: var MS = calculateMeanSquared(renderedBuffer,0.4,0.75); me@1936: // Calculate the Loudness of each block me@1936: var MSL = calculateLoudnessFromBlocks(MS); me@1936: // Get blocks from Absolute Gate me@1936: var LK = loudnessGate(MSL,MS,-70); me@1936: // Calculate Loudness me@1936: var LK_gate = loudnessOfBlocks(LK); me@1936: // Get blocks from Relative Gate me@1936: var RK = loudnessGate(MSL,MS,LK_gate-10); me@1936: var RK_gate = loudnessOfBlocks(RK); me@1936: buffer.buffer.lufs = RK_gate; me@1936: } me@1936: buffer.ready(); me@1936: }; nickjillings@1939: processSource.start(0); me@1936: offlineContext.startRendering(); me@1936: } me@1936: me@1936: function calculateMeanSquared(buffer,frame_dur,frame_overlap) me@1936: { me@1936: frame_size = Math.floor(buffer.sampleRate*frame_dur); me@1936: step_size = Math.floor(frame_size*(1.0-frame_overlap)); me@1936: num_frames = Math.floor((buffer.length-frame_size)/step_size); me@1936: me@1936: MS = Array(buffer.numberOfChannels); me@1936: for (var c=0; c= 3){G = 1.41;} me@1936: sum += blocks[c][n]*G; me@1936: } me@1936: MSL[n] = -0.691 + 10*Math.log10(sum); me@1936: } me@1936: return MSL; me@1936: } me@1936: me@1936: function loudnessGate(blocks,source,threshold) me@1936: { me@1936: var num_frames = source[0].length; me@1936: var num_channels = source.length; me@1936: var LK = Array(num_channels); me@1936: for (var c=0; c threshold) me@1936: { me@1936: for (var c=0; c= 3){G = 1.41;} me@1936: sum += blocks[c][n]*G; me@1936: } me@1936: sum /= num_frames; me@1936: loudness += sum; me@1936: } me@1936: loudness = -0.691 + 10 * Math.log10(loudness); me@1936: return loudness; me@1936: }