changeset 2591:c0854362d09d

Merge branch 'master' into vnext
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Wed, 09 Nov 2016 13:48:36 +0000
parents 278e6e54703b (current diff) 21110fddb0af (diff)
children 89f787e2e90c eeb2e6dce5f2
files js/core.js python/generate_report.py tests/examples/APE_example.xml tests/examples/project.xml
diffstat 7 files changed, 338 insertions(+), 241 deletions(-) [+]
line wrap: on
line diff
--- a/js/core.js	Wed Nov 09 13:22:50 2016 +0000
+++ b/js/core.js	Wed Nov 09 13:48:36 2016 +0000
@@ -1611,22 +1611,21 @@
             } else {
                 interfaceContext.playhead.setTimePerPixel(this.audioObjects[id]);
             }
+            var setTime = audioContext.currentTime;
             if (this.synchPlayback && this.loopPlayback) {
                 // Traditional looped playback
-                var setTime = audioContext.currentTime + specification.crossFade;
                 for (var i = 0; i < this.audioObjects.length; i++) {
                     this.audioObjects[i].play(audioContext.currentTime);
                     if (id == i) {
                         this.audioObjects[i].loopStart(setTime);
                     } else {
-                        this.audioObjects[i].loopStop(setTime);
+                        this.audioObjects[i].loopStop(setTime + specification.crossFade);
                     }
                 }
             } else {
-                var setTime = audioContext.currentTime + specification.crossFade;
                 for (var i = 0; i < this.audioObjects.length; i++) {
                     if (i != id) {
-                        this.audioObjects[i].stop(setTime);
+                        this.audioObjects[i].stop(setTime + specification.crossFade);
                     } else if (i == id) {
                         this.audioObjects[id].play(setTime);
                     }
@@ -1871,10 +1870,10 @@
             this.outputGain.gain.cancelScheduledValues(audioContext.currentTime);
             if (!audioEngineContext.loopPlayback || !audioEngineContext.synchPlayback) {
                 this.metric.startListening(audioEngineContext.timer.getTestTime());
-                this.outputGain.gain.setValueAtTime(this.onplayGain, startTime);
+                this.outputGain.gain.linearRampToValueAtTime(this.onplayGain, startTime + specification.crossFade);
                 this.interfaceDOM.startPlayback();
             } else {
-                this.outputGain.gain.setValueAtTime(0.0, startTime);
+                this.outputGain.gain.linearRampToValueAtTime(0.0, startTime);
             }
             if (audioEngineContext.loopPlayback) {
                 this.bufferNode.loopStart = this.specification.startTime || 0;
@@ -1894,7 +1893,7 @@
             this.bufferNode.stop(stopTime);
             this.bufferNode = undefined;
         }
-        this.outputGain.gain.setValueAtTime(0.0, stopTime);
+        this.outputGain.gain.linearRampToValueAtTime(0.0, stopTime);
         this.interfaceDOM.stopPlayback();
     };
 
--- a/python/generate_report.py	Wed Nov 09 13:22:50 2016 +0000
+++ b/python/generate_report.py	Wed Nov 09 13:48:36 2016 +0000
@@ -64,6 +64,10 @@
 gender = []
 age    = []
 
+# diagnostics
+browser  = []
+platform = []
+
 # get username if available
 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
     user = os.environ.get(name)
@@ -162,6 +166,20 @@
         individual_table = '\n' # table with stats for this individual test file
         timeline_plots = '' # plots of timeline (movements and plays)
         
+        # diagnostics: browser
+        vendor = root.find("./navigator/vendor")
+        if vendor is not None and vendor.text is not None:
+            browser.append(vendor.text.replace(',',''))
+        else:
+            browser.append('UNAVAILABLE')
+
+        # diagnostics: platform
+        platform_tag = root.find("./navigator/platform")
+        if platform_tag is not None and platform_tag.text is not None:
+            platform.append(platform_tag.text.replace('_','\_'))
+        else:
+            platform_tag.append('UNAVAILABLE')
+
         # DEMO survey stats
         # get gender
         post_survey = root.find("./survey/[@location='post']")
@@ -535,6 +553,104 @@
         '''
 # problem: some people entered twice? 
 
+
+# pie chart of browser usage
+browsers = ['Google Inc.', 'Apple Computer Inc.', 'UNAVAILABLE']
+# TODO: get the above automatically
+browser_distribution = ''
+for item in browsers:
+    number = browser.count(item)
+    if number>0:
+        browser_distribution += str("{:.2f}".format((100.0*number)/len(browser)))+\
+                               '/'+item.capitalize()+' ('+str(number)+'),\n'
+
+body += r'''
+        % Pie chart of browser distribution
+        \def\angle{0}
+        \def\radius{3}
+        \def\cyclelist{{"orange","blue","red","green"}}
+        \newcount\cyclecount \cyclecount=-1
+        \newcount\ind \ind=-1
+        \begin{figure}[htbp]
+        \begin{center}\begin{tikzpicture}[nodes = {font=\sffamily}]
+        \foreach \percent/\name in {'''+\
+        browser_distribution+\
+        r'''} {\ifx\percent\empty\else               % If \percent is empty, do nothing
+        \global\advance\cyclecount by 1     % Advance cyclecount
+        \global\advance\ind by 1            % Advance list index
+        \ifnum6<\cyclecount                 % If cyclecount is larger than list
+          \global\cyclecount=0              %   reset cyclecount and
+          \global\ind=0                     %   reset list index
+        \fi
+        \pgfmathparse{\cyclelist[\the\ind]} % Get color from cycle list
+        \edef\color{\pgfmathresult}         %   and store as \color
+        % Draw angle and set labels
+        \draw[fill={\color!50},draw={\color}] (0,0) -- (\angle:\radius)
+          arc (\angle:\angle+\percent*3.6:\radius) -- cycle;
+        \node at (\angle+0.5*\percent*3.6:0.7*\radius) {\percent\,\%};
+        \node[pin=\angle+0.5*\percent*3.6:\name]
+          at (\angle+0.5*\percent*3.6:\radius) {};
+        \pgfmathparse{\angle+\percent*3.6}  % Advance angle
+        \xdef\angle{\pgfmathresult}         %   and store in \angle
+        \fi
+        };
+        \end{tikzpicture}
+        \caption{Representation of browsers across subjects}
+        \label{default}
+        \end{center}
+        \end{figure}
+        
+        '''
+
+# pie chart of platform usage
+platforms = ['Win32', 'Win64', 'MacIntel', 'Linux i686', 'Linux x86\_64', 'UNAVAILABLE']
+# TODO: get the above automatically # order alphabetically
+platform_distribution = ''
+for item in platforms:
+    number = platform.count(item)
+    if number>0:
+        platform_distribution += str("{:.2f}".format((100.0*number)/len(platform)))+\
+                               '/'+item.capitalize()+' ('+str(number)+'),\n'
+
+body += r'''
+        % Pie chart of browser distribution
+        \def\angle{0}
+        \def\radius{3}
+        \def\cyclelist{{"orange","blue","red","green","cyan"}}
+        \newcount\cyclecount \cyclecount=-1
+        \newcount\ind \ind=-1
+        \begin{figure}[htbp]
+        \begin{center}\begin{tikzpicture}[nodes = {font=\sffamily}]
+        \foreach \percent/\name in {'''+\
+        platform_distribution+\
+        r'''} {\ifx\percent\empty\else               % If \percent is empty, do nothing
+        \global\advance\cyclecount by 1     % Advance cyclecount
+        \global\advance\ind by 1            % Advance list index
+        \ifnum6<\cyclecount                 % If cyclecount is larger than list
+          \global\cyclecount=0              %   reset cyclecount and
+          \global\ind=0                     %   reset list index
+        \fi
+        \pgfmathparse{\cyclelist[\the\ind]} % Get color from cycle list
+        \edef\color{\pgfmathresult}         %   and store as \color
+        % Draw angle and set labels
+        \draw[fill={\color!50},draw={\color}] (0,0) -- (\angle:\radius)
+          arc (\angle:\angle+\percent*3.6:\radius) -- cycle;
+        \node at (\angle+0.5*\percent*3.6:0.7*\radius) {\percent\,\%};
+        \node[pin=\angle+0.5*\percent*3.6:\name]
+          at (\angle+0.5*\percent*3.6:\radius) {};
+        \pgfmathparse{\angle+\percent*3.6}  % Advance angle
+        \xdef\angle{\pgfmathresult}         %   and store in \angle
+        \fi
+        };
+        \end{tikzpicture}
+        \caption{Representation of platforms across subjects}
+        \label{default}
+        \end{center}
+        \end{figure}
+        
+        '''
+
+
 #TODO
 # time per page in function of number of fragments (plot)
 # time per participant in function of number of pages
--- a/python/score_parser.py	Wed Nov 09 13:22:50 2016 +0000
+++ b/python/score_parser.py	Wed Nov 09 13:48:36 2016 +0000
@@ -26,26 +26,28 @@
 elif not os.access(os.path.dirname(folder_name), os.W_OK):
     #the file does exist but write privileges are not given
     print("No write privileges in folder '"+folder_name+"'.")
+    
 
-    
 # CODE
 
-# remember which files have been opened this time
-file_history = []
+storage = {}
 
-# get every XML file in folder
+# create folder 'ratings' if not yet created
+if not os.path.exists(folder_name + '/ratings'):
+    os.makedirs(folder_name + '/ratings')
+
+# Get every XML file in the folder
 for file_name in os.listdir(folder_name):
-    if file_name.endswith(".xml"):
+    if (file_name.endswith(".xml")):
         tree = ET.parse(folder_name + '/' + file_name)
         root = tree.getroot()
-
-        # get subject ID from XML file
-        subject_id = file_name[:-4] # file name (without extension) as subject ID
-
-        # get list of all pages this subject evaluated
-        for page in root.findall("./page"):    # iterate over pages
-            page_name = page.get('ref') # get page reference ID
-                       
+        
+        subject_id = root.get('key');
+        
+        # get the list of the pages this subject evaluated
+        for page in root.findall("./page"):     # iterate over pages
+            page_name = page.get('ref') # get page ID
+            
             if page_name is None: # ignore 'empty' audio_holders
                 print("WARNING: " + file_name + " contains empty audio holder. (score_parser.py)")
                 break
@@ -53,84 +55,64 @@
             if page.get('state') != "complete":
                 print("WARNING: " + file_name + " contains incomplete page " +page_name+ ". (score_parser.py)")
                 break;
-
-            file_name = folder_name+'/ratings/'+page_name+'-ratings.csv' # score file name
-
-            # create folder 'ratings' if not yet created
-            if not os.path.exists(folder_name + '/ratings'):
-                os.makedirs(folder_name + '/ratings')
-
+            
+            # Check if page in the store
+            if storage.get(page_name) == None:
+                storage[page_name] = {'header':[], 'axis':{}} # add to the store
+            
+            # Get the axis names
+            pageConfig = root.find('./waet/page/[@id="'+page_name+'"]')
+            for interface in pageConfig.findall('./interface'):    # Get the <interface> noeds
+                interfaceName = interface.get("name"); # Get the axis name
+                if interfaceName == None:
+                    interfaceName = "default"   # If name not set, make name 'default'
+                if storage[page_name]['axis'].get(interfaceName) == None:
+                    storage[page_name]['axis'][interfaceName] = {}  # If not in store for page, add empty dict
+                storage[page_name]['axis'][interfaceName][subject_id] = [] # Add the store for the session
+                    
             # header: fragment IDs in 'alphabetical' order
             # go to fragment column, or create new column if it doesn't exist yet
-
-            # get array of audio elements and number of audio elements
-            audiolist = page.findall("./audioelement")
-            n_fragments = len(audiolist)
-
+            
             # get alphabetical array of fragment IDs from this subject's XML
             fragmentnamelist = []    # make empty list
-            for audioelement in audiolist: # iterate over all audioelements
+            for audioelement in page.findall("./audioelement"): # iterate over all audioelements
                 fragmentnamelist.append(audioelement.get('ref')) # add to list
+            
+            fragmentnamelist = sorted(fragmentnamelist);    # Sort the list
+            storage[page_name]['header'] = fragmentnamelist;
+            
+            for fragmentname in fragmentnamelist:
+                audioElement = page.find("./audioelement/[@ref='"+ fragmentname+ "']") # Get the element
+                for value in audioElement.findall('./value'):
+                    axisName = value.get('interface-name')
+                    if axisName == None:
+                        axisName = 'default'
+                    axisStore = storage[page_name]['axis'][axisName]
+                    if hasattr(value, 'text'):
+                        axisStore[subject_id].append(value.text)
+                    else:
+                        axisStore[subject_id].append('')
 
-
-            # if file exists, get header and add any 'new' fragments not yet in the header
-            if os.path.isfile(file_name):
-                with open(file_name, 'r') as readfile:
-                    filereader = csv.reader(readfile, delimiter=',')
-                    headerrow = next(filereader)
-
-                # If file hasn't been opened yet this time, remove all rows except header
-                if file_name not in file_history:
-                    with open(file_name, 'w') as writefile:
-                        filewriter = csv.writer(writefile, delimiter=',')
-                        headerrow = sorted(headerrow)
-                        filewriter.writerow(headerrow)
-                    file_history.append(file_name)
-
-                # Which of the fragments are in fragmentnamelist but not in headerrow?
-                newfragments = list(set(fragmentnamelist)-set(headerrow))
-                newfragments = sorted(newfragments) # new fragments in alphabetical order
-                # If not empty, read file and rewrite adding extra columns
-                if newfragments: # if not empty
-                    with open('temp.csv', 'w') as writefile:
-                        filewriter = csv.writer(writefile, delimiter=',')
-                        filewriter.writerow(headerrow + newfragments) # write new header
-                        with open(file_name, 'r') as readfile:
-                            filereader = csv.reader(readfile, delimiter=',')
-                            next(filereader) # skip header
-                            for row in filereader: # rewrite row plus empty cells for every new fragment name
-                                filewriter.writerow(row + ['']*len(newfragments))
-                    os.rename('temp.csv', file_name) # replace old file with temp file
-                    headerrow = headerrow + newfragments
-                    
-
-            # if file does not exist yet, create file and make header
-            else:
-                headerrow = sorted(fragmentnamelist) # sort alphabetically
-                headerrow.insert(0,'')
-                fragmentnamelist = fragmentnamelist[1:] #HACKY FIX inserting in firstrow also affects fragmentnamelist
-                with open(file_name, 'w') as writefile:
-                    filewriter = csv.writer(writefile, delimiter=',')
-                    filewriter.writerow(headerrow)
-                file_history.append(file_name)
-
-            # open file to write for this page
-            writefile = open(file_name, 'a')
+# Now create the individual files
+for page_name in storage:
+    for axis_name in storage[page_name]['axis']:
+        
+        file_name = folder_name+'/ratings/'+page_name+'-'+axis_name+'-ratings.csv' # score file name
+        
+        # I'm not as elegant, I say burn the files and start again
+        headerrow = list(storage[page_name]['header'])  # Extract the element IDs
+        headerrow.insert(0,'file_keys')
+        with open(file_name, 'w') as writefile:
             filewriter = csv.writer(writefile, delimiter=',')
-
-            # prepare row to be written for this subject for this page
-            ratingrow = [subject_id]
-
-            # get scores related to fragment [id]
-            for fragmentname in headerrow[1:]: # iterate over fragments in header (skip first empty column)
-                elementvalue = page.find("./audioelement/[@ref='"
-                                       + fragmentname
-                                       + "']/value")
-                if hasattr(elementvalue, 'text'): # if rating for this fragment exists
-                    ratingrow.append(elementvalue.text) # add to rating row
-                else: # if this subject has not rated this fragment
-                    ratingrow.append('') # append empty cell
-
-            # write row: [subject ID, rating fragment ID 1, ..., rating fragment ID M]
-            if any(ratingrow[1:]): # append to file if row non-empty (except subject name)
-                filewriter.writerow(ratingrow)
+            filewriter.writerow(headerrow)
+        
+        # open file to write the page
+        writefile = open(file_name, 'a')
+        filewriter = csv.writer(writefile, delimiter=',')
+        
+        for subject_id in storage[page_name]['axis'][axis_name]:
+            entry = [subject_id]
+            for value in storage[page_name]['axis'][axis_name][subject_id]:
+                entry.append(value)
+            filewriter.writerow(entry)
+        writefile.close()
\ No newline at end of file
--- a/tests/examples/AB_example.xml	Wed Nov 09 13:22:50 2016 +0000
+++ b/tests/examples/AB_example.xml	Wed Nov 09 13:48:36 2016 +0000
@@ -14,7 +14,7 @@
 				<option name="researcher">Research in the field of audio</option>
 			</surveyentry>
 			<surveyentry type="statement" id="test-intro">
-				<statement>This is an example of an 'AB'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement>
+				<statement>This is an example of an 'AB'-style test, with two pages, using the test stimuli in 'example_eval/'. The 'playOne' configuration option means a fragment has to be finished playing before another fragment can be auditioned. </statement>
 			</surveyentry>
 		</survey>
 		<survey location="after">
@@ -53,7 +53,7 @@
             <interfaceoption type="show" name='comments'/>
 		</interface>
 	</setup>
-	<page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12">
+	<page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' loudness="-12">
 		<commentboxprefix>Comment on fragment</commentboxprefix>
 		<interface>
 			<title>Depth</title>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/examples/APE_example.xml	Wed Nov 09 13:48:36 2016 +0000
@@ -0,0 +1,143 @@
+<?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' poolSize="2" loudness="-23" calibration="true">
+		<survey location="before">
+			<surveyentry type="question" id="sessionId" mandatory="true">
+				<statement>Please enter your name.</statement>
+                <conditional check="equals" value="John" jumpToOnPass="test-intro" jumpToOnFail="checkboxtest"/>
+			</surveyentry>
+			<surveyentry type="checkbox" id="checkboxtest" mandatory="true" min="2" max="4">
+				<statement>Please select with which activities you have any experience (example checkbox question)</statement>
+				<option name="musician">Playing a musical instrument</option>
+				<option name="soundengineer">Recording or mixing audio</option>
+				<option name="developer">Developing audio software</option>
+				<option name="hwdesigner">Designing or building audio hardware</option>
+				<option name="researcher">Research in the field of audio</option>
+			</surveyentry>
+            <surveyentry type="question" id="instrument" mandatory="false">
+                <statement>What instrument did you play</statement>
+            </surveyentry>
+			<surveyentry type="statement" id="test-intro">
+				<statement>This is an example of an 'APE'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement>
+			</surveyentry>
+		</survey>
+		<survey location="after">
+			<surveyentry type="question" id="location" mandatory="true" boxsize="large">
+				<statement>Please enter your location. (example mandatory text question)</statement>
+			</surveyentry>
+			<surveyentry type="number" id="age" min="0">
+				<statement>Please enter your age (example non-mandatory number question)</statement>
+			</surveyentry>
+			<surveyentry type="radio" id="rating">
+				<statement>Please rate this interface (example radio button question)</statement>
+				<option name="bad">Bad</option>
+				<option name="poor">Poor</option>
+				<option name="good">Good</option>
+				<option name="great">Great</option>
+			</surveyentry>
+			<surveyentry type="statement" id="thankyou">
+				<statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement>
+			</surveyentry>
+		</survey>
+		<metric>
+			<metricenable>testTimer</metricenable>
+			<metricenable>elementTimer</metricenable>
+			<metricenable>elementInitialPosition</metricenable>
+			<metricenable>elementTracker</metricenable>
+			<metricenable>elementFlagListenedTo</metricenable>
+			<metricenable>elementFlagMoved</metricenable>
+			<metricenable>elementListenTracker</metricenable>
+		</metric>
+		<interface>
+			<interfaceoption type="check" name="fragmentMoved"/>
+            <interfaceoption type="check" name="fragmentPlayed"/>
+			<interfaceoption type="check" name="scalerange" min="25" max="75"/>
+			<interfaceoption type="show" name='playhead'/>
+			<interfaceoption type="show" name="page-count"/>
+            <interfaceoption type="show" name="comments"/>
+		</interface>
+	</setup>
+	<page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12">
+		<commentboxprefix>Comment on fragment</commentboxprefix>
+		<interface name="preference">
+            <title>Preference</title>
+			<scales>
+				<scalelabel position="0">Min</scalelabel>
+				<scalelabel position="100">Max</scalelabel>
+				<scalelabel position="50">Middle</scalelabel>
+				<scalelabel position="20">20</scalelabel>
+			</scales>
+		</interface>
+		<interface name="depth">
+			<title>Depth</title>
+			<scales>
+				<scalelabel position="0">Low</scalelabel>
+				<scalelabel position="100">High</scalelabel>
+				<scalelabel position="50">Middle</scalelabel>
+				<scalelabel position="50">Middle</scalelabel>
+			</scales>
+		</interface>
+		<audioelement url="0.wav" id="track-0" type="anchor"/>
+		<audioelement url="1.wav" id="track-1"/>
+		<audioelement url="2.wav" id="track-2"/>
+		<audioelement url="3.wav" id="track-3"/>
+		<audioelement url="4.wav" id="track-4"/>
+		<survey location="before">
+			<surveyentry type="statement" id="test-0-intro">
+				<statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
+			</surveyentry>
+		</survey>
+		<survey location="after">
+			<surveyentry type="question" id="genre-0" mandatory="true">
+				<statement>Please enter the genre.</statement>
+			</surveyentry>
+		</survey>
+	</page>
+	<page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' label="letter">
+        <commentboxprefix>Comment on fragment</commentboxprefix>
+		<interface name="preference">
+			<title>Example Test Question</title>
+			<scales>
+				<scalelabel position="0">Min</scalelabel>
+				<scalelabel position="100">Max</scalelabel>
+				<scalelabel position="50">Middle</scalelabel>
+				<scalelabel position="20">20</scalelabel>
+			</scales>
+		</interface>
+		<audioelement url="0.wav" gain="-6" id="track-5" type="anchor" marker="20"/>
+		<audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80"/>
+		<audioelement url="2.wav" gain="0.0" id="track-7"/>
+		<audioelement url="3.wav" gain="0.0" id="track-8"/>
+		<audioelement url="4.wav" gain="0.0" id="track-9"/>
+		<audioelement url="5.wav" gain="0.0" id="track-10"/>
+		<audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference"/>
+		<commentquestion id='mixingExperience' type="question">
+			<statement>What is your general experience with numbers?</statement>
+		</commentquestion>
+		<commentquestion id="preference" type="radio">
+			<statement>Please enter your overall preference</statement>
+			<option name="worst">Very Bad</option>
+			<option name="bad"></option>
+			<option name="OK">OK</option>
+			<option name="Good"></option>
+			<option name="Great">Great</option>
+		</commentquestion>
+		<commentquestion id="character" type="checkbox">
+			<statement>Please describe the overall character</statement>
+			<option name="funky">Funky</option>
+			<option name="mellow">Mellow</option>
+			<option name="laidback">Laid back</option>
+			<option name="heavy">Heavy</option>
+		</commentquestion>
+		<survey location="before">
+			<surveyentry type="statement" id="test-1-intro">
+				<statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
+			</surveyentry>
+		</survey>
+		<survey location="after">
+			<surveyentry type="question" id="genre-1" mandatory="true">
+				<statement>Please enter the genre.</statement>
+			</surveyentry>
+		</survey>
+	</page>
+</waet>
\ No newline at end of file
--- a/tests/examples/mushra_example.xml	Wed Nov 09 13:22:50 2016 +0000
+++ b/tests/examples/mushra_example.xml	Wed Nov 09 13:48:36 2016 +0000
@@ -94,13 +94,13 @@
 				<scalelabel position="20">20</scalelabel>
 			</scales>
 		</interface>
-		<audioelement url="0.wav" gain="-6" id="track-5" type="anchor" marker="20"/>
+		<audioelement url="0.wav" gain="-6.0" id="track-5" type="anchor" marker="20"/>
 		<audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80"/>
 		<audioelement url="2.wav" gain="0.0" id="track-7"/>
 		<audioelement url="3.wav" gain="0.0" id="track-8"/>
 		<audioelement url="4.wav" gain="0.0" id="track-9"/>
 		<audioelement url="5.wav" gain="0.0" id="track-10"/>
-		<audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference"/>
+		<audioelement url="1.wav" gain="0.0" id="track-11" type="outside-reference"/>
 		<commentquestion id='mixingExperience' type="question">
 			<statement>What is your general experience with numbers?</statement>
 		</commentquestion>
--- a/tests/examples/project.xml	Wed Nov 09 13:22:50 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-<?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' poolSize="2" loudness="-23" calibration="true">
-		<survey location="before">
-			<surveyentry type="question" id="sessionId" mandatory="true">
-				<statement>Please enter your name.</statement>
-                <conditional check="equals" value="John" jumpToOnPass="test-intro" jumpToOnFail="checkboxtest"/>
-			</surveyentry>
-			<surveyentry type="checkbox" id="checkboxtest" mandatory="true" min="2" max="4">
-				<statement>Please select with which activities you have any experience (example checkbox question)</statement>
-				<option name="musician">Playing a musical instrument</option>
-				<option name="soundengineer">Recording or mixing audio</option>
-				<option name="developer">Developing audio software</option>
-				<option name="hwdesigner">Designing or building audio hardware</option>
-				<option name="researcher">Research in the field of audio</option>
-			</surveyentry>
-            <surveyentry type="question" id="instrument" mandatory="false">
-                <statement>What instrument did you play</statement>
-            </surveyentry>
-			<surveyentry type="statement" id="test-intro">
-				<statement>This is an example of an 'APE'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement>
-			</surveyentry>
-		</survey>
-		<survey location="after">
-			<surveyentry type="question" id="location" mandatory="true" boxsize="large">
-				<statement>Please enter your location. (example mandatory text question)</statement>
-			</surveyentry>
-			<surveyentry type="number" id="age" min="0">
-				<statement>Please enter your age (example non-mandatory number question)</statement>
-			</surveyentry>
-			<surveyentry type="radio" id="rating">
-				<statement>Please rate this interface (example radio button question)</statement>
-				<option name="bad">Bad</option>
-				<option name="poor">Poor</option>
-				<option name="good">Good</option>
-				<option name="great">Great</option>
-			</surveyentry>
-			<surveyentry type="statement" id="thankyou">
-				<statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement>
-			</surveyentry>
-		</survey>
-		<metric>
-			<metricenable>testTimer</metricenable>
-			<metricenable>elementTimer</metricenable>
-			<metricenable>elementInitialPosition</metricenable>
-			<metricenable>elementTracker</metricenable>
-			<metricenable>elementFlagListenedTo</metricenable>
-			<metricenable>elementFlagMoved</metricenable>
-			<metricenable>elementListenTracker</metricenable>
-		</metric>
-		<interface>
-			<interfaceoption type="check" name="fragmentMoved"/>
-            <interfaceoption type="check" name="fragmentPlayed"/>
-			<interfaceoption type="check" name="scalerange" min="25" max="75"/>
-			<interfaceoption type="show" name='playhead'/>
-			<interfaceoption type="show" name="page-count"/>
-            <interfaceoption type="show" name="comments"/>
-		</interface>
-	</setup>
-	<page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12">
-		<commentboxprefix>Comment on fragment</commentboxprefix>
-		<interface name="preference">
-            <title>Preference</title>
-			<scales>
-				<scalelabel position="0">Min</scalelabel>
-				<scalelabel position="100">Max</scalelabel>
-				<scalelabel position="50">Middle</scalelabel>
-				<scalelabel position="20">20</scalelabel>
-			</scales>
-		</interface>
-		<interface name="depth">
-			<title>Depth</title>
-			<scales>
-				<scalelabel position="0">Low</scalelabel>
-				<scalelabel position="100">High</scalelabel>
-				<scalelabel position="50">Middle</scalelabel>
-				<scalelabel position="50">Middle</scalelabel>
-			</scales>
-		</interface>
-		<audioelement url="0.wav" id="track-0" type="anchor"/>
-		<audioelement url="1.wav" id="track-1"/>
-		<audioelement url="2.wav" id="track-2"/>
-		<audioelement url="3.wav" id="track-3"/>
-		<audioelement url="4.wav" id="track-4"/>
-		<survey location="before">
-			<surveyentry type="statement" id="test-0-intro">
-				<statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
-			</surveyentry>
-		</survey>
-		<survey location="after">
-			<surveyentry type="question" id="genre-0" mandatory="true">
-				<statement>Please enter the genre.</statement>
-			</surveyentry>
-		</survey>
-	</page>
-	<page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' label="letter">
-        <commentboxprefix>Comment on fragment</commentboxprefix>
-		<interface name="preference">
-			<title>Example Test Question</title>
-			<scales>
-				<scalelabel position="0">Min</scalelabel>
-				<scalelabel position="100">Max</scalelabel>
-				<scalelabel position="50">Middle</scalelabel>
-				<scalelabel position="20">20</scalelabel>
-			</scales>
-		</interface>
-		<audioelement url="0.wav" gain="-6" id="track-5" type="anchor" marker="20"/>
-		<audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80"/>
-		<audioelement url="2.wav" gain="0.0" id="track-7"/>
-		<audioelement url="3.wav" gain="0.0" id="track-8"/>
-		<audioelement url="4.wav" gain="0.0" id="track-9"/>
-		<audioelement url="5.wav" gain="0.0" id="track-10"/>
-		<audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference"/>
-		<commentquestion id='mixingExperience' type="question">
-			<statement>What is your general experience with numbers?</statement>
-		</commentquestion>
-		<commentquestion id="preference" type="radio">
-			<statement>Please enter your overall preference</statement>
-			<option name="worst">Very Bad</option>
-			<option name="bad"></option>
-			<option name="OK">OK</option>
-			<option name="Good"></option>
-			<option name="Great">Great</option>
-		</commentquestion>
-		<commentquestion id="character" type="checkbox">
-			<statement>Please describe the overall character</statement>
-			<option name="funky">Funky</option>
-			<option name="mellow">Mellow</option>
-			<option name="laidback">Laid back</option>
-			<option name="heavy">Heavy</option>
-		</commentquestion>
-		<survey location="before">
-			<surveyentry type="statement" id="test-1-intro">
-				<statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement>
-			</surveyentry>
-		</survey>
-		<survey location="after">
-			<surveyentry type="question" id="genre-1" mandatory="true">
-				<statement>Please enter the genre.</statement>
-			</surveyentry>
-		</survey>
-	</page>
-</waet>
\ No newline at end of file