nicholas@755: /** nicholas@755: * mushra.js nicholas@755: * Create the MUSHRA interface nicholas@755: */ nicholas@755: nicholas@755: // Once this is loaded and parsed, begin execution nicholas@755: loadInterface(); nicholas@755: nicholas@755: function loadInterface() { nicholas@755: // Get the dimensions of the screen available to the page nicholas@755: var width = window.innerWidth; nicholas@755: var height = window.innerHeight; nicholas@755: nicholas@755: // The injection point into the HTML page nicholas@755: interfaceContext.insertPoint = document.getElementById("topLevelBody"); nicholas@755: var testContent = document.createElement('div'); nicholas@755: testContent.id = 'testContent'; nicholas@755: nicholas@755: // Create the top div for the Title element nicholas@755: var titleAttr = specification.title; nicholas@755: var title = document.createElement('div'); nicholas@755: title.className = "title"; nicholas@755: title.align = "center"; nicholas@755: var titleSpan = document.createElement('span'); nicholas@755: nicholas@755: // Set title to that defined in XML, else set to default nicholas@755: if (titleAttr != undefined) { nicholas@755: titleSpan.textContent = titleAttr; nicholas@755: } else { nicholas@755: titleSpan.textContent = 'Listening test'; nicholas@755: } nicholas@755: // Insert the titleSpan element into the title div element. nicholas@755: title.appendChild(titleSpan); nicholas@755: nicholas@755: var pagetitle = document.createElement('div'); nicholas@755: pagetitle.className = "pageTitle"; nicholas@755: pagetitle.align = "center"; nicholas@755: var titleSpan = document.createElement('span'); nicholas@755: titleSpan.id = "pageTitle"; nicholas@755: pagetitle.appendChild(titleSpan); nicholas@755: nicholas@755: // Create Interface buttons! nicholas@755: var interfaceButtons = document.createElement('div'); nicholas@755: interfaceButtons.id = 'interface-buttons'; nicholas@755: nicholas@755: // Create playback start/stop points nicholas@755: var playback = document.createElement("button"); nicholas@755: playback.innerHTML = 'Stop'; nicholas@755: playback.id = 'playback-button'; nicholas@755: // onclick function. Check if it is playing or not, call the correct function in the nicholas@755: // audioEngine, change the button text to reflect the next state. nicholas@755: playback.onclick = function() { nicholas@755: if (audioEngineContext.status == 1) { nicholas@755: audioEngineContext.stop(); nicholas@755: this.innerHTML = 'Stop'; nicholas@755: var time = audioEngineContext.timer.getTestTime(); nicholas@755: console.log('Stopped at ' + time); // DEBUG/SAFETY nicholas@755: } nicholas@755: }; nicholas@755: // Create Submit (save) button nicholas@755: var submit = document.createElement("button"); nicholas@755: submit.innerHTML = 'Submit'; nicholas@755: submit.onclick = buttonSubmitClick; nicholas@755: submit.id = 'submit-button'; nicholas@755: // Append the interface buttons into the interfaceButtons object. nicholas@755: interfaceButtons.appendChild(playback); nicholas@755: interfaceButtons.appendChild(submit); nicholas@755: nicholas@755: // Create a slider box nicholas@755: var sliderBox = document.createElement('div'); nicholas@755: sliderBox.style.width = "100%"; nicholas@755: sliderBox.style.height = window.innerHeight - 180 + 'px'; nicholas@755: sliderBox.id = 'slider'; nicholas@755: sliderBox.align = "center"; nicholas@755: nicholas@755: // Global parent for the comment boxes on the page nicholas@755: var feedbackHolder = document.createElement('div'); nicholas@755: feedbackHolder.id = 'feedbackHolder'; nicholas@755: nicholas@755: testContent.style.zIndex = 1; nicholas@755: interfaceContext.insertPoint.innerHTML = null; // Clear the current schema nicholas@755: nicholas@755: // Inject into HTML nicholas@755: testContent.appendChild(title); // Insert the title nicholas@755: testContent.appendChild(pagetitle); nicholas@755: testContent.appendChild(interfaceButtons); nicholas@755: testContent.appendChild(sliderBox); nicholas@755: testContent.appendChild(feedbackHolder); nicholas@755: interfaceContext.insertPoint.appendChild(testContent); nicholas@755: nicholas@755: // Load the full interface nicholas@755: testState.initialise(); nicholas@755: testState.advanceState(); nicholas@755: } nicholas@755: nicholas@755: function loadTest(audioHolderObject) nicholas@755: { nicholas@755: var id = audioHolderObject.id; nicholas@755: nicholas@755: var feedbackHolder = document.getElementById('feedbackHolder'); nicholas@755: var interfaceObj = audioHolderObject.interfaces; nicholas@756: if (interfaceObj.length > 1) nicholas@756: { nicholas@756: console.log("WARNING - This interface only supports one node per page. Using first interface node"); nicholas@756: } nicholas@755: nicholas@755: var sliderBox = document.getElementById('slider'); nicholas@755: feedbackHolder.innerHTML = null; nicholas@755: sliderBox.innerHTML = null; nicholas@755: nicholas@755: var commentBoxPrefix = "Comment on track"; nicholas@755: if (interfaceObj.commentBoxPrefix != undefined) { nicholas@755: commentBoxPrefix = interfaceObj.commentBoxPrefix; nicholas@755: } nicholas@755: var loopPlayback = audioHolderObject.loop; nicholas@755: nicholas@755: currentTestHolder = document.createElement('audioHolder'); nicholas@755: currentTestHolder.id = audioHolderObject.id; nicholas@755: currentTestHolder.repeatCount = audioHolderObject.repeatCount; nicholas@755: nicholas@755: $(audioHolderObject.commentQuestions).each(function(index,element) { nicholas@755: var node = interfaceContext.createCommentQuestion(element); nicholas@755: feedbackHolder.appendChild(node.holder); nicholas@755: }); nicholas@755: nicholas@755: // Find all the audioElements from the audioHolder nicholas@755: $(audioHolderObject.audioElements).each(function(index,element){ nicholas@755: // Find URL of track nicholas@755: // In this jQuery loop, variable 'this' holds the current audioElement. nicholas@755: nicholas@755: // Now load each audio sample. First create the new track by passing the full URL nicholas@755: var trackURL = audioHolderObject.hostURL + element.url; nicholas@755: var audioObject = audioEngineContext.newTrack(element); nicholas@755: nicholas@755: var node = interfaceContext.createCommentBox(audioObject); nicholas@755: nicholas@755: // Create a slider per track nicholas@755: audioObject.interfaceDOM = new sliderObject(audioObject); nicholas@755: nicholas@758: if (typeof audioHolderObject.initialPosition === "number") nicholas@758: { nicholas@758: // Set the values nicholas@758: audioObject.interfaceDOM.slider.value = audioHolderObject.initalPosition; nicholas@758: } else { nicholas@758: // Distribute it randomnly nicholas@758: audioObject.interfaceDOM.slider.value = Math.random(); nicholas@758: } nicholas@755: nicholas@755: sliderBox.appendChild(audioObject.interfaceDOM.holder); nicholas@755: audioObject.metric.initialised(audioObject.interfaceDOM.slider.value); nicholas@755: nicholas@755: }); nicholas@755: nicholas@755: // Auto-align nicholas@755: var numObj = audioHolderObject.audioElements.length; nicholas@755: var totalWidth = (numObj-1)*150+100; nicholas@755: var diff = (window.innerWidth - totalWidth)/2; nicholas@755: audioEngineContext.audioObjects[0].interfaceDOM.holder.style.marginLeft = diff + 'px'; nicholas@755: } nicholas@755: nicholas@755: function sliderObject(audioObject) nicholas@755: { nicholas@755: // Constructs the slider object. We use the HTML5 slider object nicholas@755: this.parent = audioObject; nicholas@755: this.holder = document.createElement('div'); nicholas@755: this.title = document.createElement('span'); nicholas@755: this.slider = document.createElement('input'); nicholas@755: this.play = document.createElement('button'); nicholas@755: nicholas@755: this.holder.className = 'track-slider'; nicholas@755: this.holder.style.height = window.innerHeight-200 + 'px'; nicholas@755: this.holder.appendChild(this.title); nicholas@755: this.holder.appendChild(this.slider); nicholas@755: this.holder.appendChild(this.play); nicholas@755: this.holder.align = "center"; nicholas@755: this.holder.style.marginLeft = "50px"; nicholas@755: this.holder.setAttribute('trackIndex',audioObject.id); nicholas@755: nicholas@755: this.title.textContent = audioObject.id; nicholas@755: this.title.style.width = "100%"; nicholas@755: this.title.style.float = "left"; nicholas@755: nicholas@755: this.slider.type = "range"; nicholas@756: this.slider.className = "track-slider-range"; nicholas@755: this.slider.min = "0"; nicholas@755: this.slider.max = "1"; nicholas@755: this.slider.step = "0.01"; nicholas@755: this.slider.setAttribute('orient','vertical'); nicholas@755: this.slider.style.height = window.innerHeight-250 + 'px'; nicholas@755: this.slider.onchange = function() nicholas@755: { nicholas@755: var time = audioEngineContext.timer.getTestTime(); nicholas@755: var id = Number(this.parentNode.getAttribute('trackIndex')); nicholas@755: audioEngineContext.audioObjects[id].metric.moved(time,this.value); nicholas@755: console.log('slider '+id+' moved to '+this.value+' ('+time+')'); nicholas@755: }; nicholas@755: nicholas@759: this.play.textContent = "Loading..."; nicholas@755: this.play.value = audioObject.id; nicholas@755: this.play.style.float = "left"; nicholas@755: this.play.style.width = "100%"; nicholas@756: this.play.disabled = true; nicholas@756: this.play.onclick = function(event) nicholas@755: { nicholas@756: var id = Number(event.srcElement.value); nicholas@756: //audioEngineContext.metric.sliderPlayed(id); nicholas@756: audioEngineContext.play(id); nicholas@756: $(".track-slider").removeClass('track-slider-playing'); nicholas@756: $(event.currentTarget.parentElement).addClass('track-slider-playing'); nicholas@755: }; nicholas@755: nicholas@755: this.enable = function() { nicholas@756: this.play.disabled = false; nicholas@759: this.play.textContent = "Play"; nicholas@756: $(this.slider).removeClass('track-slider-disabled'); nicholas@755: }; nicholas@755: nicholas@755: this.exportXMLDOM = function(audioObject) { nicholas@755: // Called by the audioObject holding this element. Must be present nicholas@755: var node = document.createElement('value'); nicholas@755: node.textContent = this.slider.value; nicholas@755: return node; nicholas@755: }; nicholas@755: this.getValue = function() { nicholas@755: return this.slider.value; nicholas@755: }; nicholas@756: nicholas@757: this.resize = function(event) nicholas@757: { nicholas@757: this.holder.style.height = window.innerHeight-200 + 'px'; nicholas@757: this.slider.style.height = window.innerHeight-250 + 'px'; nicholas@757: } nicholas@759: this.updateLoading = function(progress) nicholas@759: { nicholas@759: progress = String(progress); nicholas@759: progress = progress.substr(0,5); nicholas@759: this.play.textContent = "Loading: "+progress+"%"; nicholas@759: } nicholas@757: nicholas@756: if (this.parent.state == 1) nicholas@756: { nicholas@756: this.enable(); nicholas@756: } nicholas@755: } nicholas@755: nicholas@757: function resizeWindow(event) nicholas@757: { nicholas@757: // Function called when the window has been resized. nicholas@757: // MANDATORY FUNCTION nicholas@757: nicholas@757: // Auto-align nicholas@757: var numObj = audioEngineContext.audioObjects.length; nicholas@757: var totalWidth = (numObj-1)*150+100; nicholas@757: var diff = (window.innerWidth - totalWidth)/2; nicholas@757: document.getElementById('slider').style.height = window.innerHeight - 180 + 'px'; nicholas@757: audioEngineContext.audioObjects[0].interfaceDOM.holder.style.marginLeft = diff + 'px'; nicholas@757: for (var i in audioEngineContext.audioObjects) nicholas@757: { nicholas@757: audioEngineContext.audioObjects[i].interfaceDOM.resize(event); nicholas@757: } nicholas@757: } nicholas@757: nicholas@755: nicholas@755: function buttonSubmitClick() // TODO: Only when all songs have been played! nicholas@755: { nicholas@755: var checks = testState.currentStateMap[testState.currentIndex].interfaces[0].options; nicholas@755: var canContinue = true; nicholas@755: nicholas@755: // Check that the anchor and reference objects are correctly placed nicholas@755: if (interfaceContext.checkHiddenAnchor() == false) {return;} nicholas@755: if (interfaceContext.checkHiddenReference() == false) {return;} nicholas@755: /* nicholas@755: for (var i=0; i