Mercurial > hg > webaudioevaluationtool
comparison core.js @ 1430:e3ff8b7d6538
Automatic Loudness normalisation to -23 LUFS
author | Nicholas Jillings <nickjillings@users.noreply.github.com> |
---|---|
date | Wed, 16 Dec 2015 12:15:18 +0000 |
parents | 61d11e39bdab |
children | a75a4e0af44f |
comparison
equal
deleted
inserted
replaced
1429:c06930d14ff7 | 1430:e3ff8b7d6538 |
---|---|
17 var projectReturn; // Hold the URL for the return | 17 var projectReturn; // Hold the URL for the return |
18 | 18 |
19 | 19 |
20 // Add a prototype to the bufferSourceNode to reference to the audioObject holding it | 20 // Add a prototype to the bufferSourceNode to reference to the audioObject holding it |
21 AudioBufferSourceNode.prototype.owner = undefined; | 21 AudioBufferSourceNode.prototype.owner = undefined; |
22 // Add a prototype to the bufferNode to hold the desired LINEAR gain | |
23 AudioBuffer.prototype.gain = undefined; | |
24 // Add a prototype to the bufferNode to hold the computed LUFS loudness | |
25 AudioBuffer.prototype.lufs = undefined; | |
22 | 26 |
23 window.onload = function() { | 27 window.onload = function() { |
24 // Function called once the browser has loaded all files. | 28 // Function called once the browser has loaded all files. |
25 // This should perform any initial commands such as structure / loading documents | 29 // This should perform any initial commands such as structure / loading documents |
26 | 30 |
111 break; | 115 break; |
112 } | 116 } |
113 } | 117 } |
114 if (buffer == null) | 118 if (buffer == null) |
115 { | 119 { |
116 buffer = new audioEngineContext.bufferObj(URL); | 120 buffer = new audioEngineContext.bufferObj(); |
121 buffer.getMedia(URL); | |
117 audioEngineContext.buffers.push(buffer); | 122 audioEngineContext.buffers.push(buffer); |
118 } | 123 } |
119 }); | 124 }); |
120 }); | 125 }); |
121 | 126 |
755 | 760 |
756 // Create store for new audioObjects | 761 // Create store for new audioObjects |
757 this.audioObjects = []; | 762 this.audioObjects = []; |
758 | 763 |
759 this.buffers = []; | 764 this.buffers = []; |
760 this.bufferObj = function(url) | 765 this.bufferObj = function() |
761 { | 766 { |
762 this.url = url; | 767 this.url = null; |
763 this.buffer = null; | 768 this.buffer = null; |
764 this.xmlRequest = new XMLHttpRequest(); | 769 this.xmlRequest = new XMLHttpRequest(); |
765 this.users = []; | 770 this.users = []; |
766 this.xmlRequest.open('GET',this.url,true); | 771 this.getMedia = function(url) { |
767 this.xmlRequest.responseType = 'arraybuffer'; | 772 this.url = url; |
768 | 773 this.xmlRequest.open('GET',this.url,true); |
769 var bufferObj = this; | 774 this.xmlRequest.responseType = 'arraybuffer'; |
770 | 775 |
771 // Create callback to decode the data asynchronously | 776 var bufferObj = this; |
772 this.xmlRequest.onloadend = function() { | 777 |
773 audioContext.decodeAudioData(bufferObj.xmlRequest.response, function(decodedData) { | 778 // Create callback to decode the data asynchronously |
774 bufferObj.buffer = decodedData; | 779 this.xmlRequest.onloadend = function() { |
775 for (var i=0; i<bufferObj.users.length; i++) | 780 audioContext.decodeAudioData(bufferObj.xmlRequest.response, function(decodedData) { |
776 { | 781 bufferObj.buffer = decodedData; |
777 bufferObj.users[i].state = 1; | 782 for (var i=0; i<bufferObj.users.length; i++) |
778 if (bufferObj.users[i].interfaceDOM != null) | |
779 { | 783 { |
780 bufferObj.users[i].interfaceDOM.enable(); | 784 bufferObj.users[i].state = 1; |
785 if (bufferObj.users[i].interfaceDOM != null) | |
786 { | |
787 bufferObj.users[i].interfaceDOM.enable(); | |
788 } | |
781 } | 789 } |
782 } | 790 calculateLoudness(bufferObj.buffer,"I"); |
783 }, function(){ | 791 }, function(){ |
784 // Should only be called if there was an error, but sometimes gets called continuously | 792 // Should only be called if there was an error, but sometimes gets called continuously |
785 // Check here if the error is genuine | 793 // Check here if the error is genuine |
786 if (bufferObj.buffer == undefined) { | 794 if (bufferObj.buffer == undefined) { |
787 // Genuine error | 795 // Genuine error |
788 console.log('FATAL - Error loading buffer on '+audioObj.id); | 796 console.log('FATAL - Error loading buffer on '+audioObj.id); |
789 if (request.status == 404) | 797 if (request.status == 404) |
790 { | 798 { |
791 console.log('FATAL - Fragment '+audioObj.id+' 404 error'); | 799 console.log('FATAL - Fragment '+audioObj.id+' 404 error'); |
792 console.log('URL: '+audioObj.url); | 800 console.log('URL: '+audioObj.url); |
793 errorSessionDump('Fragment '+audioObj.id+' 404 error'); | 801 errorSessionDump('Fragment '+audioObj.id+' 404 error'); |
802 } | |
794 } | 803 } |
795 } | 804 }); |
796 }); | 805 }; |
806 this.xmlRequest.send(); | |
797 }; | 807 }; |
798 this.xmlRequest.send(); | |
799 }; | 808 }; |
800 | 809 |
801 this.play = function(id) { | 810 this.play = function(id) { |
802 // Start the timer and set the audioEngine state to playing (1) | 811 // Start the timer and set the audioEngine state to playing (1) |
803 if (this.status == 0 && this.loopPlayback) { | 812 if (this.status == 0 && this.loopPlayback) { |
836 { | 845 { |
837 if (i != id) { | 846 if (i != id) { |
838 this.audioObjects[i].outputGain.gain.value = 0.0; | 847 this.audioObjects[i].outputGain.gain.value = 0.0; |
839 this.audioObjects[i].stop(); | 848 this.audioObjects[i].stop(); |
840 } else if (i == id) { | 849 } else if (i == id) { |
841 this.audioObjects[id].outputGain.gain.value = this.audioObjects[id].specification.gain; | 850 this.audioObjects[id].outputGain.gain.value = this.audioObjects[id].specification.gain*this.audioObjects[id].buffer.buffer.gain; |
842 this.audioObjects[id].play(audioContext.currentTime+0.01); | 851 this.audioObjects[id].play(audioContext.currentTime+0.01); |
843 } | 852 } |
844 } | 853 } |
845 } | 854 } |
846 interfaceContext.playhead.start(); | 855 interfaceContext.playhead.start(); |
879 } | 888 } |
880 } | 889 } |
881 if (buffer == null) | 890 if (buffer == null) |
882 { | 891 { |
883 console.log("[WARN]: Buffer was not loaded in pre-test! "+URL); | 892 console.log("[WARN]: Buffer was not loaded in pre-test! "+URL); |
884 buffer = new this.bufferObj(URL); | 893 buffer = new this.bufferObj(); |
894 buffer.getMedia(URL); | |
885 this.buffers.push(buffer); | 895 this.buffers.push(buffer); |
886 } | 896 } |
887 this.audioObjects[audioObjectId].specification = element; | 897 this.audioObjects[audioObjectId].specification = element; |
888 this.audioObjects[audioObjectId].url = URL; | 898 this.audioObjects[audioObjectId].url = URL; |
889 this.audioObjects[audioObjectId].buffer = buffer; | 899 this.audioObjects[audioObjectId].buffer = buffer; |
929 }; | 939 }; |
930 | 940 |
931 this.setSynchronousLoop = function() { | 941 this.setSynchronousLoop = function() { |
932 // Pads the signals so they are all exactly the same length | 942 // Pads the signals so they are all exactly the same length |
933 var length = 0; | 943 var length = 0; |
934 var lens = []; | |
935 var maxId; | 944 var maxId; |
936 for (var i=0; i<this.audioObjects.length; i++) | 945 for (var i=0; i<this.audioObjects.length; i++) |
937 { | 946 { |
938 lens.push(this.audioObjects[i].buffer.buffer.length); | |
939 if (length < this.audioObjects[i].buffer.buffer.length) | 947 if (length < this.audioObjects[i].buffer.buffer.length) |
940 { | 948 { |
941 length = this.audioObjects[i].buffer.buffer.length; | 949 length = this.audioObjects[i].buffer.buffer.length; |
942 maxId = i; | 950 maxId = i; |
943 } | 951 } |
944 } | 952 } |
945 // Perform difference | |
946 for (var i=0; i<lens.length; i++) | |
947 { | |
948 lens[i] = length - lens[i]; | |
949 } | |
950 // Extract the audio and zero-pad | 953 // Extract the audio and zero-pad |
951 for (var i=0; i<lens.length; i++) | 954 for (var i=0; i<this.audioObjects.length; i++) |
952 { | 955 { |
953 var orig = this.audioObjects[i].buffer.buffer; | 956 var orig = this.audioObjects[i].buffer.buffer; |
954 var hold = audioContext.createBuffer(orig.numberOfChannels,length,orig.sampleRate); | 957 var hold = audioContext.createBuffer(orig.numberOfChannels,length,orig.sampleRate); |
955 for (var c=0; c<orig.numberOfChannels; c++) | 958 for (var c=0; c<orig.numberOfChannels; c++) |
956 { | 959 { |
957 var inData = hold.getChannelData(c); | 960 var inData = hold.getChannelData(c); |
958 var outData = orig.getChannelData(c); | 961 var outData = orig.getChannelData(c); |
959 for (var n=0; n<orig.length; n++) | 962 for (var n=0; n<orig.length; n++) |
960 {inData[n] = outData[n];} | 963 {inData[n] = outData[n];} |
961 } | 964 } |
965 hold.gain = orig.gain; | |
966 hold.lufs = orig.lufs; | |
962 this.audioObjects[i].buffer.buffer = hold; | 967 this.audioObjects[i].buffer.buffer = hold; |
963 delete orig; | |
964 } | 968 } |
965 }; | 969 }; |
966 | 970 |
967 } | 971 } |
968 | 972 |
992 // the audiobuffer is not designed for multi-start playback | 996 // the audiobuffer is not designed for multi-start playback |
993 // When stopeed, the buffer node is deleted and recreated with the stored buffer. | 997 // When stopeed, the buffer node is deleted and recreated with the stored buffer. |
994 this.buffer; | 998 this.buffer; |
995 | 999 |
996 this.loopStart = function() { | 1000 this.loopStart = function() { |
997 this.outputGain.gain.value = 1.0; | 1001 this.outputGain.gain.value = this.specification.gain*this.buffer.buffer.gain; |
998 this.metric.startListening(audioEngineContext.timer.getTestTime()); | 1002 this.metric.startListening(audioEngineContext.timer.getTestTime()); |
999 }; | 1003 }; |
1000 | 1004 |
1001 this.loopStop = function() { | 1005 this.loopStop = function() { |
1002 if (this.outputGain.gain.value != 0.0) { | 1006 if (this.outputGain.gain.value != 0.0) { |