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