Mercurial > hg > webaudioevaluationtool
changeset 1048:7a8fcf04aad3
Merge
author | Brecht De Man <BrechtDeMan@users.noreply.github.com> |
---|---|
date | Mon, 29 Jun 2015 19:04:40 +0100 |
parents | ba83143187d6 (current diff) 01fcd75067c1 (diff) |
children | a37ab38cf90b |
files | .hgignore ape.js core.js docs/SMC15/interface.png docs/SMC15/smc2015template.tex example_eval/project.xml index.html scripts/comment_parser.py scripts/score_parser.py |
diffstat | 3 files changed, 194 insertions(+), 105 deletions(-) [+] |
line wrap: on
line diff
--- a/ape.js Mon Jun 29 19:02:48 2015 +0100 +++ b/ape.js Mon Jun 29 19:04:40 2015 +0100 @@ -147,6 +147,40 @@ return state; }; + Interface.prototype.checkScaleRange = function() + { + var audioObjs = audioEngineContext.audioObjects; + var audioHolder = testState.stateMap[testState.stateIndex]; + var interfaces = audioHolder.interfaces; + + var minRanking = audioObjs[0].interfaceDOM.getValue(); + var maxRanking = minRanking; + + var minScale; + var maxScale; + for (var i=0; i<interfaces[0].options.length; i++) + { + if (interfaces[0].options[i].check == "scalerange") { + minScale = interfaces[0].options[i].min; + maxScale = interfaces[0].options[i].max; + } + } + + for (var i=1; i<audioObjs.length; i++){ + if (audioObjs[i].specification.type != 'outsidereference') { + var ranking = audioObjs[i].interfaceDOM.getValue(); + if (ranking < minRanking) { minRanking = ranking;} + if (ranking > maxRanking) { maxRanking = ranking;} + } + } + if (minRanking > minScale || maxRanking < maxScale) { + alert('Please use the full width of the scale'); + return false; + } else { + return true; + } + }; + // Bindings for audioObjects // Create the top div for the Title element @@ -264,11 +298,11 @@ feedbackHolder.innerHTML = null; canvas.innerHTML = null; - //var playbackHolder = document.createElement('div'); - //playbackHolder.style.width = "100%"; - //playbackHolder.align = 'center'; - //playbackHolder.appendChild(interfaceContext.playhead.object); - //feedbackHolder.appendChild(playbackHolder); + var playbackHolder = document.createElement('div'); + playbackHolder.style.width = "100%"; + playbackHolder.align = 'center'; + playbackHolder.appendChild(interfaceContext.playhead.object); + feedbackHolder.appendChild(playbackHolder); // Setup question title var interfaceObj = audioHolderObject.interfaces; var commentBoxPrefix = "Comment on track"; @@ -323,14 +357,6 @@ currentTestHolder.id = audioHolderObject.id; currentTestHolder.repeatCount = audioHolderObject.repeatCount; - var randomise = audioHolderObject.randomiseOrder; - - var audioElements = audioHolderObject.audioElements; - currentTrackOrder = []; - if (randomise) { - audioHolderObject.audioElements = randomiseOrder(audioHolderObject.audioElements); - } - // Delete any previous audioObjects associated with the audioEngine audioEngineContext.audioObjects = []; interfaceContext.deleteCommentBoxes(); @@ -369,6 +395,31 @@ feedbackHolder.appendChild(node.holder); }); + // Construct outside reference; + if (audioHolderObject.outsideReference != null) { + var outsideReferenceHolder = document.createElement('div'); + outsideReferenceHolder.id = 'outside-reference'; + outsideReferenceHolderspan = document.createElement('span'); + outsideReferenceHolderspan.textContent = 'Reference'; + outsideReferenceHolder.appendChild(outsideReferenceHolderspan); + + var audioObject = audioEngineContext.newTrack(audioHolderObject.outsideReference); + + outsideReferenceHolder.onclick = function() + { + audioEngineContext.play(audioEngineContext.audioObjects.length-1); + $('.track-slider').removeClass('track-slider-playing'); + $('.comment-div').removeClass('comment-box-playing'); + if (event.srcElement.nodeName == 'DIV') { + $(event.srcElement).addClass('track-slider-playing'); + } else { + $(event.srcElement.parentElement).addClass('track-slider-playing'); + } + }; + + document.getElementById('interface-buttons').appendChild(outsideReferenceHolder); + } + testWaitIndicator(); } @@ -408,6 +459,9 @@ $(element).addClass('track-slider-playing'); $('.comment-div').removeClass('comment-box-playing'); $('#comment-div-'+id).addClass('comment-box-playing'); + var outsideReference = document.getElementById('outside-reference'); + if (outsideReference != undefined) + $(outsideReference).removeClass('track-slider-playing'); } }; @@ -445,66 +499,12 @@ function buttonSubmitClick() // TODO: Only when all songs have been played! { - var checks = specification.commonInterface.options; + var checks = testState.currentStateMap[testState.currentIndex].interfaces[0].options; var canContinue = true; // Check that the anchor and reference objects are correctly placed - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; - var anchorId = null; - var referenceId = null; - for (var i=0; i<audioObjs.length; i++) { - if (audioObjs[i].specification.anchor == true && anchorId == null) {anchorId = i;} - if (audioObjs[i].specification.reference == true && referenceId == null) {referenceId = i;} - } - if (anchorId != null) { - if (audioObjs[anchorId].specification.marker != null) { - if (audioObjs[anchorId].interfaceDOM.getValue() > audioObjs[anchorId].specification.marker) - { - // Anchor is not set below - console.log('Anchor node not below marker value'); - alert('Please keep listening'); - return; - } - } else { - // No marker value given, ensure it is the minimum value - var anchorVal = audioObjs[anchorId].interfaceDOM.getValue(); - for (var i=0; i<audioObjs.length; i++) { - if (i != anchorId) { - if (anchorVal > audioObjs[i].interfaceDOM.getValue()) { - // Anchor not the minimum - console.log('No marker set, anchor node not the minimum'); - alert('Please keep listening'); - return; - } - } - } - } - } - if (referenceId != null) { - if (audioObjs[referenceId].specification.marker != null) { - if (audioObjs[referenceId].interfaceDOM.getValue() < audioObjs[referenceId].specification.marker) - { - // Anchor is not set below - console.log('Reference node not above marker value'); - alert('Please keep listening'); - return; - } - } else { - // No marker value given, ensure it is the minimum value - var referenceVal = audioObjs[referenceId].interfaceDOM.getValue(); - for (var i=0; i<audioObjs.length; i++) { - if (i != referenceId) { - if (referenceVal > audioObjs[i].interfaceDOM.getValue()) { - // Anchor not the minimum - console.log('No marker set, reference node not the maximum'); - alert('Please keep listening'); - return; - } - } - } - } - } + if (interfaceContext.checkHiddenAnchor() == false) {return;} + if (interfaceContext.checkHiddenReference() == false) {return;} for (var i=0; i<checks.length; i++) { if (checks[i].type == 'check') @@ -531,9 +531,15 @@ var checkState = interfaceContext.checkAllCommented(); if (checkState == false) {canContinue = false;} break; + case 'scalerange': + // Check the scale is used to its full width outlined by the node + var checkState = interfaceContext.checkScaleRange(); + if (checkState == false) {canContinue = false;} + break; } } + if (!canContinue) {break;} } if (canContinue) { @@ -618,6 +624,7 @@ for (var i=0; i<audioObjects.length; i++) { var audioElement = audioEngineContext.audioObjects[i].exportXMLDOM(); + audioElement.setAttribute('presentedId',i); xmlDoc.appendChild(audioElement); }
--- a/core.js Mon Jun 29 19:02:48 2015 +0100 +++ b/core.js Mon Jun 29 19:04:40 2015 +0100 @@ -204,7 +204,7 @@ this.popupContent.appendChild(span); this.popupContent.appendChild(document.createElement('br')); var input = document.createElement('input'); - input.type = 'number'; + input.type = 'textarea'; if (node.min != null) {input.min = node.min;} if (node.max != null) {input.max = node.max;} if (node.step != null) {input.step = node.step;} @@ -298,7 +298,7 @@ return; } var enteredNumber = Number(input.value); - if (enteredNumber == undefined) { + if (isNaN(enteredNumber)) { alert('Please enter a valid number'); return; } @@ -638,6 +638,9 @@ function interfaceXMLSave(){ // Create the XML string to be exported with results var xmlDoc = document.createElement("BrowserEvaluationResult"); + var projectDocument = specification.projectXML; + projectDocument.setAttribute('file-name',url); + xmlDoc.appendChild(projectDocument); xmlDoc.appendChild(returnDateNode()); for (var i=0; i<testState.stateResults.length; i++) { @@ -892,8 +895,16 @@ var root = document.createElement('audioElement'); root.id = this.specification.id; root.setAttribute('url',this.url); - root.appendChild(this.interfaceDOM.exportXMLDOM(this)); - root.appendChild(this.commentDOM.exportXMLDOM(this)); + var file = document.createElement('file'); + file.setAttribute('sampleRate',this.buffer.sampleRate); + file.setAttribute('channels',this.buffer.numberOfChannels); + file.setAttribute('sampleCount',this.buffer.length); + file.setAttribute('duration',this.buffer.duration); + root.appendChild(file); + if (this.specification.type != 'outsidereference') { + root.appendChild(this.interfaceDOM.exportXMLDOM(this)); + root.appendChild(this.commentDOM.exportXMLDOM(this)); + } root.appendChild(this.metric.exportXMLDOM()); return root; }; @@ -1213,6 +1224,7 @@ this.decode = function() { // projectXML - DOM Parsed document + this.projectXML = projectXML.childNodes[0]; var setupNode = projectXML.getElementsByTagName('setup')[0]; this.interfaceType = setupNode.getAttribute('interface'); this.projectReturn = setupNode.getAttribute('projectReturn'); @@ -1246,6 +1258,22 @@ this.type = child.nodeName; if (this.type == 'check') { this.check = child.getAttribute('name'); + if (this.check == 'scalerange') { + this.min = child.getAttribute('min'); + this.max = child.getAttribute('max'); + if (this.min == null) {this.min = 1;} + else if (Number(this.min) > 1 && this.min != null) { + this.min = Number(this.min)/100; + } else { + this.min = Number(this.min); + } + if (this.max == null) {this.max = 0;} + else if (Number(this.max) > 1 && this.max != null) { + this.max = Number(this.max)/100; + } else { + this.max = Number(this.max); + } + } } else if (this.type == 'anchor' || this.type == 'reference') { this.value = Number(child.textContent); } @@ -1345,7 +1373,7 @@ var title = DOM.getElementsByTagName('title'); if (title.length == 0) {this.title = null;} else {this.title = title[0].textContent;} - + this.options = parent.commonInterface.options; var scale = DOM.getElementsByTagName('scale'); this.scale = []; for (var i=0; i<scale.length; i++) { @@ -1360,27 +1388,27 @@ this.url = xml.getAttribute('url'); this.id = xml.id; this.parent = parent; - this.anchor = xml.getAttribute('anchor'); - if (this.anchor == 'true') {this.anchor = true;} + this.type = xml.getAttribute('type'); + if (this.type == null) {this.type = "normal";} + if (this.type == 'anchor') {this.anchor = true;} else {this.anchor = false;} - - this.reference = xml.getAttribute('reference'); - if (this.reference == 'true') {this.reference = true;} + if (this.type == 'reference') {this.reference = true;} else {this.reference = false;} - if (this.anchor == true && this.reference == true) { - console.log('ERROR - Cannot have one audioElement be both the reference and anchor!'); - console.log(this); - console.log('Neither reference nor anchor will be enabled on this fragment'); - this.anchor = false; - this.reference = false; - } - if (this.anchor == true) { + this.marker = xml.getAttribute('marker'); + if (this.marker == null) {this.marker = undefined;} + + if (this.anchor == true && this.marker == undefined) { this.marker = anchor; } - if (this.reference == true) { + else if (this.reference == true && this.marker == undefined) { this.marker = reference; } + + if (this.marker != undefined) { + this.marker = Number(this.marker); + if (this.marker > 1) {this.marker /= 100;} + } }; this.commentQuestionNode = function(xml) { @@ -1494,13 +1522,30 @@ this.audioElements =[]; var audioElementsDOM = xml.getElementsByTagName('audioElements'); + this.outsideReference = null; for (var i=0; i<audioElementsDOM.length; i++) { - this.audioElements.push(new this.audioElementNode(this,audioElementsDOM[i])); + if (audioElementsDOM[i].getAttribute('type') == 'outsidereference') { + if (this.outsideReference == null) { + this.outsideReference = new this.audioElementNode(this,audioElementsDOM[i]); + } else { + console.log('Error only one audioelement can be of type outsidereference per audioholder'); + this.audioElements.push(new this.audioElementNode(this,audioElementsDOM[i])); + console.log('Element id '+audioElementsDOM[i].id+' made into normal node'); + } + } else { + this.audioElements.push(new this.audioElementNode(this,audioElementsDOM[i])); + } + } + + if (this.randomiseOrder) { + this.audioElements = randomiseOrder(this.audioElements); } // Check only one anchor and one reference per audioNode var anchor = []; var reference = []; + this.anchorId = null; + this.referenceId = null; for (var i=0; i<this.audioElements.length; i++) { if (this.audioElements[i].anchor == true) {anchor.push(i);} @@ -1515,7 +1560,7 @@ this.audioElements[anchor[i]].anchor = false; this.audioElements[anchor[i]].value = undefined; } - } + } else {this.anchorId = anchor[0];} if (reference.length > 1) { console.log('Error - cannot have more than one anchor!'); console.log('Each anchor node will be a normal mode to continue the test'); @@ -1524,7 +1569,7 @@ this.audioElements[reference[i]].reference = false; this.audioElements[reference[i]].value = undefined; } - } + } else {this.referenceId = reference[0];} this.commentQuestions = []; var commentQuestionsDOM = xml.getElementsByTagName('CommentQuestion'); @@ -1798,7 +1843,7 @@ this.deleteCommentBoxes = function() { this.commentBoxes = []; - } + }; this.createCommentQuestion = function(element) { var node; @@ -1888,5 +1933,41 @@ this.interval = undefined; }; }; + + // Global Checkers + // These functions will help enforce the checkers + this.checkHiddenAnchor = function() + { + var audioHolder = testState.currentStateMap[testState.currentIndex]; + if (audioHolder.anchorId != null) + { + var audioObject = audioEngineContext.audioObjects[audioHolder.anchorId]; + if (audioObject.interfaceDOM.getValue() > audioObject.specification.marker) + { + // Anchor is not set below + console.log('Anchor node not below marker value'); + alert('Please keep listening'); + return false; + } + } + return true; + }; + + this.checkHiddenReference = function() + { + var audioHolder = testState.currentStateMap[testState.currentIndex]; + if (audioHolder.referenceId != null) + { + var audioObject = audioEngineContext.audioObjects[audioHolder.referenceId]; + if (audioObject.interfaceDOM.getValue() < audioObject.specification.marker) + { + // Anchor is not set below + console.log('Reference node not above marker value'); + alert('Please keep listening'); + return false; + } + } + return true; + }; }
--- a/example_eval/project.xml Mon Jun 29 19:02:48 2015 +0100 +++ b/example_eval/project.xml Mon Jun 29 19:04:40 2015 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <BrowserEvalProjectDocument> - <setup interface="APE" projectReturn="/save" randomiseOrder='false' collectMetrics='true'> + <setup interface="APE" projectReturn="/save" randomiseOrder='true' collectMetrics='true'> <PreTest> <question id="Location" mandatory="true" boxsize="large">Please enter your location.</question> <checkbox id="experience"> @@ -39,8 +39,7 @@ <check name="fragmentFullPlayback"/> <check name="fragmentMoved"/> <check name="fragmentComments"/>--> - <anchor>20</anchor> - <reference>80</reference> + <check name="scalerange" min="25" max="75"/> </interface> </setup> <audioHolder id='test-0' hostURL="example_eval/" sampleRate="44100" randomiseOrder='true' repeatCount='0' loop='true' elementComments='true'> @@ -51,21 +50,22 @@ <scale position="50">Middle</scale> <scale position="20">20</scale> <commentBoxPrefix>Comment on fragment</commentBoxPrefix> + <anchor>40</anchor> </interface> - <audioElements url="0.wav" id="0"/> + <audioElements url="0.wav" id="0" type="anchor"/> <audioElements url="1.wav" id="1"/> <audioElements url="2.wav" id="2"/> <audioElements url="3.wav" id="3"/> - <audioElements url="4.wav" id="4"/> - <audioElements url="5.wav" id="5"/> + <audioElements url="4.wav" id="4" type="outsidereference"/> + <!--<audioElements url="5.wav" id="5"/> <audioElements url="6.wav" id="6"/> - <!--<audioElements url="7.wav" id="7"/> + <audioElements url="7.wav" id="7"/> <audioElements url="8.wav" id="8"/> <audioElements url="9.wav" id="9"/> <audioElements url="10.wav" id="10"/>--> - <CommentQuestion id='generalExperience' type="text">General Comments</CommentQuestion> + <CommentQuestion id='mixingExperience' type="text">What is your mixing experience</CommentQuestion> <CommentQuestion id="preference" type="radio"> - <statement>What do you think of the song?</statement> + <statement>Please enter your ranking preference on this song</statement> <option name="worst">Very Bad</option> <option name="bad"></option> <option name="OK">OK</option> @@ -73,7 +73,7 @@ <option name="Great">Great</option> </CommentQuestion> <CommentQuestion id="preference" type="checkbox"> - <statement>This song is... </statement> + <statement>Describe this song</statement> <option name="bright">Bright</option> <option name="punchy">Punchy</option> <option name="dark">Dark</option> @@ -92,10 +92,11 @@ <scale position="100">Max</scale> <scale position="50">Middle</scale> <scale position="75">75</scale> + <scalerange min="25" max="75"/> <commentBoxPrefix>Comment on fragment</commentBoxPrefix> </interface> - <audioElements url="0.wav" id="0"/> - <audioElements url="1.wav" id="1"/> + <audioElements url="0.wav" id="0" type="reference" marker="80"/> + <audioElements url="1.wav" id="1" type="anchor" marker="20"/> <audioElements url="2.wav" id="2"/> <audioElements url="3.wav" id="3"/> <audioElements url="4.wav" id="4"/>