Mercurial > hg > webaudioevaluationtool
changeset 2221:6dbee0a43792
Merge branch 'Dev_main'. Preparing for tidy up of file structure.
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Thu, 14 Apr 2016 12:26:53 +0100 |
parents | de1feb0d13df (current diff) 7f44ba6533b4 (diff) |
children | 4d1aa94202e3 |
files | |
diffstat | 8 files changed, 452 insertions(+), 353 deletions(-) [+] |
line wrap: on
line diff
--- a/core.js Wed Apr 13 15:46:40 2016 +0100 +++ b/core.js Thu Apr 14 12:26:53 2016 +0100 @@ -492,10 +492,59 @@ return Math.pow(10,gain/20.0); } +function secondsToSamples(time,fs) { + return Math.round(time*fs); +} + +function samplesToSeconds(samples,fs) { + return samples / fs; +} + function randomString(length) { return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1); } +function randomiseOrder(input) +{ + // This takes an array of information and randomises the order + var N = input.length; + + var inputSequence = []; // For safety purposes: keep track of randomisation + for (var counter = 0; counter < N; ++counter) + inputSequence.push(counter) // Fill array + var inputSequenceClone = inputSequence.slice(0); + + var holdArr = []; + var outputSequence = []; + for (var n=0; n<N; n++) + { + // First pick a random number + var r = Math.random(); + // Multiply and floor by the number of elements left + r = Math.floor(r*input.length); + // Pick out that element and delete from the array + holdArr.push(input.splice(r,1)[0]); + // Do the same with sequence + outputSequence.push(inputSequence.splice(r,1)[0]); + } + console.log(inputSequenceClone.toString()); // print original array to console + console.log(outputSequence.toString()); // print randomised array to console + return holdArr; +} + +function randomSubArray(array,num) { + if (num > array.length) { + num = array.length; + } + var ret = []; + while (num > 0) { + var index = Math.floor(Math.random() * array.length); + ret.push( array.splice(index,1)[0] ); + num--; + } + return ret; +} + function interfacePopup() { // Creates an object to manage the popup this.popup = null; @@ -556,12 +605,14 @@ }; this.hidePopup = function(){ - this.popup.style.zIndex = -1; - this.popup.style.visibility = 'hidden'; - var blank = document.getElementsByClassName('testHalt')[0]; - blank.style.zIndex = -2; - blank.style.visibility = 'hidden'; - this.buttonPrevious.style.visibility = 'inherit'; + if (this.popup) { + this.popup.style.zIndex = -1; + this.popup.style.visibility = 'hidden'; + var blank = document.getElementsByClassName('testHalt')[0]; + blank.style.zIndex = -2; + blank.style.visibility = 'hidden'; + this.buttonPrevious.style.visibility = 'inherit'; + } }; this.postNode = function() { @@ -850,43 +901,68 @@ this.currentStatePosition = null; this.currentStore = null; this.initialise = function(){ - + // Get the data from Specification - var pageHolder = []; + var pagePool = []; + var pageInclude = []; for (var page of specification.pages) { - var repeat = page.repeatCount; - while(repeat >= 0) - { - pageHolder.push(page); - repeat--; + if (page.alwaysInclude) { + pageInclude.push(page); + } else { + pagePool.push(page); } } + + // Find how many are left to get + var numPages = specification.poolSize; + if (numPages > pagePool.length) { + console.log("WARNING - You have specified more pages in <setup poolSize> than you have created!!"); + numPages = specification.pages.length; + } + if (specification.poolSize == 0) { + numPages = specification.pages.length; + } + numPages -= pageInclude.length; + + if (numPages > 0) { + // Go find the rest of the pages from the pool + var subarr = null; + if (specification.randomiseOrder) { + // Append a random sub-array + subarr = randomSubArray(pagePool,numPages); + } else { + // Append the matching number + subarr = pagePool.slice(0,numPages); + } + pageInclude = pageInclude.concat(subarr); + } + + // We now have our selected pages in pageInclude array if (specification.randomiseOrder) { - pageHolder = randomiseOrder(pageHolder); + pageInclude = randomiseOrder(pageInclude); } - for (var i=0; i<pageHolder.length; i++) + for (var i=0; i<pageInclude.length; i++) { - if (specification.testPages <= i && specification.testPages != 0) {break;} - pageHolder[i].presentedId = i; - this.stateMap.push(pageHolder[i]); - storage.createTestPageStore(pageHolder[i]); - for (var element of pageHolder[i].audioElements) { - var URL = pageHolder[i].hostURL + element.url; - var buffer = null; - for (var buffObj of audioEngineContext.buffers) { - if (URL == buffObj.url) { - buffer = buffObj; - break; + pageInclude[i].presentedId = i; + this.stateMap.push(pageInclude[i]); + // For each selected page, we must get the sub pool + if (pageInclude[i].poolSize != 0 && pageInclude[i].poolSize != pageInclude[i].audioElements.length) { + var elemInclude = []; + var elemPool = []; + for (var elem of pageInclude[i].audioElements) { + if (elem.include || elem.type != "normal") { + elemInclude.push(elem); + } else { + elemPool.push(elem); } } - if (buffer == null) { - buffer = new audioEngineContext.bufferObj(); - buffer.getMedia(URL); - audioEngineContext.buffers.push(buffer); - } + var numElems = pageInclude[i].poolSize - elemInclude.length; + pageInclude[i].audioElements = elemInclude.concat(randomSubArray(elemPool,numElems)); } + storage.createTestPageStore(pageInclude[i]); + audioEngineContext.loadPageData(pageInclude[i]); } if (specification.preTest != null) {this.preTestSurvey = specification.preTest;} @@ -1170,8 +1246,56 @@ // The buffer is already ready, trigger bufferLoaded audioObject.bufferLoaded(this); } + }; + + this.copyBuffer = function(preSilenceTime,postSilenceTime) { + // 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); + // Now we can use some efficient background copy schemes if we are just padding the end + if (preSilenceSamples == 0 && typeof copy.buffer.copyToChannel == "function") { + for (var c=0; c<this.buffer.numberOfChannels; c++) { + copy.buffer.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); + 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; } }; + + this.loadPageData = function(page) { + // Load the URL from pages + for (var element of page.audioElements) { + var URL = page.hostURL + element.url; + var buffer = null; + for (var buffObj of this.buffers) { + if (URL == buffObj.url) { + buffer = buffObj; + break; + } + } + if (buffer == null) { + buffer = new this.bufferObj(); + buffer.getMedia(URL); + this.buffers.push(buffer); + } + } + }; this.play = function(id) { // Start the timer and set the audioEngine state to playing (1) @@ -1191,16 +1315,16 @@ this.timer.startTest(); if (id == undefined) { id = -1; - console.log('FATAL - Passed id was undefined - AudioEngineContext.play(id)'); + console.error('FATAL - Passed id was undefined - AudioEngineContext.play(id)'); return; } else { interfaceContext.playhead.setTimePerPixel(this.audioObjects[id]); } if (this.loopPlayback) { - var setTime = audioContext.currentTime; + var setTime = audioContext.currentTime+specification.crossFade; for (var i=0; i<this.audioObjects.length; i++) { - this.audioObjects[i].play(setTime); + this.audioObjects[i].play(audioContext.currentTime); if (id == i) { this.audioObjects[i].loopStart(setTime); } else { @@ -1208,7 +1332,7 @@ } } } else { - var setTime = audioContext.currentTime+0.1; + var setTime = audioContext.currentTime+specification.crossFade; for (var i=0; i<this.audioObjects.length; i++) { if (i != id) { @@ -1314,6 +1438,7 @@ this.setSynchronousLoop = function() { // Pads the signals so they are all exactly the same length + // Get the length of the longest signal. var length = 0; var maxId; for (var i=0; i<this.audioObjects.length; i++) @@ -1325,20 +1450,10 @@ } } // Extract the audio and zero-pad - for (var i=0; i<this.audioObjects.length; i++) + for (var ao of this.audioObjects) { - var orig = this.audioObjects[i].buffer.buffer; - var hold = audioContext.createBuffer(orig.numberOfChannels,length,orig.sampleRate); - for (var c=0; c<orig.numberOfChannels; c++) - { - var inData = hold.getChannelData(c); - var outData = orig.getChannelData(c); - for (var n=0; n<orig.length; n++) - {inData[n] = outData[n];} - } - hold.playbackGain = orig.playbackGain; - hold.lufs = orig.lufs; - this.audioObjects[i].buffer.buffer = hold; + var lengthDiff = length - ao.buffer.buffer.length; + ao.buffer = ao.buffer.copyBuffer(0,samplesToSeconds(lengthDiff,ao.buffer.buffer.sampleRate)); } }; @@ -1387,26 +1502,13 @@ this.buffer = callee; return; } - if (audioEngineContext.loopPlayback){ - // First copy the buffer into this.buffer - this.buffer = new audioEngineContext.bufferObj(); - this.buffer.url = callee.url; - this.buffer.buffer = audioContext.createBuffer(callee.buffer.numberOfChannels, callee.buffer.length, callee.buffer.sampleRate); - for (var c=0; c<callee.buffer.numberOfChannels; c++) - { - var src = callee.buffer.getChannelData(c); - var dst = this.buffer.buffer.getChannelData(c); - for (var n=0; n<src.length; n++) - { - dst[n] = src[n]; - } - } - } else { - this.buffer = callee; - } + 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; + if (preSilenceTime != 0 || postSilenceTime != 0) { + this.buffer = callee.copyBuffer(preSilenceTime,postSilenceTime); + } this.state = 1; - this.buffer.buffer.playbackGain = callee.buffer.playbackGain; - this.buffer.buffer.lufs = callee.buffer.lufs; var targetLUFS = this.specification.parent.loudness || specification.loudness; if (typeof targetLUFS === "number") { @@ -1763,34 +1865,6 @@ return storeDOM; }; } - -function randomiseOrder(input) -{ - // This takes an array of information and randomises the order - var N = input.length; - - var inputSequence = []; // For safety purposes: keep track of randomisation - for (var counter = 0; counter < N; ++counter) - inputSequence.push(counter) // Fill array - var inputSequenceClone = inputSequence.slice(0); - - var holdArr = []; - var outputSequence = []; - for (var n=0; n<N; n++) - { - // First pick a random number - var r = Math.random(); - // Multiply and floor by the number of elements left - r = Math.floor(r*input.length); - // Pick out that element and delete from the array - holdArr.push(input.splice(r,1)[0]); - // Do the same with sequence - outputSequence.push(inputSequence.splice(r,1)[0]); - } - console.log(inputSequenceClone.toString()); // print original array to console - console.log(outputSequence.toString()); // print randomised array to console - return holdArr; -} function Interface(specificationObject) { // This handles the bindings between the interface and the audioEngineContext;
--- a/example_eval/ABX_example.xml Wed Apr 13 15:46:40 2016 +0100 +++ b/example_eval/ABX_example.xml Thu Apr 14 12:26:53 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="ABX" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="ABX" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/AB_example.xml Wed Apr 13 15:46:40 2016 +0100 +++ b/example_eval/AB_example.xml Thu Apr 14 12:26:53 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="AB" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="AB" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/mushra_example.xml Wed Apr 13 15:46:40 2016 +0100 +++ b/example_eval/mushra_example.xml Thu Apr 14 12:26:53 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100"> + <setup interface="MUSHRA" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100"> <exitText>Thank you for looking at WAET. You can modify the successful completion text as well!</exitText> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true">
--- a/example_eval/project.xml Wed Apr 13 15:46:40 2016 +0100 +++ b/example_eval/project.xml Thu Apr 14 12:26:53 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="APE" projectReturn="save.php" randomiseOrder='true' testPages="2" loudness="-23" sampleRate="44100" calibration="true"> + <setup interface="APE" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" sampleRate="44100" calibration="true"> <survey location="before"> <surveyentry type="question" id="sessionId" mandatory="true"> <statement>Please enter your name.</statement>
--- a/example_eval/radio_example.xml Wed Apr 13 15:46:40 2016 +0100 +++ b/example_eval/radio_example.xml Thu Apr 14 12:26:53 2016 +0100 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" ?> <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="likert" projectReturn="save.php"> + <setup interface="likert" projectReturn="save.php" crossFade="3.0"> <metric> <metricenable>testTimer</metricenable> <metricenable>elementTimer</metricenable> @@ -18,7 +18,7 @@ <interfaceoption type="show" name="page-count"/> </interface> </setup> - <page id='test-0' hostURL="example_eval/" randomiseOrder='true' repeatCount='4' loop='true' showElementComments='true' loudness="-23"> + <page id='test-0' hostURL="example_eval/" randomiseOrder='true' repeatCount='4' loop='true' showElementComments='true' loudness="-23" poolSize="3"> <interface> <scales> <scalelabel position="0">(1) Very Annoying</scalelabel> @@ -28,8 +28,9 @@ <scalelabel position="100">(5) Inaudible</scalelabel> </scales> </interface> - <audioelement url="0.wav" id="track-1"/> + <audioelement url="0.wav" id="track-1" alwaysInclude="true"/> <audioelement url="1.wav" id="track-2"/> + <audioelement url="3.wav" id="track-4"/> <audioelement url="2.wav" id="track-3" type="outside-reference"/> </page> </waet>
--- a/specification.js Wed Apr 13 15:46:40 2016 +0100 +++ b/specification.js Thu Apr 14 12:26:53 2016 +0100 @@ -27,7 +27,19 @@ } var dataType = schema.getAttribute('type'); if (typeof dataType == "string") { dataType = dataType.substr(3);} - else {dataType = "string";} + else { + var rest = schema.getAllElementsByTagName("xs:restriction").concat(schema.getAllElementsByTagName("xs:enumeration")); + if (rest.length > 0) { + dataType = rest[0].getAttribute("base"); + if (typeof dataType == "string") { + dataType = dataType.substr(3); + } else { + dataType = "string"; + } + } else { + dataType = "string"; + } + } if (attribute == null) { return attribute;
--- a/test-schema.xsd Wed Apr 13 15:46:40 2016 +0100 +++ b/test-schema.xsd Thu Apr 14 12:26:53 2016 +0100 @@ -1,263 +1,275 @@ <?xml version="1.0"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <!-- define simple elements--> - <xs:element name="statement" type="xs:string"/> - <xs:element name="metricenable" type="xs:string"/> - <xs:element name="title" type="xs:string"/> - - <!-- define simple attributes--> - <xs:attribute name="id" type="xs:ID"/> - <xs:attribute name="mandatory" type="xs:boolean"/> - <xs:attribute name="name" type="xs:string"/> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <!-- define simple elements--> + <xs:element name="statement" type="xs:string" /> + <xs:element name="metricenable" type="xs:string" /> + <xs:element name="title" type="xs:string" /> - <xs:attribute name="preSilence" default="0"> - <xs:simpleType> - <xs:restriction base="xs:decimal"> - <xs:minInclusive value="0.0"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="postSilence" default="0"> - <xs:simpleType> - <xs:restriction base="xs:decimal"> - <xs:minInclusive value="0.0"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - - <!-- define complex elements--> - <xs:element name="waet"> - <xs:complexType> - <xs:sequence> - <xs:element ref="setup" minOccurs="1" maxOccurs="1"/> - <xs:element ref="page" minOccurs="1" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> + <!-- define simple attributes--> + <xs:attribute name="id" type="xs:ID" /> + <xs:attribute name="mandatory" type="xs:boolean" /> + <xs:attribute name="name" type="xs:string" /> + <xs:attribute name="poolSize" type="xs:nonNegativeInteger" default="0" /> + <xs:attribute name="alwaysInclude" type="xs:boolean" default="false" /> - <xs:element name="setup"> - <xs:complexType> - <xs:sequence> - <xs:element name="exitText" type="xs:string" minOccurs="0" maxOccurs="1"/> - <xs:element ref="survey" minOccurs="0" maxOccurs="2"/> - <xs:element ref="metric" maxOccurs="1"/> - <xs:element ref="interface" maxOccurs="1"/> - </xs:sequence> - <xs:attribute name="interface" type="xs:string" use="required"/> - <xs:attribute name="projectReturn" type="xs:string" use="optional" default=""/> - <xs:attribute name="randomiseOrder" type="xs:boolean" default="false"/> - <xs:attribute name="testPages" type="xs:nonNegativeInteger" default="0"/> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute name="sampleRate" type="xs:positiveInteger" use="optional"/> - <xs:attribute name="calibration" type="xs:boolean" default="false"/> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <xs:attribute name="preSilence"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="postSilence"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> - <xs:element name="page"> - <xs:complexType> - <xs:sequence> - <xs:element ref="title" minOccurs="0" maxOccurs="1"/> - <xs:element name="commentboxprefix" type="xs:string" minOccurs="0" maxOccurs="1"/> - <xs:element ref="interface" minOccurs="1" maxOccurs="unbounded"/> - <xs:element ref="audioelement" minOccurs="1" maxOccurs="unbounded"/> - <xs:element ref="commentquestion" minOccurs="0" maxOccurs="unbounded"/> - <xs:element ref="survey" minOccurs="0" maxOccurs="2"/> - </xs:sequence> - <xs:attribute ref="id" use="required"/> - <xs:attribute name="hostURL" type="xs:anyURI" default=""/> - <xs:attribute name="randomiseOrder" type="xs:boolean" default="false"/> - <xs:attribute name="repeatCount" type="xs:nonNegativeInteger" default="0"/> - <xs:attribute name="loop" type="xs:boolean" default="false"/> - <xs:attribute name="showElementComments" type="xs:boolean" default="false"/> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute name="label" use="optional" default="default"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="default"/> - <xs:enumeration value="none"/> - <xs:enumeration value="number"/> - <xs:enumeration value="letter"/> - <xs:enumeration value="capital"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <!-- define complex elements--> + <xs:element name="waet"> + <xs:complexType> + <xs:sequence> + <xs:element ref="setup" minOccurs="1" maxOccurs="1" /> + <xs:element ref="page" minOccurs="1" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> - <xs:element name="metric"> - <xs:complexType> - <xs:sequence> - <xs:element name="metricenable" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> - </xs:sequence> - </xs:complexType> - </xs:element> + <xs:element name="setup"> + <xs:complexType> + <xs:sequence> + <xs:element name="exitText" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> + <xs:element ref="metric" maxOccurs="1" /> + <xs:element ref="interface" maxOccurs="1" /> + </xs:sequence> + <xs:attribute name="interface" type="xs:string" use="required" /> + <xs:attribute name="projectReturn" type="xs:string" use="optional" default="" /> + <xs:attribute name="randomiseOrder" type="xs:boolean" default="false" /> + <xs:attribute ref="poolSize" /> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute name="sampleRate" type="xs:positiveInteger" use="optional" /> + <xs:attribute name="calibration" type="xs:boolean" default="false" /> + <xs:attribute name="crossFade" default="0.0"> + <xs:simpleType> + <xs:restriction base="xs:decimal"> + <xs:minInclusive value="0.0" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> + </xs:element> - <xs:element name="interface"> - <xs:complexType> - <xs:sequence> - <xs:element ref="title" minOccurs="0" maxOccurs="1"/> - <xs:element name="interfaceoption" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:attribute name="type" use="required"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="check"/> - <xs:enumeration value="show"/> - <xs:enumeration value="option"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute ref="name" use="required"/> - <xs:attribute name="min" type="xs:decimal" use="optional"/> - <xs:attribute name="max" type="xs:decimal" use="optional"/> - </xs:complexType> + <xs:element name="page"> + <xs:complexType> + <xs:sequence> + <xs:element ref="title" minOccurs="0" maxOccurs="1" /> + <xs:element name="commentboxprefix" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element ref="interface" minOccurs="1" maxOccurs="unbounded" /> + <xs:element ref="audioelement" minOccurs="1" maxOccurs="unbounded" /> + <xs:element ref="commentquestion" minOccurs="0" maxOccurs="unbounded" /> + <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="hostURL" type="xs:anyURI" default="" /> + <xs:attribute name="randomiseOrder" type="xs:boolean" default="false" /> + <xs:attribute name="repeatCount" type="xs:nonNegativeInteger" default="0" /> + <xs:attribute name="loop" type="xs:boolean" default="false" /> + <xs:attribute name="showElementComments" type="xs:boolean" default="false" /> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute name="label" use="optional" default="default"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="default" /> + <xs:enumeration value="none" /> + <xs:enumeration value="number" /> + <xs:enumeration value="letter" /> + <xs:enumeration value="capital" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="poolSize" /> + <xs:attribute ref="alwaysInclude" /> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> </xs:element> - <xs:element name="scales" minOccurs="0" maxOccurs="1"> - <xs:complexType> - <xs:sequence> - <xs:element name="scalelabel" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute name="position" use="required"> - <xs:simpleType> - <xs:restriction base="xs:nonNegativeInteger"> - <xs:minInclusive value="0"/> - <xs:maxInclusive value="100"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> + + <xs:element name="metric"> + <xs:complexType> + <xs:sequence> + <xs:element name="metricenable" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> </xs:element> - </xs:sequence> - <xs:attribute ref="name" use="optional"/> - </xs:complexType> - </xs:element> - <xs:element name="audioelement"> - <xs:complexType> - <xs:attribute ref="id" use="required"/> - <xs:attribute name="url" type="xs:anyURI" use="required"/> - <xs:attribute name="gain" type="xs:decimal" default="0"/> - <xs:attribute ref="name"/> - <xs:attribute name="type" default="normal"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="normal"/> - <xs:enumeration value="anchor"/> - <xs:enumeration value="reference"/> - <xs:enumeration value="outside-reference"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="marker" use="optional"> - <xs:simpleType> - <xs:restriction base="xs:nonNegativeInteger"> - <xs:minInclusive value="0"/> - <xs:maxInclusive value="100"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional"/> - <xs:attribute ref="preSilence"/> - <xs:attribute ref="postSilence"/> - </xs:complexType> - </xs:element> + <xs:element name="interface"> + <xs:complexType> + <xs:sequence> + <xs:element ref="title" minOccurs="0" maxOccurs="1" /> + <xs:element name="interfaceoption" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:attribute name="type" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="check" /> + <xs:enumeration value="show" /> + <xs:enumeration value="option" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute ref="name" use="required" /> + <xs:attribute name="min" type="xs:decimal" use="optional" /> + <xs:attribute name="max" type="xs:decimal" use="optional" /> + </xs:complexType> + </xs:element> + <xs:element name="scales" minOccurs="0" maxOccurs="1"> + <xs:complexType> + <xs:sequence> + <xs:element name="scalelabel" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="position" use="required"> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="100" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="name" use="optional" /> + </xs:complexType> + </xs:element> - <xs:element name="commentquestion"> - <xs:complexType> - <xs:sequence> - <xs:element ref="statement" minOccurs="0" maxOccurs="1"/> - <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute ref="name"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> + <xs:element name="audioelement"> + <xs:complexType> + <xs:attribute ref="id" use="required" /> + <xs:attribute name="url" type="xs:anyURI" use="required" /> + <xs:attribute name="gain" type="xs:decimal" default="0" /> + <xs:attribute ref="name" /> + <xs:attribute name="type" default="normal"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal" /> + <xs:enumeration value="anchor" /> + <xs:enumeration value="reference" /> + <xs:enumeration value="outside-reference" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="marker" use="optional"> + <xs:simpleType> + <xs:restriction base="xs:nonNegativeInteger"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="100" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> + <xs:attribute ref="alwaysInclude" /> + <xs:attribute ref="preSilence" /> + <xs:attribute ref="postSilence" /> + </xs:complexType> </xs:element> - </xs:sequence> - <xs:attribute ref="id" use="optional"/> - <xs:attribute ref="name" use="optional"/> - <xs:attribute name="type" default="question"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="question"/> - <xs:enumeration value="radio"/> - <xs:enumeration value="checkbox"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:complexType> - </xs:element> - <xs:element name="survey"> - <xs:complexType> - <xs:sequence> - <xs:element name="surveyentry" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:sequence> - <xs:element ref="statement" minOccurs="1" maxOccurs="1"/> - <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute ref="name"/> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - </xs:element> - </xs:sequence> - <xs:attribute ref="id" use="required"/> - <xs:attribute ref="name"/> - <xs:attribute ref="mandatory"/> - <xs:attribute name="min" type="xs:decimal"/> - <xs:attribute name="max" type="xs:decimal"/> - <xs:attribute name="type" use="required"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="statement"/> - <xs:enumeration value="question"/> - <xs:enumeration value="number"/> - <xs:enumeration value="radio"/> - <xs:enumeration value="checkbox"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="boxsize" default="normal"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="normal"/> - <xs:enumeration value="large"/> - <xs:enumeration value="small"/> - <xs:enumeration value="huge"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:complexType> + <xs:element name="commentquestion"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="0" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="id" use="optional" /> + <xs:attribute ref="name" use="optional" /> + <xs:attribute name="type" default="question"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="question" /> + <xs:enumeration value="radio" /> + <xs:enumeration value="checkbox" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> </xs:element> - </xs:sequence> - <xs:attribute name="location"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="before"/> - <xs:enumeration value="pre"/> - <xs:enumeration value="after"/> - <xs:enumeration value="post"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:complexType> - </xs:element> - -</xs:schema> \ No newline at end of file + + <xs:element name="survey"> + <xs:complexType> + <xs:sequence> + <xs:element name="surveyentry" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element ref="statement" minOccurs="1" maxOccurs="1" /> + <xs:element name="option" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute ref="name" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute ref="id" use="required" /> + <xs:attribute ref="name" /> + <xs:attribute ref="mandatory" /> + <xs:attribute name="min" type="xs:decimal" /> + <xs:attribute name="max" type="xs:decimal" /> + <xs:attribute name="type" use="required"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="statement" /> + <xs:enumeration value="question" /> + <xs:enumeration value="number" /> + <xs:enumeration value="radio" /> + <xs:enumeration value="checkbox" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="boxsize" default="normal"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="normal" /> + <xs:enumeration value="large" /> + <xs:enumeration value="small" /> + <xs:enumeration value="huge" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="location"> + <xs:simpleType> + <xs:restriction base="xs:string"> + <xs:enumeration value="before" /> + <xs:enumeration value="pre" /> + <xs:enumeration value="after" /> + <xs:enumeration value="post" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + </xs:complexType> + </xs:element> + + </xs:schema>