Mercurial > hg > webaudioevaluationtool
view loudness.js @ 2191:dd5a8556235c
Calibration sliders update on mouse move trigger
author | Nicholas Jillings <nickjillings@users.noreply.github.com> |
---|---|
date | Tue, 29 Mar 2016 14:37:07 +0100 |
parents | 749adcb68e99 |
children |
line wrap: on
line source
/** * loundess.js * Loudness module for the Web Audio Evaluation Toolbox * Allows for automatic calculation of loudness of Web Audio API Buffer objects, * return gain values to correct for a target loudness or match loudness between * multiple objects */ var interval_cal_loudness_event = null; if (typeof OfflineAudioContext == "undefined"){ var OfflineAudioContext = webkitOfflineAudioContext; } function calculateLoudness(buffer, timescale, target, offlineContext) { // This function returns the EBU R 128 specification loudness model and sets the linear gain required to match -23 LUFS // buffer -> Web Audio API Buffer object // timescale -> M or Momentary (returns Array), S or Short (returns Array), // I or Integrated (default, returns number) // target -> default is -23 LUFS but can be any LUFS measurement. if (buffer == undefined) { return 0; } if (timescale == undefined) { timescale = "I"; } if (target == undefined) { target = -23; } if (offlineContext == undefined) { offlineContext = new OfflineAudioContext(audioContext.destination.channelCount, buffer.buffer.duration*audioContext.sampleRate, audioContext.sampleRate); } // Create the required filters var KFilter = offlineContext.createBiquadFilter(); KFilter.type = "highshelf"; KFilter.gain.value = 4; KFilter.frequency.value = 1500; var HPFilter = offlineContext.createBiquadFilter(); HPFilter.type = "highpass"; HPFilter.Q.value = 0.5; HPFilter.frequency.value = 38; // copy Data into the process buffer var processSource = offlineContext.createBufferSource(); processSource.buffer = buffer.buffer; processSource.connect(KFilter); KFilter.connect(HPFilter); HPFilter.connect(offlineContext.destination); offlineContext.oncomplete = function(renderedBuffer) { // Have the renderedBuffer information, now continue processing if (typeof renderedBuffer.renderedBuffer == 'object') { renderedBuffer = renderedBuffer.renderedBuffer; } switch(timescale) { case "I": // Calculate the Mean Squared of a signal var MS = calculateMeanSquared(renderedBuffer,0.4,0.75); // Calculate the Loudness of each block var MSL = calculateLoudnessFromBlocks(MS); // Get blocks from Absolute Gate var LK = loudnessGate(MSL,MS,-70); // Calculate Loudness var LK_gate = loudnessOfBlocks(LK); // Get blocks from Relative Gate var RK = loudnessGate(MSL,MS,LK_gate-10); var RK_gate = loudnessOfBlocks(RK); buffer.buffer.lufs = RK_gate; } buffer.ready(); }; processSource.start(0); offlineContext.startRendering(); } function calculateMeanSquared(buffer,frame_dur,frame_overlap) { frame_size = Math.floor(buffer.sampleRate*frame_dur); step_size = Math.floor(frame_size*(1.0-frame_overlap)); num_frames = Math.floor((buffer.length-frame_size)/step_size); MS = Array(buffer.numberOfChannels); for (var c=0; c<buffer.numberOfChannels; c++) { MS[c] = new Float32Array(num_frames); var data = buffer.getChannelData(c); for (var no=0; no<num_frames; no++) { MS[c][no] = 0.0; for (var ptr=0; ptr<frame_size; ptr++) { var sample = data[no*step_size+ptr]; MS[c][no] += sample*sample; } MS[c][no] /= frame_size; } } return MS; } function calculateLoudnessFromBlocks(blocks) { var num_frames = blocks[0].length; var num_channels = blocks.length; var MSL = Array(num_frames); for (var n=0; n<num_frames; n++) { var sum = 0; for (var c=0; c<num_channels; c++) { var G = 1.0; if(G >= 3){G = 1.41;} sum += blocks[c][n]*G; } MSL[n] = -0.691 + 10*Math.log10(sum); } return MSL; } function loudnessGate(blocks,source,threshold) { var num_frames = source[0].length; var num_channels = source.length; var LK = Array(num_channels); for (var c=0; c<num_channels; c++) { LK[c] = []; } for (var n=0; n<num_frames; n++) { if (blocks[n] > threshold) { for (var c=0; c<num_channels; c++) { LK[c].push(source[c][n]); } } } return LK; } function loudnessOfBlocks(blocks) { var num_frames = blocks[0].length; var num_channels = blocks.length; var loudness = 0.0; for (var n=0; n<num_frames; n++) { var sum = 0; for (var c=0; c<num_channels; c++) { var G = 1.0; if(G >= 3){G = 1.41;} sum += blocks[c][n]*G; } sum /= num_frames; loudness += sum; } loudness = -0.691 + 10 * Math.log10(loudness); return loudness; }