annotate core.js @ 44:c57aba852764 Dev_main

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