changeset 2603:1c8aac0ee5e9

Merge master into vnext
author Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk>
date Mon, 14 Nov 2016 14:45:39 +0000
parents afeda52bcd53 (diff) 6ff61a4f62a8 (current diff)
children 8188efa9415d 5dfb7d954bb2
files interfaces/AB.js js/core.js js/specification.js tests/examples/APE_example.xml xml/test-schema.xsd
diffstat 7 files changed, 147 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/interfaces/AB.js	Mon Nov 14 14:41:12 2016 +0000
+++ b/interfaces/AB.js	Mon Nov 14 14:45:39 2016 +0000
@@ -316,7 +316,7 @@
             if (this.parent.specification.parent.playOne || specification.playOne) {
                 $('.comparator-button').text('Wait');
                 $('.comparator-button').attr("disabled", "true");
-                $(this.playback).removeAttr("disabled");
+                $(this.playback).css("disabled", "false");
             } else {
                 $('.comparator-button').text('Listen');
             }
@@ -352,6 +352,46 @@
     this.selected = null;
 
     // First generate the Audio Objects for the Audio Engine
+    var label = audioHolderObject.labelStart;
+    if (label == "") {
+        switch (audioHolderObject.label) {
+            case "number":
+                label = "1";
+                break;
+            case "letter":
+                label = "a";
+                break;
+            case "none":
+                label = "";
+                break;
+            case "capital":
+            default:
+                label = "A";
+                break;
+        }
+    } else {
+        switch (audioHolderObject.label) {
+            case "number":
+                if (!isFinite(Number(label))) {
+                    label = "1";
+                }
+                break;
+            case "letter":
+                if (label.charCodeAt(0) < 97 || label.charCodeAt(0) > 122) {
+                    label = "a";
+                }
+                break;
+            case "none":
+                label = "";
+                break;
+            case "capital":
+            default:
+                if (label.charCodeAt(0) < 65 || label.charCodeAt(0) > 90) {
+                    label = "A";
+                }
+                break;
+        }
+    }
     for (var index = 0; index < audioHolderObject.audioElements.length; index++) {
         var element = audioHolderObject.audioElements[index];
         var audioObject = audioEngineContext.newTrack(element);
@@ -359,22 +399,22 @@
             var orNode = new interfaceContext.outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder"));
             audioObject.bindInterface(orNode);
         } else {
-            var label;
-            switch (audioObject.specification.parent.label) {
+            var node = new this.comparatorBox(audioObject, index, label);
+            switch (audioHolderObject.label) {
                 case "none":
                     label = "";
                     break;
                 case "number":
-                    label = "" + index;
+                    label = (Number(label) + 1).toString(10);
                     break;
                 case "letter":
-                    label = String.fromCharCode(97 + index);
+                    label = String.fromCharCode((label.charCodeAt(0) - 96) % 26 + 97);
                     break;
+                case "capital":
                 default:
-                    label = String.fromCharCode(65 + index);
+                    label = String.fromCharCode((label.charCodeAt(0) - 64) % 26 + 65);
                     break;
             }
-            var node = new this.comparatorBox(audioObject, index, label);
             audioObject.bindInterface(node);
             this.comparators.push(node);
             this.boxHolders.appendChild(node.box);
--- a/interfaces/timeline.js	Mon Nov 14 14:41:12 2016 +0000
+++ b/interfaces/timeline.js	Mon Nov 14 14:45:39 2016 +0000
@@ -506,7 +506,7 @@
                     break;
             }
             if (checkState == false) {
-                canContinue == false;
+                canContinue = false;
             }
         }
         if (!canContinue) {
--- a/js/core.js	Mon Nov 14 14:41:12 2016 +0000
+++ b/js/core.js	Mon Nov 14 14:45:39 2016 +0000
@@ -922,6 +922,33 @@
             console.log("Checkbox: " + node.specification.statement);
             var inputs = this.popupResponse.getElementsByTagName('input');
             node.response = [];
+            var numChecked = 0;
+            for (var i = 0; i < node.specification.options.length; i++) {
+                if (inputs[i].checked) {
+                    numChecked++;
+                }
+            }
+            if (node.specification.min != undefined) {
+                if (node.specification.max == undefined) {
+                    if (numChecked < node.specification.min) {
+                        var msg = "You must select at least " + node.specification.min + " option";
+                        if (node.specification.min > 1) {
+                            msg += "s";
+                        }
+                        interfaceContext.lightbox.post("Error", msg);
+                        return;
+                    }
+                } else {
+                    if (numChecked < node.specification.min || numChecked > node.specification.max) {
+                        if (node.specification.min == node.specification.max) {
+                            interfaceContext.lightbox.post("Error", "You must only select " + node.specification.min);
+                        } else {
+                            interfaceContext.lightbox.post("Error", "You must select between " + node.specification.min + " and " + node.specification.max);
+                        }
+                        return;
+                    }
+                }
+            }
             for (var i = 0; i < node.specification.options.length; i++) {
                 node.response.push({
                     name: node.specification.options[i].name,
@@ -1694,21 +1721,20 @@
     };
 
     this.setSynchronousLoop = function () {
-        // Pads the signals so they are all exactly the same length
-        // Get the length of the longest signal.
-        var length = 0;
+        // Pads the signals so they are all exactly the same duration
+        // Get the duration of the longest signal.
+        var duration = 0;
         var maxId;
         for (var i = 0; i < this.audioObjects.length; i++) {
-            if (length < this.audioObjects[i].buffer.buffer.length) {
-                length = this.audioObjects[i].buffer.buffer.length;
+            if (duration < this.audioObjects[i].buffer.buffer.duration) {
+                duration = this.audioObjects[i].buffer.buffer.duration;
                 maxId = i;
             }
         }
         // Extract the audio and zero-pad
         for (var ao of this.audioObjects) {
-            var lengthDiff = length - ao.buffer.buffer.length;
-            if (lengthDiff > 0) {
-                ao.buffer.buffer = ao.buffer.copyBuffer(0, samplesToSeconds(lengthDiff, ao.buffer.buffer.sampleRate));
+            if (ao.buffer.buffer.duration !== duration) {
+                ao.buffer.buffer = ao.buffer.copyBuffer(0, duration - ao.buffer.buffer.duration);
             }
         }
     };
@@ -3263,8 +3289,10 @@
                     break;
                 case "radio":
                     var child = this.parent.document.createElement('response');
-                    child.setAttribute('name', node.response.name);
-                    child.textContent = node.response.text;
+                    if (node.response !== null) {
+                        child.setAttribute('name', node.response.name);
+                        child.textContent = node.response.text;
+                    }
                     surveyresult.appendChild(child);
                     break;
                 case "checkbox":
--- a/js/specification.js	Mon Nov 14 14:41:12 2016 +0000
+++ b/js/specification.js	Mon Nov 14 14:45:39 2016 +0000
@@ -275,6 +275,16 @@
                 }
                 switch (this.type) {
                     case "checkbox":
+                        if (this.min != undefined) {
+                            node.setAttribute("min", this.min);
+                        } else {
+                            node.setAttribute("min", "0");
+                        }
+                        if (this.max != undefined) {
+                            node.setAttribute("max", this.max);
+                        } else {
+                            node.setAttribute("max", "undefined");
+                        }
                     case "radio":
                         for (var i = 0; i < this.options.length; i++) {
                             var option = this.options[i];
@@ -283,6 +293,7 @@
                             optionNode.textContent = option.text;
                             node.appendChild(optionNode);
                         }
+                        break;
                     case "number":
                         if (this.min != undefined) {
                             node.setAttribute("min", this.min);
@@ -290,6 +301,7 @@
                         if (this.max != undefined) {
                             node.setAttribute("max", this.max);
                         }
+                        break;
                     case "question":
                         if (this.boxsize != undefined) {
                             node.setAttribute("boxsize", this.boxsize);
@@ -297,6 +309,16 @@
                         if (this.mandatory != undefined) {
                             node.setAttribute("mandatory", this.mandatory);
                         }
+                        break;
+                    case "video":
+                        if (this.mandatory != undefined) {
+                            node.setAttribute("mandatory", this.mandatory);
+                        }
+                    case "youtube":
+                        if (this.url != undefined) {
+                            node.setAttribute("url", this.url);
+                        }
+                        break;
                     default:
                         break;
                 }
@@ -459,6 +481,7 @@
         this.outsideReference = null;
         this.loudness = null;
         this.label = null;
+        this.labelStart = "";
         this.preTest = null;
         this.postTest = null;
         this.interfaces = [];
--- a/python/generate_report.py	Mon Nov 14 14:41:12 2016 +0000
+++ b/python/generate_report.py	Mon Nov 14 14:45:39 2016 +0000
@@ -120,9 +120,10 @@
 
 # generate images for later use
 if render_figures:
-    subprocess.call("python timeline_view_movement.py '"+folder_name+"'", shell=True)
-    subprocess.call("python score_parser.py '"+folder_name+"'", shell=True)
-    subprocess.call("python score_plot.py '"+folder_name+"ratings/'", shell=True)
+    script_path = os.path.dirname(os.path.realpath(__file__)) # where is generate_report.py?
+    subprocess.call("python " +script_path+"/timeline_view_movement.py '"+folder_name+"'", shell=True)
+    subprocess.call("python " +script_path+"/score_parser.py '"+folder_name+"'", shell=True)
+    subprocess.call("python " +script_path+"/score_plot.py '"+folder_name+"ratings/'", shell=True)
 
 # make array of text and array of dates
 body_array = []
--- a/python/timeline_view_movement.py	Mon Nov 14 14:41:12 2016 +0000
+++ b/python/timeline_view_movement.py	Mon Nov 14 14:45:39 2016 +0000
@@ -124,9 +124,10 @@
                     stop_times_global  = []
                     listen_events = audioelement.findall("./metric/metricresult/[@name='elementListenTracker']/event")
                     for event in listen_events:
-                        # get testtime: start and stop
-                        start_times_global.append(float(event.find('testtime').get('start')))#-time_offset)
-                        stop_times_global.append(float(event.find('testtime').get('stop')))#-time_offset)
+                        if event.find('testtime') is not None:
+                            # get testtime: start and stop
+                            start_times_global.append(float(event.find('testtime').get('start')))#-time_offset)
+                            stop_times_global.append(float(event.find('testtime').get('stop')))#-time_offset)
                     
                     # display fragment name at start
                     plt.text(0,initial_position+0.02,audio_id,color=colormap[increment%len(colormap)]) #,rotation=45
@@ -289,12 +290,35 @@
                 plt.ylabel('Rating') # default
                 plt.ylim(0, 1) # rating between 0 and 1
 
-                # TO DO: 
-                # Y axis title and tick labels as specified in 'setup' for corresponding page
+                # Y axis title and tick labels as specified in 'setup'
+                # for corresponding page
+                page_setup = root.find("./waet/page[@id='"+page_name+"']") 
+                    # 'ref' of page is 'id' in page setup
+
                 # Different plots for different axes
+                interfaces = page_setup.findall("./interface")
+                interface_title = interfaces[0].find("./title")
+                scales = interfaces[0].findall("./scales") # get first interface by default
+                scalelabels = scales[0].findall("./scalelabel") # get first scale by default
+
+                labelpos = [] # array of scalelabel positions
+                labelstr = [] # array of strings at labels
+                for scalelabel in scalelabels:
+                    labelpos.append(float(scalelabel.get('position'))/100.0)
+                    labelstr.append(scalelabel.text)
+
+                # use interface name as Y axis label
+                if interface_title is not None:
+                    plt.ylabel(interface_title.text)
+                else:
+                    plt.ylabel('Rating') # default
+
+                if len(labelpos):
+                    plt.yticks(labelpos, labelstr)
             
                 #plt.show() # uncomment to show plot; comment when just saving
                 #exit()
             
+                # save as PDF
                 plt.savefig(timeline_folder+subject_id+"-"+page_name+".pdf", bbox_inches='tight')
                 plt.close()
--- a/test_create/attributes.json	Mon Nov 14 14:41:12 2016 +0000
+++ b/test_create/attributes.json	Mon Nov 14 14:45:39 2016 +0000
@@ -27,5 +27,9 @@
     "postSilence": "Post Silence",
     "poolSize": "Pool Size",
     "alwaysInclude": "Always Include",
-    "crossFade": "Cross Fade"
+    "crossFade": "Cross Fade",
+    "check": "Check",
+    "value": "Value",
+    "jumpToOnPass": "Jump To ID On Pass",
+    "jumpToOnFail": "Jump To ID On Fail"
 }