Mercurial > hg > webaudioevaluationtool
changeset 2467:221688a8be4f
Merge branch 'master' into Dev_main
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Tue, 02 Aug 2016 12:26:19 +0100 |
parents | 496fde335890 (diff) d26623bd65e0 (current diff) |
children | 8273da734d07 |
files | js/core.js |
diffstat | 5 files changed, 240 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/interfaces/ape.js Tue Aug 02 11:22:51 2016 +0100 +++ b/interfaces/ape.js Tue Aug 02 12:26:19 2016 +0100 @@ -395,7 +395,11 @@ event.preventDefault(); var obj = interfaceContext.getSelectedObject(); if (obj == null) {return;} - $(obj).css("left",event.clientX-6 + "px"); + var move = event.clientX-6; + var w = $(event.currentTarget).width(); + move = Math.max(50,move); + move = Math.min(w+50,move); + $(obj).css("left",move + "px"); interfaceContext.moveObject(); }); @@ -404,6 +408,9 @@ var obj = interfaceContext.getSelectedObject(); if (obj == null) {return;} var move = event.originalEvent.targetTouches[0].clientX - 6; + var w = $(event.currentTarget).width(); + move = Math.max(50,move); + move = Math.min(w+50,move); $(obj).css("left",move + "px"); interfaceContext.moveObject(); });
--- a/js/core.js Tue Aug 02 11:22:51 2016 +0100 +++ b/js/core.js Tue Aug 02 12:26:19 2016 +0100 @@ -859,6 +859,39 @@ console.log("Question Response: "+ textArea.value); node.response = textArea.value; } + // Perform the conditional + for (var condition of node.specification.conditions) { + var pass = false; + switch(condition.check) { + case "equals": + if (textArea.value == condition.value) { + pass = true; + } + break; + case "greaterThan": + case "lessThan": + console.log("Survey Element of type 'question' cannot interpret greaterThan/lessThan conditions. IGNORING"); + break; + case "contains": + if (textArea.value.includes(condition.value)) { + pass = true; + } + break; + } + var jumpID; + if (pass) { + jumpID = condition.jumpToOnPass; + } else { + jumpID = condition.jumpToOnFail; + } + if (jumpID != undefined) { + var index = this.popupOptions.findIndex(function(item,index,element){ + if (item.specification.id == jumpID) {return true;} else {return false;} + },this); + this.currentIndex = index-1; + break; + } + } } else if (node.specification.type == 'checkbox') { // Must extract checkbox data console.log("Checkbox: "+ node.specification.statement); @@ -872,6 +905,38 @@ }); console.log(node.specification.options[i].name+": "+ inputs[i].checked); } + // Perform the conditional + for (var condition of node.specification.conditions) { + var pass = false; + switch(condition.check) { + case "equals": + case "greaterThan": + case "lessThan": + console.log("Survey Element of type 'checkbox' cannot interpret equals/greaterThan/lessThan conditions. IGNORING"); + break; + case "contains": + for (var response of node.response) { + if (response.name == condition.value && response.checked) { + pass = true; + break; + } + } + break; + } + var jumpID; + if (pass) { + jumpID = condition.jumpToOnPass; + } else { + jumpID = condition.jumpToOnFail; + } + if (jumpID != undefined) { + var index = this.popupOptions.findIndex(function(item,index,element){ + if (item.specification.id == jumpID) {return true;} else {return false;} + },this); + this.currentIndex = index-1; + break; + } + } } else if (node.specification.type == "radio") { var optHold = this.popupResponse; console.log("Radio: "+ node.specification.statement); @@ -894,6 +959,35 @@ } i++; } + // Perform the conditional + for (var condition of node.specification.conditions) { + var pass = false; + switch(condition.check) { + case "contains": + case "greaterThan": + case "lessThan": + console.log("Survey Element of type 'radio' cannot interpret contains/greaterThan/lessThan conditions. IGNORING"); + break; + case "equals": + if (node.response == condition.value) { + pass = true; + } + break; + } + var jumpID; + if (pass) { + jumpID = condition.jumpToOnPass; + } else { + jumpID = condition.jumpToOnFail; + } + if (jumpID != undefined) { + var index = this.popupOptions.findIndex(function(item,index,element){ + if (item.specification.id == jumpID) {return true;} else {return false;} + },this); + this.currentIndex = index-1; + break; + } + } } else if (node.specification.type == "number") { var input = this.popupContent.getElementsByTagName('input')[0]; if (node.mandatory == true && input.value.length == 0) { @@ -914,6 +1008,43 @@ return; } node.response = input.value; + // Perform the conditional + for (var condition of node.specification.conditions) { + var pass = false; + switch(condition.check) { + case "contains": + console.log("Survey Element of type 'number' cannot interpret contains conditions. IGNORING"); + break; + case "greaterThan": + if (node.response > Number(condition.value)) { + pass = true; + } + break; + case "lessThan": + if (node.response < Number(condition.value)) { + pass = true; + } + break; + case "equals": + if (node.response == condition.value) { + pass = true; + } + break; + } + var jumpID; + if (pass) { + jumpID = condition.jumpToOnPass; + } else { + jumpID = condition.jumpToOnFail; + } + if (jumpID != undefined) { + var index = this.popupOptions.findIndex(function(item,index,element){ + if (item.specification.id == jumpID) {return true;} else {return false;} + },this); + this.currentIndex = index-1; + break; + } + } } this.currentIndex++; if (this.currentIndex < this.popupOptions.length) { @@ -1355,29 +1486,48 @@ // Copies the entire bufferObj. if (preSilenceTime == undefined) {preSilenceTime = 0;} if (postSilenceTime == undefined) {postSilenceTime = 0;} - var copy = new this.constructor(); - copy.url = this.url; var preSilenceSamples = secondsToSamples(preSilenceTime,this.buffer.sampleRate); var postSilenceSamples = secondsToSamples(postSilenceTime,this.buffer.sampleRate); var newLength = this.buffer.length+preSilenceSamples+postSilenceSamples; - copy.buffer = audioContext.createBuffer(this.buffer.numberOfChannels, newLength, this.buffer.sampleRate); + var copybuffer = audioContext.createBuffer(this.buffer.numberOfChannels, newLength, this.buffer.sampleRate); // Now we can use some efficient background copy schemes if we are just padding the end - if (preSilenceSamples == 0 && typeof copy.buffer.copyToChannel == "function") { + if (preSilenceSamples == 0 && typeof copybuffer.copyToChannel == "function") { for (var c=0; c<this.buffer.numberOfChannels; c++) { - copy.buffer.copyToChannel(this.buffer.getChannelData(c),c); + copybuffer.copyToChannel(this.buffer.getChannelData(c),c); } } else { for (var c=0; c<this.buffer.numberOfChannels; c++) { var src = this.buffer.getChannelData(c); - var dst = copy.buffer.getChannelData(c); + var dst = copybuffer.getChannelData(c); for (var n=0; n<src.length; n++) dst[n+preSilenceSamples] = src[n]; } } // Copy in the rest of the buffer information - copy.buffer.lufs = this.buffer.lufs; - copy.buffer.playbackGain = this.buffer.playbackGain; - return copy; + copybuffer.lufs = this.buffer.lufs; + copybuffer.playbackGain = this.buffer.playbackGain; + return copybuffer; + } + + this.cropBuffer = function(startTime, stopTime) { + // Copy and return the cropped buffer + var start_sample = Math.floor(startTime*this.buffer.sampleRate); + var stop_sample = Math.floor(stopTime*this.buffer.sampleRate); + var newLength = stop_sample - start_sample; + var copybuffer = audioContext.createBuffer(this.buffer.numberOfChannels, newLength, this.buffer.sampleRate); + // Now we can use some efficient background copy schemes if we are just padding the end + for (var c=0; c<this.buffer.numberOfChannels; c++) { + var buffer = this.buffer.getChannelData(c); + var sub_frame = buffer.subarray(start_sample,stop_sample); + if (typeof copybuffer.copyToChannel == "function") { + copybuffer.copyToChannel(sub_frame,c); + } else { + var dst = copybuffer.getChannelData(c); + for (var n=0; n<newLength; n++) + dst[n] = src[n+start_sample]; + } + } + return copybuffer; } }; @@ -1402,13 +1552,9 @@ this.play = function(id) { // Start the timer and set the audioEngine state to playing (1) - if (this.status == 0 && this.loopPlayback) { + if (this.status == 0) { // Check if all audioObjects are ready - if(this.checkAllReady()) - { - this.status = 1; - this.setSynchronousLoop(); - } + this.bufferReady(id); } else { @@ -1563,6 +1709,15 @@ } }; + this.bufferReady = function(id) { + if(this.checkAllReady()) { + if (this.synchPlayback){this.setSynchronousLoop();} + this.status = 1; + return true; + } + return false; + } + this.exportXML = function() { @@ -1611,12 +1766,22 @@ this.buffer = callee; var preSilenceTime = this.specification.preSilence || this.specification.parent.preSilence || specification.preSilence || 0.0; var postSilenceTime = this.specification.postSilence || this.specification.parent.postSilence || specification.postSilence || 0.0; + var startTime = this.specification.startTime; + var stopTime = this.specification.stopTime; + var copybuffer = new callee.constructor(); + if (isFinite(startTime) || isFinite(stopTime)) { + copybuffer.buffer = callee.cropBuffer(startTime,stopTime); + } if (preSilenceTime != 0 || postSilenceTime != 0) { - this.buffer = callee.copyBuffer(preSilenceTime,postSilenceTime); + if (copybuffer.buffer == undefined) { + copybuffer.buffer = callee.copyBuffer(preSilenceTime,postSilenceTime); + } else { + copybuffer.buffer = copybuffer.copyBuffer(preSilenceTime,postSilenceTime); + } } - this.state = 1; + var targetLUFS = this.specification.parent.loudness || specification.loudness; - if (typeof targetLUFS === "number") + if (typeof targetLUFS === "number" && isFinite(targetLUFS)) { this.buffer.buffer.playbackGain = decibelToLinear(targetLUFS - this.buffer.buffer.lufs); } else { @@ -1627,6 +1792,8 @@ } this.onplayGain = decibelToLinear(this.specification.gain)*(this.buffer.buffer.playbackGain||1.0); this.storeDOM.setAttribute('playGain',linearToDecibel(this.onplayGain)); + this.state = 1; + audioEngineContext.bufferReady(id); }; this.bindInterface = function(interfaceObject) @@ -3154,6 +3321,10 @@ surveyresult.appendChild(child); break; case "checkbox": + if (node.response == undefined) { + surveyresult.appendChild(this.parent.document.createElement('response')); + break; + } for (var i=0; i<node.response.length; i++) { var checkNode = this.parent.document.createElement('response');
--- a/js/specification.js Tue Aug 02 11:22:51 2016 +0100 +++ b/js/specification.js Tue Aug 02 12:26:19 2016 +0100 @@ -214,6 +214,7 @@ this.min = undefined; this.max = undefined; this.step = undefined; + this.conditions = []; this.decode = function(parent,child) { @@ -252,6 +253,17 @@ } } } + var conditionElements = child.getElementsByTagName("conditional"); + for (var i=0; i<conditionElements.length; i++) { + var condition = conditionElements[i]; + var obj = { + check: condition.getAttribute("check"), + value: condition.getAttribute("value"), + jumpToOnPass: condition.getAttribute("jumpToOnPass"), + jumpToOnFail: condition.getAttribute("jumpToOnFail") + } + this.conditions.push(obj); + } }; this.exportXML = function(doc) @@ -287,6 +299,14 @@ default: break; } + for (var condition of this.conditions) { + var conditionDOM = doc.createElement("conditional"); + conditionDOM.setAttribute("check",condition.check); + conditionDOM.setAttribute("value",condition.value); + conditionDOM.setAttribute("jumpToOnPass",condition.jumpToOnPass); + conditionDOM.setAttribute("jumpToOnFail",condition.jumpToOnFail); + node.appendChild(conditionDOM); + } return node; }; }; @@ -622,8 +642,8 @@ this.enforce = false; this.gain = 0.0; this.label = null; - this.startTime = null; - this.stopTime = null; + this.startTime = undefined; + this.stopTime = undefined; this.schema = specification.schema.getAllElementsByName('audioelement')[0];; this.parent = null; this.decode = function(parent,xml)
--- a/tests/examples/project.xml Tue Aug 02 11:22:51 2016 +0100 +++ b/tests/examples/project.xml Tue Aug 02 12:26:19 2016 +0100 @@ -4,6 +4,7 @@ <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement> + <conditional check="equals" value="John" jumpToOnPass="test-intro" jumpToOnFail="checkboxtest"/> </surveyentry> <surveyentry type="checkbox" id="checkboxtest" mandatory="true"> <statement>Please select with which activities you have any experience (example checkbox question)</statement> @@ -13,6 +14,9 @@ <option name="hwdesigner">Designing or building audio hardware</option> <option name="researcher">Research in the field of audio</option> </surveyentry> + <surveyentry type="question" id="instrument" mandatory="false"> + <statement>What instrument did you play</statement> + </surveyentry> <surveyentry type="statement" id="test-intro"> <statement>This is an example of an 'APE'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> </surveyentry>
--- a/xml/test-schema.xsd Tue Aug 02 11:22:51 2016 +0100 +++ b/xml/test-schema.xsd Tue Aug 02 12:26:19 2016 +0100 @@ -249,6 +249,23 @@ </xs:simpleContent> </xs:complexType> </xs:element> + <xs:element name="conditional" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="check" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="equals"/> + <xs:enumeration value="lessThan"/> + <xs:enumeration value="greaterThan"/> + <xs:enumeration value="stringContains"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="value" type="xs:string" use="optional"/> + <xs:attribute name="jumpToOnPass" type="xs:string" use="optional"/> + <xs:attribute name="jumpToOnFail" type="xs:string" use="optional"/> + </xs:complexType> + </xs:element> </xs:sequence> <xs:attribute ref="id" use="required" /> <xs:attribute ref="name" />