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>