Wednesday 15 May 2013

javascript - create volume control for web audio -



javascript - create volume control for web audio -

so creating piano through web sound , having problem implementing volume control. whenever key clicked, volume command should dictate @ volume played through. have used code html5rocks , modified own uses. instead of volumesample array have of soundclips loaded buffers array. whenever seek manipulate slider , alter gain of clip, 'cannot read property 'gain' of null. testing through debugger , runs fine until this.gainnode.gain.value = fraction * fraction; portion of code. take @ code , can see missing. i'd phone call attending playsounds(buffer) method, create , connect gain node, , method changevolume @ bottom, actualy alter in gain node happens:

var context; var bufferloader; var buffers = {}; var volumemain = {}; var lowpfilter = {freq_mul: 7000, qual_mul: 30}; var buffers_to_load = { down1: 'mp3/0c.mp3', down2: 'mp3/0cs.mp3', down3: 'mp3/0d.mp3', down4: 'mp3/0ds.mp3', down5: 'mp3/0e.mp3', down6: 'mp3/0f.mp3', down7: 'mp3/0fs.mp3', down8: 'mp3/0g.mp3', down9: 'mp3/0gs.mp3', down10: 'mp3/0a.mp3', down11: 'mp3/0as.mp3', down12: 'mp3/0b.mp3', up13: 'mp3/1c.mp3', up14: 'mp3/1cs.mp3', up15: 'mp3/1d.mp3', up16: 'mp3/1ds.mp3', up17: 'mp3/1e.mp3', up18: 'mp3/1f.mp3', up19: 'mp3/1fs.mp3', up20: 'mp3/1g.mp3', up21: 'mp3/1gs.mp3', up22: 'mp3/1a.mp3', up23: 'mp3/1as.mp3', up24: 'mp3/1b.mp3', beat1: 'mp3/beat1.mp3', beat2: 'mp3/beat2.mp3' }; function loadbuffers() { var names = []; var paths = []; (var name in buffers_to_load) { var path = buffers_to_load[name]; names.push(name); paths.push(path); } bufferloader = new bufferloader(context, paths, function(bufferlist) { (var = 0; < bufferlist.length; i++) { var buffer = bufferlist[i]; var name = names[i]; buffers[name] = buffer; } }); bufferloader.load(); } document.addeventlistener('domcontentloaded', function() { seek { // prepare prefixing window.audiocontext = window.audiocontext || window.webkitaudiocontext; context = new audiocontext(); } catch(e) { alert("web sound api not supported in browser"); } loadbuffers(); }); function playsound(buffer) { var source = context.createbuffersource(); source.buffer = buffer; var filter1 = context.createbiquadfilter(); filter1.type = 0; filter1.frequency.value = 5000; var gainnode = context.creategain(); source.connect(gainnode); source.connect(filter1); gainnode.connect(context.destination); filter1.connect(context.destination); source.start(0); } //volume command volumemain.gainnode = null; volumemain.changevolume = function(element) { var volume = element.value; var fraction = parseint(element.value) / parseint(element.max); this.gainnode.gain.value = fraction * fraction; //error occurs here }; // start off initializing new context. context = new (window.audiocontext || window.webkitaudiocontext)(); if (!context.creategain) context.creategain = context.creategainnode; if (!context.createdelay) context.createdelay = context.createdelaynode; if (!context.createscriptprocessor) context.createscriptprocessor = context.createjavascriptnode; // shim layer settimeout fallback window.requestanimframe = (function(){ homecoming window.requestanimationframe || window.webkitrequestanimationframe || window.mozrequestanimationframe || window.orequestanimationframe || window.msrequestanimationframe || function( callback ){ window.settimeout(callback, 1000 / 60); }; })(); function bufferloader(context, urllist, callback) { this.context = context; this.urllist = urllist; this.onload = callback; this.bufferlist = new array(); this.loadcount = 0; } bufferloader.prototype.loadbuffer = function(url, index) { // load buffer asynchronously var request = new xmlhttprequest(); request.open("get", url, true); request.responsetype = "arraybuffer"; var loader = this; request.onload = function() { // asynchronously decode sound file info in request.response loader.context.decodeaudiodata( request.response, function(buffer) { if (!buffer) { alert('error decoding file data: ' + url); return; } loader.bufferlist[index] = buffer; if (++loader.loadcount == loader.urllist.length) loader.onload(loader.bufferlist); }, function(error) { console.error('decodeaudiodata error', error); } ); } request.onerror = function() { alert('bufferloader: xhr error'); } request.send(); }; bufferloader.prototype.load = function() { (var = 0; < this.urllist.length; ++i) this.loadbuffer(this.urllist[i], i); } lowpfilter.changefrequency = function(element) { // clamp frequency between minimum value (40 hz) , half of // sampling rate. var minvalue = 40; var maxvalue = context.samplerate / 2; // logarithm (base 2) compute how many octaves fall in range. var numberofoctaves = math.log(maxvalue / minvalue) / math.ln2; // compute multiplier 0 1 based on exponential scale. var multiplier = math.pow(2, numberofoctaves * (element.value - 1.0)); // frequency value between min , max. this.filter1.frequency.value = maxvalue * multiplier; }; lowpfilter.changequality = function(element) { this.filter1.q.value = element.value * this.qual_mul; }; lowpfilter.togglefilter = function(element) { this.source.disconnect(0); this.filter1.disconnect(0); // check if want enable filter. if (element.checked) { // connect through filter. this.source.connect(this.filter1); this.filter1.connect(context.destination); } else { // otherwise, connect directly. this.source.connect(context.destination); } }; function beat1() { this.isplaying = false; }; beat1.prototype.play = function() { this.gainnode = context.creategain(); this.source = context.createbuffersource(); this.source.buffer = buffers.beat1; // connect source gain node this.source.connect(this.gainnode); // connect gain node destination this.gainnode.connect(context.destination); // start playback in loop this.source.loop = true; this.source[this.source.start ? 'start' : 'noteon'](0); }; beat1.prototype.changevolume = function(element) { var volume = element.value; var fraction = parseint(element.value) / parseint(element.max); // let's utilize x*x curve (x-squared) since simple linear (x) not // sound good. this.gainnode.gain.value = fraction * fraction; }; beat1.prototype.stop = function() { this.source[this.source.stop ? 'stop' : 'noteoff'](0); }; beat1.prototype.toggle = function() { this.isplaying ? this.stop() : this.play(); this.isplaying = !this.isplaying; }; function beat2() { this.isplaying = false; }; beat2.prototype.play = function() { this.gainnode = context.creategain(); this.source = context.createbuffersource(); this.source.buffer = buffers.beat2; // connect source gain node this.source.connect(this.gainnode); // connect gain node destination this.gainnode.connect(context.destination); // start playback in loop this.source.loop = true; this.source[this.source.start ? 'start' : 'noteon'](0); }; beat2.prototype.changevolume = function(element) { var volume = element.value; var fraction = parseint(element.value) / parseint(element.max); // let's utilize x*x curve (x-squared) since simple linear (x) not // sound good. this.gainnode.gain.value = fraction * fraction; }; beat2.prototype.stop = function() { this.source[this.source.stop ? 'stop' : 'noteoff'](0); }; beat2.prototype.toggle = function() { this.isplaying ? this.stop() : this.play(); this.isplaying = !this.isplaying; };

this create piano , check key clicked , play appropriate sound (seperate js file):

// keyboard creation function window.onload = function () { // keyboard height var keyboard_height = 120; // keyboard width var keyboard_width = 980; // white key color var white_color = 'white'; // black key color var black_color = 'black'; // number of octaves var octaves = 2; // id of containing div var div_id = 'keyboard'; //------------------------------------------------------------ var paper = raphael(div_id, keyboard_width, keyboard_height); // define white key specs var white_width = keyboard_width / 14; // define black key specs var black_width = white_width/2; var black_height = keyboard_height/1.6; var repeat = 0; var keyboard_keys = []; //define white , black key names var wkn = ['c', 'd', 'e', 'f', 'g', 'a', 'b']; var bkn = ['csharp', 'dsharp', 'fsharp', 'gsharp', 'asharp']; //create octave groups (i=0;i<octaves;i++) { //create white keys first (var w=0; w <= 6 ; w++) { keyboard_keys[wkn[w]+i] = paper.rect(white_width*(repeat + w), 0, white_width, keyboard_height).attr("fill", white_color); }; //set multiplier black key placement var bw_multiplier = 1.5; //then black keys on top (var b=0; b <= 4 ; b++) { keyboard_keys[bkn[b]+i] = paper.rect((white_width*repeat) + (black_width*bw_multiplier), 0, black_width, black_height).attr("fill", black_color); bw_multiplier = (b == 1) ? bw_multiplier + 4 : bw_multiplier + 2; }; repeat = repeat + 7; } (var in keyboard_keys) { (function (st) { st.node.onclick = function(event) { var newcolor = '#'+(0x1000000+(math.random())*0xffffff).tostring(16).substr(1,6); st.animate({fill:newcolor}, 100); var testkey = st.paper.getelementbypoint(event.pagex, event.pagey); var indexofkey = testkey.id; if (indexofkey == 0) { playsound(buffers.down1); } else if (indexofkey == 1) { playsound(buffers.down3); } else if (indexofkey == 2) { playsound(buffers.down5); } else if (indexofkey == 3) { playsound(buffers.down6); } else if (indexofkey == 4) { playsound(buffers.down8); } else if (indexofkey == 5) { playsound(buffers.down10); } else if (indexofkey == 6) { playsound(buffers.down12); } else if (indexofkey == 7) { playsound(buffers.down2); } else if (indexofkey == 8) { playsound(buffers.down4); } else if (indexofkey == 9) { playsound(buffers.down7); } else if (indexofkey == 10) { playsound(buffers.down9); } else if (indexofkey == 11) { playsound(buffers.down11); } else if (indexofkey == 12) { playsound(buffers.up13); } else if (indexofkey == 13) { playsound(buffers.up15); } else if (indexofkey == 14) { playsound(buffers.up17); } else if (indexofkey == 15) { playsound(buffers.up18); } else if (indexofkey == 16) { playsound(buffers.up20); } else if (indexofkey == 17) { playsound(buffers.up22); } else if (indexofkey == 18) { playsound(buffers.up24); } else if (indexofkey == 19) { playsound(buffers.up14); } else if (indexofkey == 20) { playsound(buffers.up16) } else if (indexofkey == 21) { playsound(buffers.up19); } else if (indexofkey == 22) { playsound(buffers.up21); } else { playsound(buffers.up23); } }; })(keyboard_keys[i]); } };

here's define range slider volume command in html (don't worry formatted correctly on in code):

<div id="keyboard"> <script> loadbuffers(); var beat1 = new beat1(); var beat2 = new beat2(); </script> </div> <div>volume: <input type="range" min="0" max="100" value="100" oninput="volumemain.changevolume(this);" /></div> <div>low pass filter on: <input type="checkbox" checked="false" oninput="lowpfilter.togglefilter(this);" /> frequency: <input type="range" min="0" max="1" step="0.01" value="1" oninput="lowpfilter.changefrequency(this);" /> quality: <input type="range" min="0" max="1" step="0.01" value="0" oninput="lowpfilter.changequality(this);" /></div> <div>beat 1: <input type="button" onclick="beat1.toggle();" value="play/pause"/> volume: <input type="range" min="0" max="100" value="100" onchange="beat1.changevolume(this);"></div> <div>beat 2: <input type="button" onclick="beat2.toggle();" value="play/pause"/> volume: <input type="range" min="0" max="100" value="100" onchange="beat2.changevolume(this);"></div> </div>

this issue seems volume command beingness used keyboard somehow not beingness able observe sound buffer utilize , modify. code supplied when know source going adjusting volume for, in case of beat1 , beat 2 (those volume controls both work fine). need code able modify volume of source in buffer array. i'm using raphael bundle create keyboard, if helps (it doesn't). phone call attending playsound(buffer) method , volumemain.changevolume functions. none of lowpfilter methods work either 1 time figure out how adjust volume given source method's problem fixed.

edit (update). removes error , allows access gainnode value

var gainnode = context.creategain(); function playsound(buffer) { var source = context.createbuffersource(); source.buffer = buffer; var filter1 = context.createbiquadfilter(); filter1.type = 0; filter1.frequency.value = 5000; source.connect(gainnode); source.connect(filter1); gainnode.connect(context.destination); filter1.connect(context.destination); source.start(audiocontext.currenttime); } //volume command volumemain.changevolume = function(element) { var volume = element.value; var fraction = parseint(element.value) / parseint(element.max); gainnode.gain.value = fraction * fraction; console.log(gainnode.gain.value); // console log of gain value when slider moved };

previous reply

i don't understand problem if want piece of code illustration of setting gain node html range slider here's illustration oscillator. might want little spike test , see if works in code oscillator , seek , apply sound buffer code.

http://jsfiddle.net/vqb9dmrl/

<input id="gainslider" type="range" min="0" max="1" step="0.05" value="0.5"/> var audiocontext = new webkitaudiocontext(); var osc = audiocontext.createoscillator(); osc.start(audiocontext.cueenttime); var gainchan1 = audiocontext.creategain(); osc.connect(gainchan1); gainchan1.connect(audiocontext.destination); var gainslider = document.getelementbyid("gainslider"); gainslider.addeventlistener('change', function() { gainchan1.gain.value = this.value; });

javascript html5 audio web-audio

No comments:

Post a Comment