annotate core.js @ 6:8d9fd0ba13e3

Automatic loading of project from HTML
author Nicholas Jillings <nicholas.jillings@eecs.qmul.ac.uk>
date Tue, 24 Mar 2015 15:07:11 +0000
parents 955d229b8a02
children 6a6272b06d34
rev   line source
nicholas@1 1 /**
nicholas@1 2 * core.js
nicholas@1 3 *
nicholas@1 4 * Main script to run, calls all other core functions and manages loading/store to backend.
nicholas@1 5 * Also contains all global variables.
nicholas@1 6 */
nicholas@1 7
nicholas@1 8 /* create the web audio API context and store in audioContext*/
nicholas@1 9 var audioContext;
nicholas@2 10 var projectXML;
nicholas@1 11 var audioEngineContext;
nicholas@1 12
nicholas@1 13 window.onload = function() {
nicholas@1 14 // Function called once the browser has loaded all files.
nicholas@1 15 // This should perform any initial commands such as structure / loading documents
nicholas@1 16
nicholas@1 17 // Create a web audio API context
nicholas@1 18 // NORE: Currently this will only work with webkit browsers (Chrome/Safari)!
nicholas@1 19 audioContext = new webkitAudioContext;
nicholas@1 20
nicholas@1 21 // Create the audio engine object
nicholas@1 22 audioEngineContext = new AudioEngine();
nicholas@1 23 }
nicholas@1 24
nicholas@1 25 function loadProjectSpec(url) {
nicholas@1 26 // Load the project document from the given URL, decode the XML and instruct audioEngine to get audio data
nicholas@1 27 // If url is null, request client to upload project XML document
nicholas@2 28 var r = new XMLHttpRequest();
nicholas@2 29 r.open('GET',url,true);
nicholas@2 30 r.onload = function() {
nicholas@2 31 loadProjectSpecCallback(r.response);
nicholas@2 32 }
nicholas@2 33 r.send();
nicholas@2 34 }
nicholas@2 35
nicholas@2 36 function loadProjectSpecCallback(response) {
nicholas@2 37 // Function called after asynchronous download of XML project specification
nicholas@2 38 var decode = $.parseXML(response);
nicholas@2 39 projectXML = $(decode);
nicholas@2 40
nicholas@2 41 // Now extract the setup tag
nicholas@2 42 var xmlSetup = projectXML.find('setup');
nicholas@2 43 var interfaceType = xmlSetup[0].attributes['interface'];
nicholas@2 44 var interfaceJS = document.createElement('script');
nicholas@2 45 interfaceJS.setAttribute("type","text/javascript");
nicholas@2 46 if (interfaceType.value == 'APE') {
nicholas@2 47 interfaceJS.setAttribute("src","ape.js");
nicholas@2 48 }
nicholas@2 49 document.getElementsByTagName("head")[0].appendChild(interfaceJS);
nicholas@1 50 }
nicholas@1 51
nicholas@1 52 function createProjectSave(destURL) {
nicholas@1 53 // Save the data from interface into XML and send to destURL
nicholas@1 54 // If destURL is null then download XML in client
nicholas@1 55 }
nicholas@1 56
nicholas@1 57 function AudioEngine() {
nicholas@1 58
nicholas@1 59 // Create two output paths, the main outputGain and fooGain.
nicholas@1 60 // Output gain is default to 1 and any items for playback route here
nicholas@1 61 // Foo gain is used for analysis to ensure paths get processed, but are not heard
nicholas@1 62 // because web audio will optimise and any route which does not go to the destination gets ignored.
nicholas@1 63 this.outputGain = audioContext.createGain();
nicholas@1 64 this.fooGain = audioContext.createGain();
nicholas@1 65 this.fooGain.gain = 0;
nicholas@1 66
nicholas@1 67 // Connect both gains to output
nicholas@1 68 this.outputGain.connect(audioContext.destination);
nicholas@1 69 this.fooGain.connect(audioContext.destination);
nicholas@1 70
nicholas@1 71 // Create store for new audioObjects
nicholas@1 72 this.audioObjects = [];
nicholas@1 73
nicholas@1 74 this.play = function() {
nicholas@1 75 // Send play command to all playback buffers for synchronised start
nicholas@1 76 // Also start timer callbacks to detect if playback has finished
nicholas@1 77 }
nicholas@1 78
nicholas@1 79 this.stop = function() {
nicholas@1 80 // Send stop and reset command to all playback buffers
nicholas@1 81 }
nicholas@1 82
nicholas@1 83 this.newTrack = function(url) {
nicholas@1 84 // Pull data from given URL into new audio buffer
nicholas@1 85 // URLs must either be from the same source OR be setup to 'Access-Control-Allow-Origin'
nicholas@1 86 var request = new XMLHttpRequest();
nicholas@1 87 request.open('GET',url,true);
nicholas@1 88 request.responseType = 'arraybuffer';
nicholas@1 89 // Create the audioObject with ID of the new track length;
nicholas@1 90 audioObjectId = this.audioObjects.length
nicholas@1 91 this.audioObjects[audioObjectId] = new audioObject(audioObjectId);
nicholas@1 92
nicholas@1 93 // Create callback to decode the data asynchronously
nicholas@1 94 request.onload = function() {
nicholas@1 95 audioContext.decodeAudioData(request.response, function(decodedData) {
nicholas@1 96 audioObj = audioEngineContext.audioObjects[audioObjectId];
nicholas@1 97 audioObj.buffer = decodedData;
nicholas@1 98 audioObj.bufferNode.buffer = audioObj.buffer;
nicholas@1 99 audioObj.state = 1;
nicholas@1 100 }, console.log("Err - Buffer not added to " + audioObjectId));
nicholas@1 101 }
nicholas@1 102 request.send();
nicholas@1 103 }
nicholas@1 104
nicholas@1 105 }
nicholas@1 106
nicholas@1 107 function audioObject(id) {
nicholas@1 108 // The main buffer object with common control nodes to the AudioEngine
nicholas@1 109
nicholas@1 110 this.id = id;
nicholas@1 111 this.state = 0; // 0 - no data, 1 - ready
nicholas@1 112
nicholas@1 113 // Create a buffer and external gain control to allow internal patching of effects and volume leveling.
nicholas@1 114 this.bufferNode = audioContext.createBufferSource();
nicholas@1 115 this.outputGain = audioContext.createGain();
nicholas@1 116
nicholas@1 117 // Connect buffer to the audio graph
nicholas@1 118 this.bufferNode.connect(this.outputGain);
nicholas@1 119 this.outputGain.connect(audioEngineContext.outputGain);
nicholas@1 120
nicholas@1 121 // the audiobuffer is not designed for multi-start playback
nicholas@1 122 // When stopeed, the buffer node is deleted and recreated with the stored buffer.
nicholas@1 123 this.buffer;
nicholas@1 124
nicholas@1 125 this.play = function(startTime) {
nicholas@1 126 this.bufferNode.start(startTime);
nicholas@1 127 }
nicholas@1 128
nicholas@1 129 this.stop = function() {
nicholas@1 130 this.bufferNode.stop(0);
nicholas@1 131 this.bufferNode = audioContext.createBufferSource();
nicholas@1 132 this.bufferNode.connect(this.outputGain);
nicholas@1 133 this.bufferNode.buffer = this.buffer;
nicholas@1 134 }
nicholas@1 135
nicholas@1 136 }