Mercurial > hg > webaudioevaluationtool
comparison core.js @ 771:0796d28701ae
Start tidy up of core.js
author | Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk> |
---|---|
date | Mon, 07 Dec 2015 12:15:43 +0000 |
parents | d2a83474a967 |
children | d07bc42a716c |
comparison
equal
deleted
inserted
replaced
770:d2a83474a967 | 771:0796d28701ae |
---|---|
30 audioContext = new AudioContext; | 30 audioContext = new AudioContext; |
31 | 31 |
32 // Create test state | 32 // Create test state |
33 testState = new stateMachine(); | 33 testState = new stateMachine(); |
34 | 34 |
35 // Create the audio engine object | |
36 audioEngineContext = new AudioEngine(); | |
37 | |
38 // Create the popup interface object | 35 // Create the popup interface object |
39 popup = new interfacePopup(); | 36 popup = new interfacePopup(); |
40 | 37 |
41 // Create the specification object | 38 // Create the specification object |
42 specification = new Specification(); | 39 specification = new Specification(); |
43 | 40 |
44 // Create the interface object | 41 // Create the interface object |
45 interfaceContext = new Interface(specification); | 42 interfaceContext = new Interface(specification); |
46 }; | 43 }; |
44 | |
45 function loadProjectSpec(url) { | |
46 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data | |
47 // If url is null, request client to upload project XML document | |
48 var r = new XMLHttpRequest(); | |
49 r.open('GET',url,true); | |
50 r.onload = function() { | |
51 loadProjectSpecCallback(r.response); | |
52 }; | |
53 r.send(); | |
54 }; | |
55 | |
56 function loadProjectSpecCallback(response) { | |
57 // Function called after asynchronous download of XML project specification | |
58 //var decode = $.parseXML(response); | |
59 //projectXML = $(decode); | |
60 | |
61 var parse = new DOMParser(); | |
62 projectXML = parse.parseFromString(response,'text/xml'); | |
63 | |
64 // Build the specification | |
65 specification.decode(projectXML); | |
66 | |
67 // Create the audio engine object | |
68 audioEngineContext = new AudioEngine(specification); | |
69 | |
70 testState.stateMap.push(specification.preTest); | |
71 | |
72 $(specification.audioHolders).each(function(index,elem){ | |
73 testState.stateMap.push(elem); | |
74 }); | |
75 | |
76 testState.stateMap.push(specification.postTest); | |
77 | |
78 | |
79 | |
80 // Detect the interface to use and load the relevant javascripts. | |
81 var interfaceJS = document.createElement('script'); | |
82 interfaceJS.setAttribute("type","text/javascript"); | |
83 if (specification.interfaceType == 'APE') { | |
84 interfaceJS.setAttribute("src","ape.js"); | |
85 | |
86 // APE comes with a css file | |
87 var css = document.createElement('link'); | |
88 css.rel = 'stylesheet'; | |
89 css.type = 'text/css'; | |
90 css.href = 'ape.css'; | |
91 | |
92 document.getElementsByTagName("head")[0].appendChild(css); | |
93 } else if (specification.interfaceType == "MUSHRA") | |
94 { | |
95 interfaceJS.setAttribute("src","mushra.js"); | |
96 | |
97 // MUSHRA comes with a css file | |
98 var css = document.createElement('link'); | |
99 css.rel = 'stylesheet'; | |
100 css.type = 'text/css'; | |
101 css.href = 'mushra.css'; | |
102 | |
103 document.getElementsByTagName("head")[0].appendChild(css); | |
104 } | |
105 document.getElementsByTagName("head")[0].appendChild(interfaceJS); | |
106 | |
107 // Define window callbacks for interface | |
108 window.onresize = function(event){interfaceContext.resizeWindow(event);}; | |
109 } | |
110 | |
111 function createProjectSave(destURL) { | |
112 // Save the data from interface into XML and send to destURL | |
113 // If destURL is null then download XML in client | |
114 // Now time to render file locally | |
115 var xmlDoc = interfaceXMLSave(); | |
116 var parent = document.createElement("div"); | |
117 parent.appendChild(xmlDoc); | |
118 var file = [parent.innerHTML]; | |
119 if (destURL == "null" || destURL == undefined) { | |
120 var bb = new Blob(file,{type : 'application/xml'}); | |
121 var dnlk = window.URL.createObjectURL(bb); | |
122 var a = document.createElement("a"); | |
123 a.hidden = ''; | |
124 a.href = dnlk; | |
125 a.download = "save.xml"; | |
126 a.textContent = "Save File"; | |
127 | |
128 popup.showPopup(); | |
129 popup.popupContent.innerHTML = null; | |
130 popup.popupContent.appendChild(a); | |
131 } else { | |
132 var xmlhttp = new XMLHttpRequest; | |
133 xmlhttp.open("POST",destURL,true); | |
134 xmlhttp.setRequestHeader('Content-Type', 'text/xml'); | |
135 xmlhttp.onerror = function(){ | |
136 console.log('Error saving file to server! Presenting download locally'); | |
137 createProjectSave(null); | |
138 }; | |
139 xmlhttp.onreadystatechange = function() { | |
140 console.log(xmlhttp.status); | |
141 if (xmlhttp.status != 200 && xmlhttp.readyState == 4) { | |
142 createProjectSave(null); | |
143 } else { | |
144 if (xmlhttp.responseXML == null) | |
145 { | |
146 return createProjectSave(null); | |
147 } | |
148 var response = xmlhttp.responseXML.childNodes[0]; | |
149 if (response.getAttribute('state') == "OK") | |
150 { | |
151 var file = response.getElementsByTagName('file')[0]; | |
152 console.log('Save OK: Filename '+file.textContent+','+file.getAttribute('bytes')+'B'); | |
153 popup.showPopup(); | |
154 popup.popupContent.innerHTML = null; | |
155 popup.popupContent.textContent = "Thank you!"; | |
156 } else { | |
157 var message = response.getElementsByTagName('message')[0]; | |
158 errorSessionDump(message.textContent); | |
159 } | |
160 } | |
161 }; | |
162 xmlhttp.send(file); | |
163 } | |
164 } | |
165 | |
166 function errorSessionDump(msg){ | |
167 // Create the partial interface XML save | |
168 // Include error node with message on why the dump occured | |
169 var xmlDoc = interfaceXMLSave(); | |
170 var err = document.createElement('error'); | |
171 err.textContent = msg; | |
172 xmlDoc.appendChild(err); | |
173 var parent = document.createElement("div"); | |
174 parent.appendChild(xmlDoc); | |
175 var file = [parent.innerHTML]; | |
176 var bb = new Blob(file,{type : 'application/xml'}); | |
177 var dnlk = window.URL.createObjectURL(bb); | |
178 var a = document.createElement("a"); | |
179 a.hidden = ''; | |
180 a.href = dnlk; | |
181 a.download = "save.xml"; | |
182 a.textContent = "Save File"; | |
183 | |
184 popup.showPopup(); | |
185 popup.popupContent.innerHTML = "ERROR : "+msg; | |
186 popup.popupContent.appendChild(a); | |
187 } | |
188 | |
189 // Only other global function which must be defined in the interface class. Determines how to create the XML document. | |
190 function interfaceXMLSave(){ | |
191 // Create the XML string to be exported with results | |
192 var xmlDoc = document.createElement("BrowserEvaluationResult"); | |
193 var projectDocument = specification.projectXML; | |
194 projectDocument.setAttribute('file-name',url); | |
195 xmlDoc.appendChild(projectDocument); | |
196 xmlDoc.appendChild(returnDateNode()); | |
197 xmlDoc.appendChild(interfaceContext.returnNavigator()); | |
198 for (var i=0; i<testState.stateResults.length; i++) | |
199 { | |
200 xmlDoc.appendChild(testState.stateResults[i]); | |
201 } | |
202 | |
203 return xmlDoc; | |
204 } | |
47 | 205 |
48 function interfacePopup() { | 206 function interfacePopup() { |
49 // Creates an object to manage the popup | 207 // Creates an object to manage the popup |
50 this.popup = null; | 208 this.popup = null; |
51 this.popupContent = null; | 209 this.popupContent = null; |
516 }; | 674 }; |
517 | 675 |
518 this.previousState = function(){}; | 676 this.previousState = function(){}; |
519 } | 677 } |
520 | 678 |
521 function testEnded(testId) | 679 function AudioEngine(specification) { |
522 { | |
523 pageXMLSave(testId); | |
524 if (testXMLSetups.length-1 > testId) | |
525 { | |
526 // Yes we have another test to perform | |
527 testId = (Number(testId)+1); | |
528 currentState = 'testRun-'+testId; | |
529 loadTest(testId); | |
530 } else { | |
531 console.log('Testing Completed!'); | |
532 currentState = 'postTest'; | |
533 // Check for any post tests | |
534 var xmlSetup = projectXML.find('setup'); | |
535 var postTest = xmlSetup.find('PostTest')[0]; | |
536 popup.initState(postTest); | |
537 } | |
538 } | |
539 | |
540 function loadProjectSpec(url) { | |
541 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data | |
542 // If url is null, request client to upload project XML document | |
543 var r = new XMLHttpRequest(); | |
544 r.open('GET',url,true); | |
545 r.onload = function() { | |
546 loadProjectSpecCallback(r.response); | |
547 }; | |
548 r.send(); | |
549 }; | |
550 | |
551 function loadProjectSpecCallback(response) { | |
552 // Function called after asynchronous download of XML project specification | |
553 //var decode = $.parseXML(response); | |
554 //projectXML = $(decode); | |
555 | |
556 var parse = new DOMParser(); | |
557 projectXML = parse.parseFromString(response,'text/xml'); | |
558 | |
559 // Build the specification | |
560 specification.decode(projectXML); | |
561 | |
562 testState.stateMap.push(specification.preTest); | |
563 | |
564 $(specification.audioHolders).each(function(index,elem){ | |
565 testState.stateMap.push(elem); | |
566 }); | |
567 | |
568 testState.stateMap.push(specification.postTest); | |
569 | |
570 // Obtain the metrics enabled | |
571 $(specification.metrics).each(function(index,node){ | |
572 var enabled = node.textContent; | |
573 switch(node.enabled) | |
574 { | |
575 case 'testTimer': | |
576 sessionMetrics.prototype.enableTestTimer = true; | |
577 break; | |
578 case 'elementTimer': | |
579 sessionMetrics.prototype.enableElementTimer = true; | |
580 break; | |
581 case 'elementTracker': | |
582 sessionMetrics.prototype.enableElementTracker = true; | |
583 break; | |
584 case 'elementListenTracker': | |
585 sessionMetrics.prototype.enableElementListenTracker = true; | |
586 break; | |
587 case 'elementInitialPosition': | |
588 sessionMetrics.prototype.enableElementInitialPosition = true; | |
589 break; | |
590 case 'elementFlagListenedTo': | |
591 sessionMetrics.prototype.enableFlagListenedTo = true; | |
592 break; | |
593 case 'elementFlagMoved': | |
594 sessionMetrics.prototype.enableFlagMoved = true; | |
595 break; | |
596 case 'elementFlagComments': | |
597 sessionMetrics.prototype.enableFlagComments = true; | |
598 break; | |
599 } | |
600 }); | |
601 | |
602 | |
603 | |
604 // Detect the interface to use and load the relevant javascripts. | |
605 var interfaceJS = document.createElement('script'); | |
606 interfaceJS.setAttribute("type","text/javascript"); | |
607 if (specification.interfaceType == 'APE') { | |
608 interfaceJS.setAttribute("src","ape.js"); | |
609 | |
610 // APE comes with a css file | |
611 var css = document.createElement('link'); | |
612 css.rel = 'stylesheet'; | |
613 css.type = 'text/css'; | |
614 css.href = 'ape.css'; | |
615 | |
616 document.getElementsByTagName("head")[0].appendChild(css); | |
617 } else if (specification.interfaceType == "MUSHRA") | |
618 { | |
619 interfaceJS.setAttribute("src","mushra.js"); | |
620 | |
621 // MUSHRA comes with a css file | |
622 var css = document.createElement('link'); | |
623 css.rel = 'stylesheet'; | |
624 css.type = 'text/css'; | |
625 css.href = 'mushra.css'; | |
626 | |
627 document.getElementsByTagName("head")[0].appendChild(css); | |
628 } | |
629 document.getElementsByTagName("head")[0].appendChild(interfaceJS); | |
630 | |
631 // Define window callbacks for interface | |
632 window.onresize = function(event){interfaceContext.resizeWindow(event);}; | |
633 } | |
634 | |
635 function createProjectSave(destURL) { | |
636 // Save the data from interface into XML and send to destURL | |
637 // If destURL is null then download XML in client | |
638 // Now time to render file locally | |
639 var xmlDoc = interfaceXMLSave(); | |
640 var parent = document.createElement("div"); | |
641 parent.appendChild(xmlDoc); | |
642 var file = [parent.innerHTML]; | |
643 if (destURL == "null" || destURL == undefined) { | |
644 var bb = new Blob(file,{type : 'application/xml'}); | |
645 var dnlk = window.URL.createObjectURL(bb); | |
646 var a = document.createElement("a"); | |
647 a.hidden = ''; | |
648 a.href = dnlk; | |
649 a.download = "save.xml"; | |
650 a.textContent = "Save File"; | |
651 | |
652 popup.showPopup(); | |
653 popup.popupContent.innerHTML = null; | |
654 popup.popupContent.appendChild(a); | |
655 } else { | |
656 var xmlhttp = new XMLHttpRequest; | |
657 xmlhttp.open("POST",destURL,true); | |
658 xmlhttp.setRequestHeader('Content-Type', 'text/xml'); | |
659 xmlhttp.onerror = function(){ | |
660 console.log('Error saving file to server! Presenting download locally'); | |
661 createProjectSave(null); | |
662 }; | |
663 xmlhttp.onreadystatechange = function() { | |
664 console.log(xmlhttp.status); | |
665 if (xmlhttp.status != 200 && xmlhttp.readyState == 4) { | |
666 createProjectSave(null); | |
667 } else { | |
668 if (xmlhttp.responseXML == null) | |
669 { | |
670 return createProjectSave(null); | |
671 } | |
672 var response = xmlhttp.responseXML.childNodes[0]; | |
673 if (response.getAttribute('state') == "OK") | |
674 { | |
675 var file = response.getElementsByTagName('file')[0]; | |
676 console.log('Save OK: Filename '+file.textContent+','+file.getAttribute('bytes')+'B'); | |
677 popup.showPopup(); | |
678 popup.popupContent.innerHTML = null; | |
679 popup.popupContent.textContent = "Thank you!"; | |
680 } else { | |
681 var message = response.getElementsByTagName('message')[0]; | |
682 errorSessionDump(message.textContent); | |
683 } | |
684 } | |
685 }; | |
686 xmlhttp.send(file); | |
687 } | |
688 } | |
689 | |
690 function errorSessionDump(msg){ | |
691 // Create the partial interface XML save | |
692 // Include error node with message on why the dump occured | |
693 var xmlDoc = interfaceXMLSave(); | |
694 var err = document.createElement('error'); | |
695 err.textContent = msg; | |
696 xmlDoc.appendChild(err); | |
697 var parent = document.createElement("div"); | |
698 parent.appendChild(xmlDoc); | |
699 var file = [parent.innerHTML]; | |
700 var bb = new Blob(file,{type : 'application/xml'}); | |
701 var dnlk = window.URL.createObjectURL(bb); | |
702 var a = document.createElement("a"); | |
703 a.hidden = ''; | |
704 a.href = dnlk; | |
705 a.download = "save.xml"; | |
706 a.textContent = "Save File"; | |
707 | |
708 popup.showPopup(); | |
709 popup.popupContent.innerHTML = "ERROR : "+msg; | |
710 popup.popupContent.appendChild(a); | |
711 } | |
712 | |
713 // Only other global function which must be defined in the interface class. Determines how to create the XML document. | |
714 function interfaceXMLSave(){ | |
715 // Create the XML string to be exported with results | |
716 var xmlDoc = document.createElement("BrowserEvaluationResult"); | |
717 var projectDocument = specification.projectXML; | |
718 projectDocument.setAttribute('file-name',url); | |
719 xmlDoc.appendChild(projectDocument); | |
720 xmlDoc.appendChild(returnDateNode()); | |
721 xmlDoc.appendChild(interfaceContext.returnNavigator()); | |
722 for (var i=0; i<testState.stateResults.length; i++) | |
723 { | |
724 xmlDoc.appendChild(testState.stateResults[i]); | |
725 } | |
726 | |
727 return xmlDoc; | |
728 } | |
729 | |
730 function AudioEngine() { | |
731 | 680 |
732 // Create two output paths, the main outputGain and fooGain. | 681 // Create two output paths, the main outputGain and fooGain. |
733 // Output gain is default to 1 and any items for playback route here | 682 // Output gain is default to 1 and any items for playback route here |
734 // Foo gain is used for analysis to ensure paths get processed, but are not heard | 683 // Foo gain is used for analysis to ensure paths get processed, but are not heard |
735 // because web audio will optimise and any route which does not go to the destination gets ignored. | 684 // because web audio will optimise and any route which does not go to the destination gets ignored. |
745 this.fooGain.connect(audioContext.destination); | 694 this.fooGain.connect(audioContext.destination); |
746 | 695 |
747 // Create the timer Object | 696 // Create the timer Object |
748 this.timer = new timer(); | 697 this.timer = new timer(); |
749 // Create session metrics | 698 // Create session metrics |
750 this.metric = new sessionMetrics(this); | 699 this.metric = new sessionMetrics(this,specification); |
751 | 700 |
752 this.loopPlayback = false; | 701 this.loopPlayback = false; |
753 | 702 |
754 // Create store for new audioObjects | 703 // Create store for new audioObjects |
755 this.audioObjects = []; | 704 this.audioObjects = []; |
1082 this.updateTestTime(); | 1031 this.updateTestTime(); |
1083 return this.testDuration; | 1032 return this.testDuration; |
1084 }; | 1033 }; |
1085 } | 1034 } |
1086 | 1035 |
1087 function sessionMetrics(engine) | 1036 function sessionMetrics(engine,specification) |
1088 { | 1037 { |
1089 /* Used by audioEngine to link to audioObjects to minimise the timer call timers; | 1038 /* Used by audioEngine to link to audioObjects to minimise the timer call timers; |
1090 */ | 1039 */ |
1091 this.engine = engine; | 1040 this.engine = engine; |
1092 this.lastClicked = -1; | 1041 this.lastClicked = -1; |
1093 this.data = -1; | 1042 this.data = -1; |
1094 this.reset = function() { | 1043 this.reset = function() { |
1095 this.lastClicked = -1; | 1044 this.lastClicked = -1; |
1096 this.data = -1; | 1045 this.data = -1; |
1097 }; | 1046 }; |
1047 | |
1048 this.enableElementInitialPosition = false; | |
1049 this.enableElementListenTracker = false; | |
1050 this.enableElementTimer = false; | |
1051 this.enableElementTracker = false; | |
1052 this.enableFlagListenedTo = false; | |
1053 this.enableFlagMoved = false; | |
1054 this.enableTestTimer = false; | |
1055 // Obtain the metrics enabled | |
1056 for (var i=0; i<specification.metrics.length; i++) | |
1057 { | |
1058 var node = specification.metrics[i]; | |
1059 switch(node.enabled) | |
1060 { | |
1061 case 'testTimer': | |
1062 this.enableTestTimer = true; | |
1063 break; | |
1064 case 'elementTimer': | |
1065 this.enableElementTimer = true; | |
1066 break; | |
1067 case 'elementTracker': | |
1068 this.enableElementTracker = true; | |
1069 break; | |
1070 case 'elementListenTracker': | |
1071 this.enableElementListenTracker = true; | |
1072 break; | |
1073 case 'elementInitialPosition': | |
1074 this.enableElementInitialPosition = true; | |
1075 break; | |
1076 case 'elementFlagListenedTo': | |
1077 this.enableFlagListenedTo = true; | |
1078 break; | |
1079 case 'elementFlagMoved': | |
1080 this.enableFlagMoved = true; | |
1081 break; | |
1082 case 'elementFlagComments': | |
1083 this.enableFlagComments = true; | |
1084 break; | |
1085 } | |
1086 } | |
1098 this.initialiseTest = function(){}; | 1087 this.initialiseTest = function(){}; |
1099 } | 1088 } |
1100 | 1089 |
1101 function metricTracker(caller) | 1090 function metricTracker(caller) |
1102 { | 1091 { |
1302 time.setAttributeNode(minute); | 1291 time.setAttributeNode(minute); |
1303 time.setAttributeNode(secs); | 1292 time.setAttributeNode(secs); |
1304 | 1293 |
1305 hold.appendChild(date); | 1294 hold.appendChild(date); |
1306 hold.appendChild(time); | 1295 hold.appendChild(time); |
1307 return hold | 1296 return hold; |
1308 | 1297 |
1309 } | 1298 } |
1310 | 1299 |
1311 function Specification() { | 1300 function Specification() { |
1312 // Handles the decoding of the project specification XML into a simple JavaScript Object. | 1301 // Handles the decoding of the project specification XML into a simple JavaScript Object. |