Mercurial > hg > webaudioevaluationtool
changeset 1688:a449b8cdfb31
Standalone version.
Movable sliders with rating
Comment boxes
Submission to XML file
TODO:
Click track to listen
author | Nicholas Jillings <nickjillings@users.noreply.github.com> |
---|---|
date | Wed, 25 Mar 2015 12:48:29 +0000 |
parents | 8c942feff9aa |
children | 486b7ee55123 |
files | ape.js core.js |
diffstat | 2 files changed, 171 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/ape.js Tue Mar 24 15:07:11 2015 +0000 +++ b/ape.js Wed Mar 25 12:48:29 2015 +0000 @@ -17,6 +17,7 @@ // The injection point into the HTML page var insertPoint = document.getElementById("topLevelBody"); + // Decode parts of the xmlDoc that are needed // xmlDoc MUST already be parsed by jQuery! var xmlSetup = xmlDoc.find('setup'); @@ -38,6 +39,41 @@ // Insert the titleSpan element into the title div element. title.appendChild(titleSpan); + // Store the return URL path in global projectReturn + projectReturn = xmlSetup[0].attributes['projectReturn'].value; + + // Create Interface buttons! + var interfaceButtons = document.createElement('div'); + interfaceButtons.id = 'interface-buttons'; + + // MANUAL DOWNLOAD POINT + // If project return is null, this MUST be specified as the location to create the download link + var downloadPoint = document.createElement('div'); + downloadPoint.id = 'download-point'; + + // Create playback start/stop points + var playback = document.createElement("button"); + playback.innerText = 'Start'; + playback.onclick = function() { + if (audioEngineContext.status == 0) { + audioEngineContext.play(); + this.innerText = 'Stop'; + } else { + audioEngineContext.stop(); + this.innerText = 'Start'; + } + } + // Create Submit (save) button + var submit = document.createElement("button"); + submit.innerText = 'Submit'; + submit.onclick = function() { + createProjectSave(projectReturn) + } + + interfaceButtons.appendChild(playback); + interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(downloadPoint); + // Now create the slider and HTML5 canvas boxes var sliderBox = document.createElement('div'); @@ -56,8 +92,41 @@ var feedbackHolder = document.createElement('div'); + var tracks = xmlDoc.find('tracks'); + tracks = tracks[0]; + var hostURL = tracks.attributes['hostURL']; + if (hostURL == undefined) { + hostURL = ""; + } else { + hostURL = hostURL.value; + } + + var hostFs = tracks.attributes['sampleRate']; + var hostFsExplicit = tracks.attributes['sampleRateExplicit']; + if (hostFs == undefined) { + hostFsExplicit = false; + } else { + hostFs = hostFs.value; + if (hostFsExplicit != undefined) { + hostFsExplicit = hostFsExplicit.value; + } + } + + /// CHECK FOR SAMPLE RATE COMPATIBILITY + if (hostFsExplicit == true) { + if (Number(hostFs) != audioContext.sampleRate) { + var errStr = 'Sample rates do not match! Requested '+Number(hostFs)+', got '+audioContext.sampleRate+'. Please set the sample rate to match before completing this test.'; + alert(errStr); + return; + } + } + var tracksXML = xmlDoc.find('track'); tracksXML.each(function(index,element){ + // Find URL of track + var trackURL = hostURL + this.attributes['url'].value; + // Now load each track in + audioEngineContext.newTrack(trackURL); var trackObj = document.createElement('div'); var trackTitle = document.createElement('span'); trackTitle.innerText = 'Comment on track '+index; @@ -93,6 +162,7 @@ // Inject into HTML insertPoint.innerHTML = null; // Clear the current schema insertPoint.appendChild(title); // Insert the title + insertPoint.appendChild(interfaceButtons); insertPoint.appendChild(sliderBox); insertPoint.appendChild(feedbackHolder); } @@ -109,3 +179,30 @@ } } } + +// Only other global function which must be defined in the interface class. Determines how to create the XML document. +function interfaceXMLSave(){ + // Create the XML string to be exported with results + var xmlDoc = document.createElement("BrowserEvaluationResult"); + var trackSliderObjects = document.getElementsByClassName('track-slider'); + var commentObjects = document.getElementsByClassName('trackComment'); + var rateMin = 50; + var rateMax = window.innerWidth-50; + for (var i=0; i<trackSliderObjects.length; i++) + { + var trackObj = document.createElement("Track"); + trackObj.id = i; + var slider = document.createElement("Rating"); + var rate = Number(trackSliderObjects[i].style.left.substr(0,trackSliderObjects[i].style.left.length-2)); + rate = (rate-rateMin)/rateMax; + slider.innerText = Math.floor(rate*100); + var comment = document.createElement("Comment"); + comment.innerText = commentObjects[i].value; + trackObj.appendChild(slider); + trackObj.appendChild(comment); + xmlDoc.appendChild(trackObj); + } + + return xmlDoc; +} +
--- a/core.js Tue Mar 24 15:07:11 2015 +0000 +++ b/core.js Wed Mar 25 12:48:29 2015 +0000 @@ -9,6 +9,7 @@ var audioContext; var projectXML; var audioEngineContext; +var projectReturn; window.onload = function() { // Function called once the browser has loaded all files. @@ -16,7 +17,7 @@ // Create a web audio API context // NORE: Currently this will only work with webkit browsers (Chrome/Safari)! - audioContext = new webkitAudioContext; + audioContext = new AudioContext; // Create the audio engine object audioEngineContext = new AudioEngine(); @@ -52,6 +53,23 @@ function createProjectSave(destURL) { // Save the data from interface into XML and send to destURL // If destURL is null then download XML in client + // Now time to render file locally + var xmlDoc = interfaceXMLSave(); + if (destURL == "null" || destURL == undefined) { + var parent = document.createElement("div"); + parent.appendChild(xmlDoc); + var file = [parent.innerHTML]; + var bb = new Blob(file,{type : 'application/xml'}); + var dnlk = window.URL.createObjectURL(bb); + var a = document.createElement("a"); + a.hidden = ''; + a.href = dnlk; + a.download = "save.xml"; + a.textContent = "Save File"; + + var submitDiv = document.getElementById('download-point'); + submitDiv.appendChild(a); + } } function AudioEngine() { @@ -64,6 +82,9 @@ this.fooGain = audioContext.createGain(); this.fooGain.gain = 0; + // Use this to detect playback state: 0 - stopped, 1 - playing + this.status = 0; + // Connect both gains to output this.outputGain.connect(audioContext.destination); this.fooGain.connect(audioContext.destination); @@ -74,32 +95,42 @@ this.play = function() { // Send play command to all playback buffers for synchronised start // Also start timer callbacks to detect if playback has finished + if (this.status == 0) { + // First get current clock + var timer = audioContext.currentTime; + // Add 3 seconds + timer += 3.0; + + // Send play to all tracks + for (var i=0; i<this.audioObjects.length; i++) + { + this.audioObjects[i].play(timer); + } + this.status = 1; + } } this.stop = function() { // Send stop and reset command to all playback buffers + if (this.status == 1) { + for (var i=0; i<this.audioObjects.length; i++) + { + this.audioObjects[i].stop(); + } + this.status = 0; + } } this.newTrack = function(url) { // Pull data from given URL into new audio buffer // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin' - var request = new XMLHttpRequest(); - request.open('GET',url,true); - request.responseType = 'arraybuffer'; + // Create the audioObject with ID of the new track length; audioObjectId = this.audioObjects.length this.audioObjects[audioObjectId] = new audioObject(audioObjectId); - - // Create callback to decode the data asynchronously - request.onload = function() { - audioContext.decodeAudioData(request.response, function(decodedData) { - audioObj = audioEngineContext.audioObjects[audioObjectId]; - audioObj.buffer = decodedData; - audioObj.bufferNode.buffer = audioObj.buffer; - audioObj.state = 1; - }, console.log("Err - Buffer not added to " + audioObjectId)); - } - request.send(); + + // AudioObject will get track itself. + this.audioObjects[audioObjectId].constructTrack(url); } } @@ -131,6 +162,33 @@ this.bufferNode = audioContext.createBufferSource(); this.bufferNode.connect(this.outputGain); this.bufferNode.buffer = this.buffer; + this.bufferNode.loop = true; } -} + this.constructTrack = function(url) { + var request = new XMLHttpRequest(); + request.open('GET',url,true); + request.responseType = 'arraybuffer'; + + var audioObj = this; + + // Create callback to decode the data asynchronously + request.onloadend = function() { + audioContext.decodeAudioData(request.response, function(decodedData) { + audioObj.buffer = decodedData; + audioObj.bufferNode.buffer = audioObj.buffer; + audioObj.bufferNode.loop = true; + audioObj.state = 1; + }, function(){ + // Should only be called if there was an error, but sometimes gets called continuously + // Check here if the error is genuine + if (audioObj.state == 0 || audioObj.buffer == undefined) { + // Genuine error + console.log('FATAL - Error loading buffer on '+audioObj.id); + } + }); + } + request.send(); + } + +} \ No newline at end of file