annotate core.js @ 1704:536818090e6a

Updated results XML generator to match documentation syntax.
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Thu, 09 Apr 2015 10:59:53 +0100
parents 93eaa894cc97
children fef9e8337cfd
rev   line source
nickjillings@1682 1 /**
nickjillings@1682 2 * core.js
nickjillings@1682 3 *
nickjillings@1682 4 * Main script to run, calls all other core functions and manages loading/store to backend.
nickjillings@1682 5 * Also contains all global variables.
nickjillings@1682 6 */
nickjillings@1682 7
nickjillings@1682 8 /* create the web audio API context and store in audioContext*/
nickjillings@1682 9 var audioContext;
nickjillings@1683 10 var projectXML;
nickjillings@1682 11 var audioEngineContext;
nickjillings@1688 12 var projectReturn;
nickjillings@1703 13 var preTestQuestions = document.createElement('PreTest');
nickjillings@1703 14 var postTestQuestions = document.createElement('PostTest');
nickjillings@1682 15
nickjillings@1682 16 window.onload = function() {
nickjillings@1682 17 // Function called once the browser has loaded all files.
nickjillings@1682 18 // This should perform any initial commands such as structure / loading documents
nickjillings@1682 19
nickjillings@1682 20 // Create a web audio API context
nickjillings@1701 21 // Fixed for cross-browser support
nickjillings@1701 22 var AudioContext = window.AudioContext || window.webkitAudioContext;
nickjillings@1688 23 audioContext = new AudioContext;
nickjillings@1682 24
nickjillings@1682 25 // Create the audio engine object
nickjillings@1682 26 audioEngineContext = new AudioEngine();
nickjillings@1697 27 };
nickjillings@1682 28
nickjillings@1682 29 function loadProjectSpec(url) {
nickjillings@1682 30 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data
nickjillings@1682 31 // If url is null, request client to upload project XML document
nickjillings@1683 32 var r = new XMLHttpRequest();
nickjillings@1683 33 r.open('GET',url,true);
nickjillings@1683 34 r.onload = function() {
nickjillings@1683 35 loadProjectSpecCallback(r.response);
nickjillings@1697 36 };
nickjillings@1683 37 r.send();
nickjillings@1697 38 };
nickjillings@1683 39
nickjillings@1683 40 function loadProjectSpecCallback(response) {
nickjillings@1683 41 // Function called after asynchronous download of XML project specification
nickjillings@1683 42 var decode = $.parseXML(response);
nickjillings@1683 43 projectXML = $(decode);
nickjillings@1683 44
nickjillings@1683 45 // Now extract the setup tag
nickjillings@1683 46 var xmlSetup = projectXML.find('setup');
nickjillings@1697 47 // Detect the interface to use and load the relevant javascripts.
nickjillings@1683 48 var interfaceType = xmlSetup[0].attributes['interface'];
nickjillings@1683 49 var interfaceJS = document.createElement('script');
nickjillings@1683 50 interfaceJS.setAttribute("type","text/javascript");
nickjillings@1683 51 if (interfaceType.value == 'APE') {
nickjillings@1683 52 interfaceJS.setAttribute("src","ape.js");
nickjillings@1683 53 }
nickjillings@1683 54 document.getElementsByTagName("head")[0].appendChild(interfaceJS);
nickjillings@1682 55 }
nickjillings@1682 56
nickjillings@1682 57 function createProjectSave(destURL) {
nickjillings@1682 58 // Save the data from interface into XML and send to destURL
nickjillings@1682 59 // If destURL is null then download XML in client
nickjillings@1688 60 // Now time to render file locally
nickjillings@1688 61 var xmlDoc = interfaceXMLSave();
nickjillings@1688 62 if (destURL == "null" || destURL == undefined) {
nickjillings@1688 63 var parent = document.createElement("div");
nickjillings@1688 64 parent.appendChild(xmlDoc);
nickjillings@1688 65 var file = [parent.innerHTML];
nickjillings@1688 66 var bb = new Blob(file,{type : 'application/xml'});
nickjillings@1688 67 var dnlk = window.URL.createObjectURL(bb);
nickjillings@1688 68 var a = document.createElement("a");
nickjillings@1688 69 a.hidden = '';
nickjillings@1688 70 a.href = dnlk;
nickjillings@1688 71 a.download = "save.xml";
nickjillings@1688 72 a.textContent = "Save File";
nickjillings@1688 73
nickjillings@1688 74 var submitDiv = document.getElementById('download-point');
nickjillings@1688 75 submitDiv.appendChild(a);
nickjillings@1688 76 }
nickjillings@1682 77 }
nickjillings@1682 78
nickjillings@1682 79 function AudioEngine() {
nickjillings@1682 80
nickjillings@1682 81 // Create two output paths, the main outputGain and fooGain.
nickjillings@1682 82 // Output gain is default to 1 and any items for playback route here
nickjillings@1682 83 // Foo gain is used for analysis to ensure paths get processed, but are not heard
nickjillings@1682 84 // because web audio will optimise and any route which does not go to the destination gets ignored.
nickjillings@1682 85 this.outputGain = audioContext.createGain();
nickjillings@1682 86 this.fooGain = audioContext.createGain();
nickjillings@1682 87 this.fooGain.gain = 0;
nickjillings@1682 88
nickjillings@1688 89 // Use this to detect playback state: 0 - stopped, 1 - playing
nickjillings@1688 90 this.status = 0;
nickjillings@1688 91
nickjillings@1682 92 // Connect both gains to output
nickjillings@1682 93 this.outputGain.connect(audioContext.destination);
nickjillings@1682 94 this.fooGain.connect(audioContext.destination);
nickjillings@1682 95
nickjillings@1682 96 // Create store for new audioObjects
nickjillings@1682 97 this.audioObjects = [];
nickjillings@1682 98
nickjillings@1682 99 this.play = function() {
nickjillings@1682 100 // Send play command to all playback buffers for synchronised start
nickjillings@1682 101 // Also start timer callbacks to detect if playback has finished
nickjillings@1688 102 if (this.status == 0) {
nickjillings@1688 103 // First get current clock
nickjillings@1688 104 var timer = audioContext.currentTime;
nickjillings@1688 105 // Add 3 seconds
nickjillings@1688 106 timer += 3.0;
nickjillings@1688 107
nickjillings@1688 108 // Send play to all tracks
nickjillings@1688 109 for (var i=0; i<this.audioObjects.length; i++)
nickjillings@1688 110 {
nickjillings@1688 111 this.audioObjects[i].play(timer);
nickjillings@1688 112 }
nickjillings@1688 113 this.status = 1;
nickjillings@1688 114 }
nickjillings@1697 115 };
nickjillings@1682 116
nickjillings@1682 117 this.stop = function() {
nickjillings@1682 118 // Send stop and reset command to all playback buffers
nickjillings@1688 119 if (this.status == 1) {
nickjillings@1688 120 for (var i=0; i<this.audioObjects.length; i++)
nickjillings@1688 121 {
nickjillings@1688 122 this.audioObjects[i].stop();
nickjillings@1688 123 }
nickjillings@1688 124 this.status = 0;
nickjillings@1688 125 }
nickjillings@1697 126 };
nickjillings@1682 127
nickjillings@1689 128 this.selectedTrack = function(id) {
nickjillings@1689 129 for (var i=0; i<this.audioObjects.length; i++)
nickjillings@1689 130 {
nickjillings@1689 131 if (id == i) {
nickjillings@1689 132 this.audioObjects[i].outputGain.gain.value = 1.0;
nickjillings@1689 133 } else {
nickjillings@1689 134 this.audioObjects[i].outputGain.gain.value = 0.0;
nickjillings@1689 135 }
nickjillings@1689 136 }
nickjillings@1697 137 };
nickjillings@1689 138
nickjillings@1689 139
nickjillings@1682 140 this.newTrack = function(url) {
nickjillings@1682 141 // Pull data from given URL into new audio buffer
nickjillings@1682 142 // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin'
nickjillings@1688 143
nickjillings@1682 144 // Create the audioObject with ID of the new track length;
nickjillings@1682 145 audioObjectId = this.audioObjects.length
nickjillings@1682 146 this.audioObjects[audioObjectId] = new audioObject(audioObjectId);
nickjillings@1688 147
nickjillings@1688 148 // AudioObject will get track itself.
nickjillings@1688 149 this.audioObjects[audioObjectId].constructTrack(url);
nickjillings@1697 150 };
nickjillings@1682 151
nickjillings@1682 152 }
nickjillings@1682 153
nickjillings@1682 154 function audioObject(id) {
nickjillings@1682 155 // The main buffer object with common control nodes to the AudioEngine
nickjillings@1682 156
nickjillings@1682 157 this.id = id;
nickjillings@1682 158 this.state = 0; // 0 - no data, 1 - ready
nickjillings@1704 159 this.url = null; // Hold the URL given for the output back to the results.
nickjillings@1682 160
nickjillings@1682 161 // Create a buffer and external gain control to allow internal patching of effects and volume leveling.
nickjillings@1682 162 this.bufferNode = audioContext.createBufferSource();
nickjillings@1682 163 this.outputGain = audioContext.createGain();
nickjillings@1682 164
nickjillings@1689 165 // Default output gain to be zero
nickjillings@1689 166 this.outputGain.gain.value = 0.0;
nickjillings@1689 167
nickjillings@1682 168 // Connect buffer to the audio graph
nickjillings@1682 169 this.bufferNode.connect(this.outputGain);
nickjillings@1682 170 this.outputGain.connect(audioEngineContext.outputGain);
nickjillings@1682 171
nickjillings@1682 172 // the audiobuffer is not designed for multi-start playback
nickjillings@1682 173 // When stopeed, the buffer node is deleted and recreated with the stored buffer.
nickjillings@1682 174 this.buffer;
nickjillings@1682 175
nickjillings@1682 176 this.play = function(startTime) {
nickjillings@1682 177 this.bufferNode.start(startTime);
nickjillings@1697 178 };
nickjillings@1682 179
nickjillings@1682 180 this.stop = function() {
nickjillings@1682 181 this.bufferNode.stop(0);
nickjillings@1682 182 this.bufferNode = audioContext.createBufferSource();
nickjillings@1682 183 this.bufferNode.connect(this.outputGain);
nickjillings@1682 184 this.bufferNode.buffer = this.buffer;
nickjillings@1688 185 this.bufferNode.loop = true;
nickjillings@1697 186 };
nickjillings@1689 187
nickjillings@1688 188 this.constructTrack = function(url) {
nickjillings@1688 189 var request = new XMLHttpRequest();
nickjillings@1704 190 this.url = url;
nickjillings@1688 191 request.open('GET',url,true);
nickjillings@1688 192 request.responseType = 'arraybuffer';
nickjillings@1688 193
nickjillings@1688 194 var audioObj = this;
nickjillings@1688 195
nickjillings@1688 196 // Create callback to decode the data asynchronously
nickjillings@1688 197 request.onloadend = function() {
nickjillings@1688 198 audioContext.decodeAudioData(request.response, function(decodedData) {
nickjillings@1688 199 audioObj.buffer = decodedData;
nickjillings@1688 200 audioObj.bufferNode.buffer = audioObj.buffer;
nickjillings@1688 201 audioObj.bufferNode.loop = true;
nickjillings@1688 202 audioObj.state = 1;
nickjillings@1688 203 }, function(){
nickjillings@1688 204 // Should only be called if there was an error, but sometimes gets called continuously
nickjillings@1688 205 // Check here if the error is genuine
nickjillings@1688 206 if (audioObj.state == 0 || audioObj.buffer == undefined) {
nickjillings@1688 207 // Genuine error
nickjillings@1688 208 console.log('FATAL - Error loading buffer on '+audioObj.id);
nickjillings@1688 209 }
nickjillings@1688 210 });
nickjillings@1697 211 };
nickjillings@1688 212 request.send();
nickjillings@1697 213 };
nickjillings@1688 214
nickjillings@1688 215 }