From c3c112aee29a0358e628ba4434592fcbc56135ea Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 24 Sep 2012 17:54:41 -0400 Subject: too-large buffer was the issue --- public/js/grid.js | 18 +- public/js/vendor/Audiolet.js | 680 ++++++++++++++++++++++++++++----------- public/js/vendor/Audiolet.min.js | 252 --------------- 3 files changed, 507 insertions(+), 443 deletions(-) delete mode 100644 public/js/vendor/Audiolet.min.js diff --git a/public/js/grid.js b/public/js/grid.js index eeae315..0a4aece 100644 --- a/public/js/grid.js +++ b/public/js/grid.js @@ -1,6 +1,6 @@ -var bufferSize = 65536 / 2; +var bufferSize = 4096; // 65536 / 2; var sampleRate = 44100; var latency = 1000 * bufferSize / sampleRate; var audioletReady = false; @@ -17,7 +17,7 @@ function Sampler (audiolet, url) { // first get the sample and load it into a buffer var buffer = new AudioletBuffer(1, 0); - buffer.load(sample, false); + buffer.load(url, false); // connect the buffer to a player and set up the objects we need this.trigger = new TriggerControl(this.audiolet); @@ -25,9 +25,9 @@ function Sampler (audiolet, url) { this.gain = new Gain(this.audiolet, 0.80); // trigger -> player -> gain -> OUTPUT - trigger.connect(player, 0, 1); - player.connect(gain); - gain.connect(this.audiolet.output); + this.trigger.connect(this.player, 0, 1); + this.player.connect(this.gain); + this.gain.connect(this.audiolet.output); this.mute = function(){ base.gain.setValue(0); @@ -39,6 +39,7 @@ function Sampler (audiolet, url) { function Sequencer (audiolet, instrument) { var base = this; + this.audiolet = audiolet; this.instrument = instrument; this.pattern = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; @@ -68,7 +69,8 @@ function AudioletApp () { this.sequencers.push(sequencer); } } - + +var Audio = new AudioletApp(); function Grid (app){ var base = this; @@ -84,9 +86,7 @@ function Grid (app){ tick = tempo; } base.toggle = toggle; - - - var Audio = new AudioletApp(); + var tog = 0; var playing = false; diff --git a/public/js/vendor/Audiolet.js b/public/js/vendor/Audiolet.js index b7be12e..66dc9e8 100644 --- a/public/js/vendor/Audiolet.js +++ b/public/js/vendor/Audiolet.js @@ -1,3 +1,18 @@ +/** + * The base audiolet object. Contains an output node which pulls data from + * connected nodes. + * + * @constructor + * @param {Number} [sampleRate=44100] The sample rate to run at. + * @param {Number} [numberOfChannels=2] The number of output channels. + * @param {Number} [bufferSize] Block size. If undefined uses a sane default. + */ +var Audiolet = function(sampleRate, numberOfChannels, bufferSize) { + this.output = new AudioletDestination(this, sampleRate, + numberOfChannels, bufferSize); +}; + + /** * A variable size multi-channel audio buffer. * @@ -835,21 +850,6 @@ AudioletInput.prototype.toString = function() { }; -/** - * The base audiolet object. Contains an output node which pulls data from - * connected nodes. - * - * @constructor - * @param {Number} [sampleRate=44100] The sample rate to run at. - * @param {Number} [numberOfChannels=2] The number of output channels. - * @param {Number} [bufferSize] Block size. If undefined uses a sane default. - */ -var Audiolet = function(sampleRate, numberOfChannels, bufferSize) { - this.output = new AudioletDestination(this, sampleRate, - numberOfChannels, bufferSize); -}; - - /** * Class representing a single output of an AudioletNode * @@ -2599,6 +2599,80 @@ CrossFade.prototype.toString = function() { return 'Cross Fader'; }; +/*! + * @depends ../core/AudioletNode.js + */ + +/** + * Filter for leaking DC offset. Maths is taken from + * https://ccrma.stanford.edu/~jos/filters/DC_Blocker.html + * + * **Inputs** + * + * - Audio + * - Filter coefficient + * + * **Outputs** + * + * - Filtered audio + * + * **Parameters** + * + * - coefficient The filter coefficient. Linked to input 1. + * + * @constructor + * @extends AudioletNode + * @param {Audiolet} audiolet The audiolet object. + * @param {Number} [coefficient=0.995] The initial coefficient. + */ +var DCFilter = function(audiolet, coefficient) { + AudioletNode.call(this, audiolet, 2, 1); + + // Same number of output channels as input channels + this.linkNumberOfOutputChannels(0, 0); + + this.coefficient = new AudioletParameter(this, 1, coefficient || 0.995); + + // Delayed values + this.xValues = []; + this.yValues = []; +}; +extend(DCFilter, AudioletNode); + +/** + * Process samples + */ +DCFilter.prototype.generate = function() { + var coefficient = this.coefficient.getValue(); + var input = this.inputs[0]; + var numberOfChannels = input.samples.length; + for (var i = 0; i < numberOfChannels; i++) { + if (i >= this.xValues.length) { + this.xValues.push(0); + } + if (i >= this.yValues.length) { + this.yValues.push(0); + } + + var x0 = input.samples[i]; + var y0 = x0 - this.xValues[i] + coefficient * this.yValues[i]; + + this.outputs[0].samples[i] = y0; + + this.xValues[i] = x0; + this.yValues[i] = y0; + } +}; + +/** + * toString + * + * @return {String} String representation. + */ +DCFilter.prototype.toString = function() { + return 'DC Filter'; +}; + /*! * @depends ../core/AudioletNode.js */ @@ -2699,80 +2773,6 @@ DampedCombFilter.prototype.toString = function() { return 'Damped Comb Filter'; }; -/*! - * @depends ../core/AudioletNode.js - */ - -/** - * Filter for leaking DC offset. Maths is taken from - * https://ccrma.stanford.edu/~jos/filters/DC_Blocker.html - * - * **Inputs** - * - * - Audio - * - Filter coefficient - * - * **Outputs** - * - * - Filtered audio - * - * **Parameters** - * - * - coefficient The filter coefficient. Linked to input 1. - * - * @constructor - * @extends AudioletNode - * @param {Audiolet} audiolet The audiolet object. - * @param {Number} [coefficient=0.995] The initial coefficient. - */ -var DCFilter = function(audiolet, coefficient) { - AudioletNode.call(this, audiolet, 2, 1); - - // Same number of output channels as input channels - this.linkNumberOfOutputChannels(0, 0); - - this.coefficient = new AudioletParameter(this, 1, coefficient || 0.995); - - // Delayed values - this.xValues = []; - this.yValues = []; -}; -extend(DCFilter, AudioletNode); - -/** - * Process samples - */ -DCFilter.prototype.generate = function() { - var coefficient = this.coefficient.getValue(); - var input = this.inputs[0]; - var numberOfChannels = input.samples.length; - for (var i = 0; i < numberOfChannels; i++) { - if (i >= this.xValues.length) { - this.xValues.push(0); - } - if (i >= this.yValues.length) { - this.yValues.push(0); - } - - var x0 = input.samples[i]; - var y0 = x0 - this.xValues[i] + coefficient * this.yValues[i]; - - this.outputs[0].samples[i] = y0; - - this.xValues[i] = x0; - this.yValues[i] = y0; - } -}; - -/** - * toString - * - * @return {String} String representation. - */ -DCFilter.prototype.toString = function() { - return 'DC Filter'; -}; - /*! * @depends ../core/AudioletNode.js */ @@ -2929,98 +2929,6 @@ DiscontinuityDetector.prototype.toString = function() { }; -/*! - * @depends ../core/AudioletNode.js - */ - -/** - * Delay line with feedback - * - * **Inputs** - * - * - Audio - * - Delay Time - * - Feedback - * - Mix - * - * **Outputs** - * - * - Delayed audio - * - * **Parameters** - * - * - delayTime The delay time in seconds. Linked to input 1. - * - feedback The amount of feedback. Linked to input 2. - * - mix The amount of delay to mix into the dry signal. Linked to input 3. - * - * @constructor - * @extends AudioletNode - * @param {Audiolet} audiolet The audiolet object. - * @param {Number} maximumDelayTime The largest allowable delay time. - * @param {Number} delayTime The initial delay time. - * @param {Number} feedabck The initial feedback amount. - * @param {Number} mix The initial mix amount. - */ -var FeedbackDelay = function(audiolet, maximumDelayTime, delayTime, feedback, - mix) { - AudioletNode.call(this, audiolet, 4, 1); - this.linkNumberOfOutputChannels(0, 0); - this.maximumDelayTime = maximumDelayTime; - this.delayTime = new AudioletParameter(this, 1, delayTime || 1); - this.feedback = new AudioletParameter(this, 2, feedback || 0.5); - this.mix = new AudioletParameter(this, 3, mix || 1); - var bufferSize = maximumDelayTime * this.audiolet.device.sampleRate; - this.buffers = []; - this.readWriteIndex = 0; -}; -extend(FeedbackDelay, AudioletNode); - -/** - * Process samples - */ -FeedbackDelay.prototype.generate = function() { - var input = this.inputs[0]; - var output = this.outputs[0]; - - var sampleRate = this.audiolet.output.device.sampleRate; - - var delayTime = this.delayTime.getValue() * sampleRate; - var feedback = this.feedback.getValue(); - var mix = this.mix.getValue(); - - var numberOfChannels = input.samples.length; - var numberOfBuffers = this.buffers.length; - for (var i = 0; i < numberOfChannels; i++) { - if (i >= numberOfBuffers) { - // Create buffer for channel if it doesn't already exist - var bufferSize = this.maximumDelayTime * sampleRate; - this.buffers.push(new Float32Array(bufferSize)); - } - - var buffer = this.buffers[i]; - - var inputSample = input.samples[i]; - var bufferSample = buffer[this.readWriteIndex]; - - output.samples[i] = mix * bufferSample + (1 - mix) * inputSample; - buffer[this.readWriteIndex] = inputSample + feedback * bufferSample; - } - - this.readWriteIndex += 1; - if (this.readWriteIndex >= delayTime) { - this.readWriteIndex = 0; - } -}; - -/** - * toString - * - * @return {String} String representation. - */ -FeedbackDelay.prototype.toString = function() { - return 'Feedback Delay'; -}; - /*! * @depends ../core/AudioletNode.js */ @@ -3157,6 +3065,98 @@ FFT.prototype.toString = function() { return 'FFT'; }; +/*! + * @depends ../core/AudioletNode.js + */ + +/** + * Delay line with feedback + * + * **Inputs** + * + * - Audio + * - Delay Time + * - Feedback + * - Mix + * + * **Outputs** + * + * - Delayed audio + * + * **Parameters** + * + * - delayTime The delay time in seconds. Linked to input 1. + * - feedback The amount of feedback. Linked to input 2. + * - mix The amount of delay to mix into the dry signal. Linked to input 3. + * + * @constructor + * @extends AudioletNode + * @param {Audiolet} audiolet The audiolet object. + * @param {Number} maximumDelayTime The largest allowable delay time. + * @param {Number} delayTime The initial delay time. + * @param {Number} feedabck The initial feedback amount. + * @param {Number} mix The initial mix amount. + */ +var FeedbackDelay = function(audiolet, maximumDelayTime, delayTime, feedback, + mix) { + AudioletNode.call(this, audiolet, 4, 1); + this.linkNumberOfOutputChannels(0, 0); + this.maximumDelayTime = maximumDelayTime; + this.delayTime = new AudioletParameter(this, 1, delayTime || 1); + this.feedback = new AudioletParameter(this, 2, feedback || 0.5); + this.mix = new AudioletParameter(this, 3, mix || 1); + var bufferSize = maximumDelayTime * this.audiolet.device.sampleRate; + this.buffers = []; + this.readWriteIndex = 0; +}; +extend(FeedbackDelay, AudioletNode); + +/** + * Process samples + */ +FeedbackDelay.prototype.generate = function() { + var input = this.inputs[0]; + var output = this.outputs[0]; + + var sampleRate = this.audiolet.output.device.sampleRate; + + var delayTime = this.delayTime.getValue() * sampleRate; + var feedback = this.feedback.getValue(); + var mix = this.mix.getValue(); + + var numberOfChannels = input.samples.length; + var numberOfBuffers = this.buffers.length; + for (var i = 0; i < numberOfChannels; i++) { + if (i >= numberOfBuffers) { + // Create buffer for channel if it doesn't already exist + var bufferSize = this.maximumDelayTime * sampleRate; + this.buffers.push(new Float32Array(bufferSize)); + } + + var buffer = this.buffers[i]; + + var inputSample = input.samples[i]; + var bufferSample = buffer[this.readWriteIndex]; + + output.samples[i] = mix * bufferSample + (1 - mix) * inputSample; + buffer[this.readWriteIndex] = inputSample + feedback * bufferSample; + } + + this.readWriteIndex += 1; + if (this.readWriteIndex >= delayTime) { + this.readWriteIndex = 0; + } +}; + +/** + * toString + * + * @return {String} String representation. + */ +FeedbackDelay.prototype.toString = function() { + return 'Feedback Delay'; +}; + /*! * @depends ../core/AudioletNode.js */ @@ -5634,6 +5634,322 @@ var EqualTemperamentTuning = function(pitchesPerOctave) { }; extend(EqualTemperamentTuning, Tuning); +function AudioFileRequest(url, async) { + this.url = url; + if (typeof async == 'undefined' || async == null) { + async = true; + } + this.async = async; + var splitURL = url.split('.'); + this.extension = splitURL[splitURL.length - 1].toLowerCase(); +} + +AudioFileRequest.prototype.onSuccess = function(decoded) { +}; + +AudioFileRequest.prototype.onFailure = function(decoded) { +}; + + +AudioFileRequest.prototype.send = function() { + if (this.extension != 'wav' && + this.extension != 'aiff' && + this.extension != 'aif') { + this.onFailure(); + return; + } + + var request = new XMLHttpRequest(); + request.open('GET', this.url, this.async); + request.overrideMimeType('text/plain; charset=x-user-defined'); + request.onreadystatechange = function(event) { + if (request.readyState == 4) { + if (request.status == 200 || request.status == 0) { + this.handleResponse(request.responseText); + } + else { + this.onFailure(); + } + } + }.bind(this); + request.send(null); +}; + +AudioFileRequest.prototype.handleResponse = function(data) { + var decoder, decoded; + if (this.extension == 'wav') { + decoder = new WAVDecoder(); + decoded = decoder.decode(data); + } + else if (this.extension == 'aiff' || this.extension == 'aif') { + decoder = new AIFFDecoder(); + decoded = decoder.decode(data); + } + this.onSuccess(decoded); +}; + + +function Decoder() { +} + +Decoder.prototype.readString = function(data, offset, length) { + return data.slice(offset, offset + length); +}; + +Decoder.prototype.readIntL = function(data, offset, length) { + var value = 0; + for (var i = 0; i < length; i++) { + value = value + ((data.charCodeAt(offset + i) & 0xFF) * + Math.pow(2, 8 * i)); + } + return value; +}; + +Decoder.prototype.readChunkHeaderL = function(data, offset) { + var chunk = {}; + chunk.name = this.readString(data, offset, 4); + chunk.length = this.readIntL(data, offset + 4, 4); + return chunk; +}; + +Decoder.prototype.readIntB = function(data, offset, length) { + var value = 0; + for (var i = 0; i < length; i++) { + value = value + ((data.charCodeAt(offset + i) & 0xFF) * + Math.pow(2, 8 * (length - i - 1))); + } + return value; +}; + +Decoder.prototype.readChunkHeaderB = function(data, offset) { + var chunk = {}; + chunk.name = this.readString(data, offset, 4); + chunk.length = this.readIntB(data, offset + 4, 4); + return chunk; +}; + +Decoder.prototype.readFloatB = function(data, offset) { + var expon = this.readIntB(data, offset, 2); + var range = 1 << 16 - 1; + if (expon >= range) { + expon |= ~(range - 1); + } + + var sign = 1; + if (expon < 0) { + sign = -1; + expon += range; + } + + var himant = this.readIntB(data, offset + 2, 4); + var lomant = this.readIntB(data, offset + 6, 4); + var value; + if (expon == himant == lomant == 0) { + value = 0; + } + else if (expon == 0x7FFF) { + value = Number.MAX_VALUE; + } + else { + expon -= 16383; + value = (himant * 0x100000000 + lomant) * Math.pow(2, expon - 63); + } + return sign * value; +}; + +function WAVDecoder(data) { +} + +WAVDecoder.prototype.__proto__ = Decoder.prototype; + +WAVDecoder.prototype.decode = function(data) { + var decoded = {}; + var offset = 0; + // Header + var chunk = this.readChunkHeaderL(data, offset); + offset += 8; + if (chunk.name != 'RIFF') { + console.error('File is not a WAV'); + return null; + } + + var fileLength = chunk.length; + fileLength += 8; + + var wave = this.readString(data, offset, 4); + offset += 4; + if (wave != 'WAVE') { + console.error('File is not a WAV'); + return null; + } + + while (offset < fileLength) { + var chunk = this.readChunkHeaderL(data, offset); + offset += 8; + if (chunk.name == 'fmt ') { + // File encoding + var encoding = this.readIntL(data, offset, 2); + offset += 2; + + if (encoding != 0x0001) { + // Only support PCM + console.error('Cannot decode non-PCM encoded WAV file'); + return null; + } + + // Number of channels + var numberOfChannels = this.readIntL(data, offset, 2); + offset += 2; + + // Sample rate + var sampleRate = this.readIntL(data, offset, 4); + offset += 4; + + // Ignore bytes/sec - 4 bytes + offset += 4; + + // Ignore block align - 2 bytes + offset += 2; + + // Bit depth + var bitDepth = this.readIntL(data, offset, 2); + var bytesPerSample = bitDepth / 8; + offset += 2; + } + + else if (chunk.name == 'data') { + // Data must come after fmt, so we are okay to use it's variables + // here + var length = chunk.length / (bytesPerSample * numberOfChannels); + var channels = []; + for (var i = 0; i < numberOfChannels; i++) { + channels.push(new Float32Array(length)); + } + + for (var i = 0; i < numberOfChannels; i++) { + var channel = channels[i]; + for (var j = 0; j < length; j++) { + var index = offset; + index += (j * numberOfChannels + i) * bytesPerSample; + // Sample + var value = this.readIntL(data, index, bytesPerSample); + // Scale range from 0 to 2**bitDepth -> -2**(bitDepth-1) to + // 2**(bitDepth-1) + var range = 1 << bitDepth - 1; + if (value >= range) { + value |= ~(range - 1); + } + // Scale range to -1 to 1 + channel[j] = value / range; + } + } + offset += chunk.length; + } + else { + offset += chunk.length; + } + } + decoded.sampleRate = sampleRate; + decoded.bitDepth = bitDepth; + decoded.channels = channels; + decoded.length = length; + return decoded; +}; + + +function AIFFDecoder() { +} + +AIFFDecoder.prototype.__proto__ = Decoder.prototype; + +AIFFDecoder.prototype.decode = function(data) { + var decoded = {}; + var offset = 0; + // Header + var chunk = this.readChunkHeaderB(data, offset); + offset += 8; + if (chunk.name != 'FORM') { + console.error('File is not an AIFF'); + return null; + } + + var fileLength = chunk.length; + fileLength += 8; + + var aiff = this.readString(data, offset, 4); + offset += 4; + if (aiff != 'AIFF') { + console.error('File is not an AIFF'); + return null; + } + + while (offset < fileLength) { + var chunk = this.readChunkHeaderB(data, offset); + offset += 8; + if (chunk.name == 'COMM') { + // Number of channels + var numberOfChannels = this.readIntB(data, offset, 2); + offset += 2; + + // Number of samples + var length = this.readIntB(data, offset, 4); + offset += 4; + + var channels = []; + for (var i = 0; i < numberOfChannels; i++) { + channels.push(new Float32Array(length)); + } + + // Bit depth + var bitDepth = this.readIntB(data, offset, 2); + var bytesPerSample = bitDepth / 8; + offset += 2; + + // Sample rate + var sampleRate = this.readFloatB(data, offset); + offset += 10; + } + else if (chunk.name == 'SSND') { + // Data offset + var dataOffset = this.readIntB(data, offset, 4); + offset += 4; + + // Ignore block size + offset += 4; + + // Skip over data offset + offset += dataOffset; + + for (var i = 0; i < numberOfChannels; i++) { + var channel = channels[i]; + for (var j = 0; j < length; j++) { + var index = offset; + index += (j * numberOfChannels + i) * bytesPerSample; + // Sample + var value = this.readIntB(data, index, bytesPerSample); + // Scale range from 0 to 2**bitDepth -> -2**(bitDepth-1) to + // 2**(bitDepth-1) + var range = 1 << bitDepth - 1; + if (value >= range) { + value |= ~(range - 1); + } + // Scale range to -1 to 1 + channel[j] = value / range; + } + } + offset += chunk.length - dataOffset - 8; + } + else { + offset += chunk.length; + } + } + decoded.sampleRate = sampleRate; + decoded.bitDepth = bitDepth; + decoded.channels = channels; + decoded.length = length; + return decoded; +}; + var Sink = this.Sink = function (global) { /** @@ -6431,7 +6747,7 @@ sinks('webaudio', function (readFn, channelCount, bufferSize, sampleRate) { soundData = null, zeroBuffer = null; self.start.apply(self, arguments); - node = context.createJavaScriptNode(self.bufferSize, 0, self.channelCount); + node = context.createJavaScriptNode(self.bufferSize, self.channelCount, self.channelCount); function bufferFill(e) { var outputBuffer = e.outputBuffer, diff --git a/public/js/vendor/Audiolet.min.js b/public/js/vendor/Audiolet.min.js deleted file mode 100644 index 388c5c5..0000000 --- a/public/js/vendor/Audiolet.min.js +++ /dev/null @@ -1,252 +0,0 @@ -var AudioletBuffer=function(a,c){this.numberOfChannels=a;this.length=c;this.channels=[];for(var b=0;bd){var l=k;if(!e||!m||m.lengthh){d.samples=d.samples.slice(0,h)}}};AudioletNode.prototype.createOutputSamples=function(){var e=this.outputs.length;for(var d=0;dc){a.samples=a.samples.slice(0,c);continue}}for(var b=a.samples.length;b0;c--){this.nodes[c].tick()}this.createInputSamples();for(var c=0;c0)};AudioletParameter.prototype.setValue=function(a){this.value=a};AudioletParameter.prototype.getValue=function(){if(this.input!=null&&this.input.samples.length>0){return this.input.samples[0]}else{return this.value}};function extend(a,c){function b(){}b.prototype=c.prototype;a.prototype=new b();a.prototype.constructor=a} -/*! - * @depends ../core/AudioletNode.js - */ -var ParameterNode=function(a,b){AudioletNode.call(this,a,1,1);this.parameter=new AudioletParameter(this,0,b)};extend(ParameterNode,AudioletNode);ParameterNode.prototype.generate=function(){this.outputs[0].samples[0]=this.parameter.getValue()};ParameterNode.prototype.toString=function(){return"Parameter Node"}; -/*! - * @depends AudioletNode.js - */ -var PassThroughNode=function(b,a,c){AudioletNode.call(this,b,a,c)};extend(PassThroughNode,AudioletNode);PassThroughNode.prototype.createOutputSamples=function(){var f=this.outputs.length;for(var e=0;ed){a.samples=a.samples.slice(0,d);continue}}for(var c=a.samples.length;cd){var e=(a-1)>>1;var c=this.heap[e];if(this.compare(b,c)){this.heap[a]=c;a=e;continue}break}this.heap[a]=b};PriorityQueue.prototype.siftUp=function(a){var e=this.heap.length;var d=a;var c=this.heap[a];var b=2*a+1;while(bthis.lastBeatTime){return null}var a={};a.callback=c;a.time=this.lastBeatTime+(b-this.beat)*this.beatLength;this.queue.push(a);return a};Scheduler.prototype.play=function(b,a,d){var c={};c.patterns=b;c.durationPattern=a;c.callback=d;c.time=this.audiolet.device.getWriteTime();this.queue.push(c);return c};Scheduler.prototype.playAbsolute=function(d,b,a,e){if(dthis.lastBeatTime){return null}var c={};c.patterns=b;c.durationPattern=a;c.callback=e;c.time=this.lastBeatTime+(d-this.beat)*this.beatLength;this.queue.push(c);return c};Scheduler.prototype.remove=function(b){var a=this.queue.heap.indexOf(b);if(a!=-1){this.queue.heap.splice(a,1);this.queue=new PriorityQueue(this.queue.heap,function(d,c){return(d.time=this.lastBeatTime+this.beatLength){this.beat+=1;this.beatInBar+=1;if(this.beatInBar==this.beatsPerBar){this.bar+=1;this.beatInBar=0}this.lastBeatTime+=this.beatLength}};Scheduler.prototype.processEvent=function(a){var h=a.durationPattern;if(h){var g=[];var b=a.patterns;var e=b.length;for(var d=0;d=this.changeTime){this.stage+=1;if(this.stage!=this.releaseStage){a=true}else{this.changeTime=null;this.delta=0}}}if(a){if(this.stage!=this.times.length){this.delta=this.calculateDelta(this.stage,this.level);this.changeTime=this.calculateChangeTime(this.stage,this.time)}else{if(this.onComplete){this.onComplete()}this.stage=null;this.time=null;this.changeTime=null;this.delta=0}}this.level+=this.delta;this.outputs[0].samples[0]=this.level};Envelope.prototype.calculateDelta=function(b,d){var c=this.levels[b+1].getValue()-d;var a=this.times[b].getValue()*this.audiolet.device.sampleRate;return(c/a)};Envelope.prototype.calculateChangeTime=function(b,c){var a=this.times[b].getValue()*this.audiolet.device.sampleRate;return(c+a)};Envelope.prototype.toString=function(){return"Envelope"}; -/*! - * @depends Envelope.js - */ -var ADSREnvelope=function(j,e,c,d,g,f,b){var h=[0,1,g,0];var a=[c,d,f];Envelope.call(this,j,e,h,a,2,b);this.attack=this.times[0];this.decay=this.times[1];this.sustain=this.levels[2];this.release=this.levels[2]};extend(ADSREnvelope,Envelope);ADSREnvelope.prototype.toString=function(){return"ADSR Envelope"}; -/*! - * @depends ../core/AudioletNode.js - */ -var BiquadFilter=function(a,b){AudioletNode.call(this,a,2,1);this.linkNumberOfOutputChannels(0,0);this.frequency=new AudioletParameter(this,1,b||22100);this.lastFrequency=null;this.xValues=[];this.yValues=[];this.b0=0;this.b1=0;this.b2=0;this.a0=0;this.a1=0;this.a2=0};extend(BiquadFilter,AudioletNode);BiquadFilter.prototype.calculateCoefficients=function(a){};BiquadFilter.prototype.generate=function(){var k=this.inputs[0];var j=this.outputs[0];var m=this.xValues;var p=this.yValues;var l=this.frequency.getValue();if(l!=this.lastFrequency){this.calculateCoefficients(l);this.lastFrequency=l}var v=this.a0;var u=this.a1;var t=this.a2;var h=this.b0;var g=this.b1;var f=this.b2;var d=k.samples.length;for(var n=0;n=m.length){m.push([0,0]);p.push([0,0])}var r=m[n];var q=r[0];var o=r[1];var e=p[n];var b=e[0];var a=e[1];var s=k.samples[n];var c=(h/v)*s+(g/v)*q+(f/v)*o-(u/v)*b-(t/v)*a;j.samples[n]=c;r[0]=s;r[1]=q;e[0]=c;e[1]=b}};BiquadFilter.prototype.toString=function(){return"Biquad Filter"}; -/*! - * @depends BiquadFilter.js - */ -var AllPassFilter=function(a,b){BiquadFilter.call(this,a,b)};extend(AllPassFilter,BiquadFilter);AllPassFilter.prototype.calculateCoefficients=function(e){var b=2*Math.PI*e/this.audiolet.device.sampleRate;var a=Math.cos(b);var c=Math.sin(b);var d=c/(2/Math.sqrt(2));this.b0=1-d;this.b1=-2*a;this.b2=1+d;this.a0=1+d;this.a1=-2*a;this.a2=1-d};AllPassFilter.prototype.toString=function(){return"All Pass Filter"}; -/*! - * @depends ../core/AudioletNode.js - */ -var Amplitude=function(b,c,a){AudioletNode.call(this,b,3,1);this.linkNumberOfOutputChannels(0,0);this.followers=[];this.attack=new AudioletParameter(this,1,c||0.01);this.release=new AudioletParameter(this,2,a||0.01)};extend(Amplitude,AudioletNode);Amplitude.prototype.generate=function(){var h=this.inputs[0];var a=this.outputs[0];var f=this.followers;var b=f.length;var l=this.audiolet.device.sampleRate;var d=this.attack.getValue();d=Math.pow(0.01,1/(d*l));var j=this.release.getValue();j=Math.pow(0.01,1/(j*l));var g=h.samples.length;for(var c=0;c=b){f.push(0)}var e=f[c];var k=Math.abs(h.samples[c]);if(k>e){e=d*(e-k)+k}else{e=j*(e-k)+k}a.samples[c]=e;f[c]=e}};Amplitude.prototype.toString=function(){return("Amplitude")}; -/*! - * @depends ../core/PassThroughNode.js - */ -var BadValueDetector=function(a,b){PassThroughNode.call(this,a,1,1);this.linkNumberOfOutputChannels(0,0);if(b){this.callback=b}};extend(BadValueDetector,PassThroughNode);BadValueDetector.prototype.callback=function(b,a){console.error(b+" detected at channel "+a)};BadValueDetector.prototype.generate=function(){var a=this.inputs[0];var b=a.samples.length;for(var c=0;c0&&!this.restartTriggerOn){this.position=f;this.restartTriggerOn=true;this.playing=true}if(b<=0&&this.restartTriggerOn){this.restartTriggerOn=false}var d=this.buffer.channels.length;for(var e=0;e=this.buffer.length){if(a){this.position%=this.buffer.length}else{this.playing=false;if(this.onComplete){this.onComplete()}}}};BufferPlayer.prototype.toString=function(){return("Buffer player")}; -/*! - * @depends ../core/AudioletNode.js - */ -var CombFilter=function(a,d,c,b){AudioletNode.call(this,a,3,1);this.linkNumberOfOutputChannels(0,0);this.maximumDelayTime=d;this.delayTime=new AudioletParameter(this,1,c||1);this.decayTime=new AudioletParameter(this,2,b);this.buffers=[];this.readWriteIndex=0};extend(CombFilter,AudioletNode);CombFilter.prototype.generate=function(){var k=this.inputs[0];var c=this.outputs[0];var l=this.audiolet.device.sampleRate;var f=this.delayTime.getValue()*l;var h=this.decayTime.getValue()*l;var a=Math.exp(-3*f/h);var j=k.samples.length;for(var e=0;e=this.buffers.length){var b=this.maximumDelayTime*l;this.buffers.push(new Float32Array(b))}var d=this.buffers[e];var g=d[this.readWriteIndex];c.samples[e]=g;d[this.readWriteIndex]=k.samples[e]+a*g}this.readWriteIndex+=1;if(this.readWriteIndex>=f){this.readWriteIndex=0}};CombFilter.prototype.toString=function(){return"Comb Filter"}; -/*! - * @depends ../core/AudioletNode.js - */ -var Sine=function(a,b){AudioletNode.call(this,a,1,1);this.frequency=new AudioletParameter(this,0,b||440);this.phase=0};extend(Sine,AudioletNode);Sine.prototype.generate=function(){var a=this.outputs[0];var c=this.frequency.getValue();var b=this.audiolet.device.sampleRate;a.samples[0]=Math.sin(this.phase);this.phase+=2*Math.PI*c/b;if(this.phase>2*Math.PI){this.phase%=2*Math.PI}};Sine.prototype.toString=function(){return"Sine"}; -/*! - * @depends ../core/AudioletNode.js - * @depends Sine.js - */ -var CrossFade=function(b,a){AudioletNode.call(this,b,3,1);this.linkNumberOfOutputChannels(0,0);this.position=new AudioletParameter(this,2,a||0.5)};extend(CrossFade,AudioletNode);CrossFade.prototype.generate=function(){var j=this.inputs[0];var h=this.inputs[1];var c=this.outputs[0];var g=this.position.getValue();var b=g*Math.PI/2;var f=Math.cos(b);var e=Math.sin(b);var k=c.samples.length;for(var d=0;d=this.buffers.length){var b=this.maximumDelayTime*n;this.buffers.push(new Float32Array(b))}if(f>=this.filterStores.length){this.filterStores.push(0)}var e=this.buffers[f];var h=this.filterStores[f];var j=e[this.readWriteIndex];h=(j*(1-d))+(h*d);c.samples[f]=j;e[this.readWriteIndex]=m.samples[f]+a*h;this.filterStores[f]=h}this.readWriteIndex+=1;if(this.readWriteIndex>=g){this.readWriteIndex=0}};DampedCombFilter.prototype.toString=function(){return"Damped Comb Filter"}; -/*! - * @depends ../core/AudioletNode.js - */ -var DCFilter=function(b,a){AudioletNode.call(this,b,2,1);this.linkNumberOfOutputChannels(0,0);this.coefficient=new AudioletParameter(this,1,a||0.995);this.xValues=[];this.yValues=[]};extend(DCFilter,AudioletNode);DCFilter.prototype.generate=function(){var c=this.coefficient.getValue();var a=this.inputs[0];var b=a.samples.length;for(var e=0;e=this.xValues.length){this.xValues.push(0)}if(e>=this.yValues.length){this.yValues.push(0)}var d=a.samples[e];var f=d-this.xValues[e]+c*this.yValues[e];this.outputs[0].samples[e]=f;this.xValues[e]=d;this.yValues[e]=f}};DCFilter.prototype.toString=function(){return"DC Filter"}; -/*! - * @depends ../core/AudioletNode.js - */ -var Delay=function(a,c,b){AudioletNode.call(this,a,2,1);this.linkNumberOfOutputChannels(0,0);this.maximumDelayTime=c;this.delayTime=new AudioletParameter(this,1,b||1);var d=c*this.audiolet.device.sampleRate;this.buffers=[];this.readWriteIndex=0};extend(Delay,AudioletNode);Delay.prototype.generate=function(){var c=this.inputs[0];var b=this.outputs[0];var e=this.audiolet.device.sampleRate;var g=this.delayTime.getValue()*e;var d=c.samples.length;for(var f=0;f=this.buffers.length){var h=this.maximumDelayTime*e;this.buffers.push(new Float32Array(h))}var a=this.buffers[f];b.samples[f]=a[this.readWriteIndex];a[this.readWriteIndex]=c.samples[f]}this.readWriteIndex+=1;if(this.readWriteIndex>=g){this.readWriteIndex=0}};Delay.prototype.toString=function(){return"Delay"}; -/*! - * @depends ../core/AudioletNode.js - */ -var DiscontinuityDetector=function(b,a,c){AudioletNode.call(this,b,1,1);this.linkNumberOfOutputChannels(0,0);this.threshold=a||0.2;if(c){this.callback=c}this.lastValues=[]};extend(DiscontinuityDetector,AudioletNode);DiscontinuityDetector.prototype.callback=function(a,b){console.error("Discontinuity of "+a+" detected on channel "+b)};DiscontinuityDetector.prototype.generate=function(){var b=this.inputs[0];var a=this.outputs[0];var c=b.samples.length;for(var d=0;d=this.lastValues.length){this.lastValues.push(0)}var e=b.samples[d];var f=Math.abs(this.lastValues[d]-e);if(f>this.threshold){this.callback(f,d)}this.lastValues[d]=e}};DiscontinuityDetector.prototype.toString=function(){return"Discontinuity Detector"}; -/*! - * @depends ../core/AudioletNode.js - */ -var FeedbackDelay=function(b,e,d,a,c){AudioletNode.call(this,b,4,1);this.linkNumberOfOutputChannels(0,0);this.maximumDelayTime=e;this.delayTime=new AudioletParameter(this,1,d||1);this.feedback=new AudioletParameter(this,2,a||0.5);this.mix=new AudioletParameter(this,3,c||1);var f=e*this.audiolet.device.sampleRate;this.buffers=[];this.readWriteIndex=0};extend(FeedbackDelay,AudioletNode);FeedbackDelay.prototype.generate=function(){var j=this.inputs[0];var c=this.outputs[0];var k=this.audiolet.output.device.sampleRate;var g=this.delayTime.getValue()*k;var a=this.feedback.getValue();var n=this.mix.getValue();var h=j.samples.length;var d=this.buffers.length;for(var f=0;f=d){var b=this.maximumDelayTime*k;this.buffers.push(new Float32Array(b))}var e=this.buffers[f];var m=j.samples[f];var l=e[this.readWriteIndex];c.samples[f]=n*l+(1-n)*m;e[this.readWriteIndex]=m+a*l}this.readWriteIndex+=1;if(this.readWriteIndex>=g){this.readWriteIndex=0}};FeedbackDelay.prototype.toString=function(){return"Feedback Delay"}; -/*! - * @depends ../core/AudioletNode.js - */ -var FFT=function(a,b){AudioletNode.call(this,a,2,1);this.linkNumberOfOutputChannels(0,0);this.bufferSize=b;this.readWriteIndex=0;this.buffer=new Float32Array(this.bufferSize);this.realBuffer=new Float32Array(this.bufferSize);this.imaginaryBuffer=new Float32Array(this.bufferSize);this.reverseTable=new Uint32Array(this.bufferSize);this.calculateReverseTable()};extend(FFT,AudioletNode);FFT.prototype.generate=function(){var b=this.inputs[0];var a=this.outputs[0];if(b.samples.length==0){return}this.buffer[this.readWriteIndex]=b.samples[0];a.samples[0]=[this.realBuffer[this.readWriteIndex],this.imaginaryBuffer[this.readWriteIndex]];this.readWriteIndex+=1;if(this.readWriteIndex>=this.bufferSize){this.transform();this.readWriteIndex=0}};FFT.prototype.calculateReverseTable=function(){var a=1;var c=this.bufferSize>>1;while(a>1}};FFT.prototype.transform=function(){for(var e=0;e=this.bufferSize){this.transform();this.readWriteIndex=0}};IFFT.prototype.calculateReverseTable=function(){var a=1;var c=this.bufferSize>>1;while(a>1}};IFFT.prototype.transform=function(){var e=1;for(var f=0;f=this.followers.length){this.followers.push(0)}var f=this.followers[c];var l=h.samples[c];var e=Math.abs(l);if(e>f){f=b*(f-e)+e}else{f=j*(f-e)+e}var k=f-d;if(k>0){a.samples[c]=l/(1+k)}else{a.samples[c]=l}this.followers[c]=f}};Limiter.prototype.toString=function(){return"Limiter"}; -/*! - * @depends ../core/AudioletNode.js - */ -var LinearCrossFade=function(b,a){AudioletNode.call(this,b,3,1);this.linkNumberOfOutputChannels(0,0);this.position=new AudioletParameter(this,2,a||0.5)};extend(LinearCrossFade,AudioletNode);LinearCrossFade.prototype.generate=function(){var h=this.inputs[0];var g=this.inputs[1];var b=this.outputs[0];var f=this.position.getValue();var e=1-f;var c=f;var j=b.samples.length;for(var d=0;d1){this.phase%=1}};Pulse.prototype.toString=function(){return"Pulse"}; -/*! - * @depends ../core/AudioletNode.js - * @depends ../core/AudioletGroup.js - */ -var Reverb=function(d,g,a,c){AudioletNode.call(this,d,4,1);this.initialMix=0.33;this.fixedGain=0.015;this.initialDamping=0.5;this.scaleDamping=0.4;this.initialRoomSize=0.5;this.scaleRoom=0.28;this.offsetRoom=0.7;this.combTuning=[1116,1188,1277,1356,1422,1491,1557,1617];this.allPassTuning=[556,441,341,225];var g=g||this.initialMix;this.mix=new AudioletParameter(this,1,g);var a=a||this.initialRoomSize;this.roomSize=new AudioletParameter(this,2,a);var c=c||this.initialDamping;this.damping=new AudioletParameter(this,3,c);this.combBuffers=[];this.combIndices=[];this.filterStores=[];var b=this.combTuning.length;for(var f=0;f=p.length){o=0}this.combIndices[r]=o;this.filterStores[r]=n}for(var r=0;r=b.length){g=0}this.allPassIndices[r]=g}this.outputs[0].samples[0]=k*q+(1-k)*j};Reverb.prototype.toString=function(){return"Reverb"}; -/*! - * @depends ../core/AudioletNode.js - */ -var Saw=function(a,b){AudioletNode.call(this,a,1,1);this.frequency=new AudioletParameter(this,0,b||440);this.phase=0};extend(Saw,AudioletNode);Saw.prototype.generate=function(){var a=this.outputs[0];var c=this.frequency.getValue();var b=this.audiolet.device.sampleRate;a.samples[0]=((this.phase/2+0.25)%0.5-0.25)*4;this.phase+=c/b;if(this.phase>1){this.phase%=1}};Saw.prototype.toString=function(){return"Saw"}; -/*! - * @depends ../core/AudioletNode.js - */ -var SoftClip=function(a){AudioletNode.call(this,a,1,1);this.linkNumberOfOutputChannels(0,0)};extend(SoftClip,AudioletNode);SoftClip.prototype.generate=function(){var b=this.inputs[0];var a=this.outputs[0];var c=b.samples.length;for(var d=0;d0.5||e<-0.5){a.samples[d]=(Math.abs(e)-0.25)/e}else{a.samples[d]=e}}};SoftClip.prototype.toString=function(){return("SoftClip")}; -/*! - * @depends ../core/AudioletNode.js - */ -var Square=function(a,b){AudioletNode.call(this,a,1,1);this.frequency=new AudioletParameter(this,0,b||440);this.phase=0};extend(Square,AudioletNode);Square.prototype.generate=function(){var a=this.outputs[0];var c=this.frequency.getValue();var b=this.audiolet.device.sampleRate;a.samples[0]=this.phase>0.5?1:-1;this.phase+=c/b;if(this.phase>1){this.phase%=1}};Square.prototype.toString=function(){return"Square"}; -/*! - * @depends ../core/AudioletNode.js - */ -var Triangle=function(a,b){AudioletNode.call(this,a,1,1);this.frequency=new AudioletParameter(this,0,b||440);this.phase=0};extend(Triangle,AudioletNode);Triangle.prototype.generate=function(){var a=this.outputs[0];var c=this.frequency.getValue();var b=this.audiolet.device.sampleRate;a.samples[0]=1-4*Math.abs((this.phase+0.25)%1-0.5);this.phase+=c/b;if(this.phase>1){this.phase%=1}};Triangle.prototype.toString=function(){return"Triangle"}; -/*! - * @depends ../core/AudioletNode.js - */ -var TriggerControl=function(b,a){AudioletNode.call(this,b,0,1);this.trigger=new AudioletParameter(this,null,a||0)};extend(TriggerControl,AudioletNode);TriggerControl.prototype.generate=function(){if(this.trigger.getValue()>0){this.outputs[0].samples[0]=1;this.trigger.setValue(0)}else{this.outputs[0].samples[0]=0}};TriggerControl.prototype.toString=function(){return"Trigger Control"}; -/*! - * @depends ../core/AudioletNode.js - */ -var UpMixer=function(a,b){AudioletNode.call(this,a,1,1);this.outputs[0].numberOfChannels=b};extend(UpMixer,AudioletNode);UpMixer.prototype.generate=function(){var c=this.inputs[0];var b=this.outputs[0];var e=c.samples.length;var a=b.samples.length;if(e==a){b.samples=c.samples}else{for(var d=0;dthis.endTime){this.stop();this.onComplete()}}; -/*! - * @depends ../core/AudioletNode.js - */ -var WhiteNoise=function(a){AudioletNode.call(this,a,0,1)};extend(WhiteNoise,AudioletNode);WhiteNoise.prototype.generate=function(){this.outputs[0].samples[0]=Math.random()*2-1};WhiteNoise.prototype.toString=function(){return"White Noise"};var Pattern=function(){};Pattern.prototype.next=function(){return null};Pattern.prototype.valueOf=function(a){if(a instanceof Pattern){return(a.next())}else{return(a)}};Pattern.prototype.reset=function(){}; -/*! - * @depends Pattern.js - */ -var PArithmetic=function(c,b,a){Pattern.call(this);this.start=c;this.value=c;this.step=b;this.repeats=a;this.position=0};extend(PArithmetic,Pattern);PArithmetic.prototype.next=function(){var a;if(this.position==0){a=this.value;this.position+=1}else{if(this.position0||l===g){m.ready();try{f=new Float32Array(l===g?m.preBufferSize*m.channelCount:m.forceBufferSize?e2000){m._audio=j=new Audio();j.mozSetup(m.channelCount,m.sampleRate);d=0;m.emit("error",[a.Error(17)])}},1000));this._timers.push(a.doInterval(c,m.interval));m._bufferFill=c;m._audio=j},{bufferSize:24576,preBufferSize:24576,forceBufferSize:false,interval:100,kill:function(){while(this._timers.length){this._timers.shift()()}this.emit("kill")},getPlaybackTime:function(){return this._audio.mozCurrentSampleOffset()/this.channelCount}},false,true);a.sinks.moz=a.sinks.audiodata}(this.Sink);void function(a){a.sinks("dummy",function(){var b=this;b.start.apply(b,arguments);function c(){var d=new Float32Array(b.bufferSize*b.channelCount);b.process(d,b.channelCount)}b._kill=a.doInterval(c,b.bufferSize/b.sampleRate*1000);b._callback=c},{kill:function(){this._kill();this.emit("kill")}},true)}(this.Sink);(function(b,a){a=b.sinks;function d(f){var e=document.createElement("audio");if(f){e.src=f}return e}a("wav",function(){var e=this,j=new a.wav.wavAudio(),k=typeof k==="undefined"?audioLib.PCMData:k;e.start.apply(e,arguments);var g=new Float32Array(e.bufferSize*e.channelCount),h=new Float32Array(e.bufferSize*e.channelCount);if(!d().canPlayType("audio/wav; codecs=1")||!btoa){throw 0}function f(){if(e._audio.hasNextFrame){return}e.ready();b.memcpy(h,0,g,0);e.process(g,e.channelCount);e._audio.setSource("data:audio/wav;base64,"+btoa(audioLib.PCMData.encode({data:g,sampleRate:e.sampleRate,channelCount:e.channelCount,bytesPerSample:e.quality})));if(!e._audio.currentFrame.src){e._audio.nextClip()}}e.kill=b.doInterval(f,40);e._bufferFill=f;e._audio=j},{quality:1,bufferSize:22050,getPlaybackTime:function(){var e=this._audio;return(e.currentFrame?e.currentFrame.currentTime*this.sampleRate:0)+e.samples}});function c(){var e=this;e.currentFrame=d();e.nextFrame=d();e._onended=function(){e.samples+=e.bufferSize;e.nextClip()}}c.prototype={samples:0,nextFrame:null,currentFrame:null,_onended:null,hasNextFrame:false,nextClip:function(){var e=this.currentFrame;this.currentFrame=this.nextFrame;this.nextFrame=e;this.hasNextFrame=false;this.currentFrame.play()},setSource:function(e){this.nextFrame.src=e;this.nextFrame.addEventListener("ended",this._onended,true);this.hasNextFrame=true}};a.wav.wavAudio=c}(this.Sink));(function(a,b){var c=typeof window==="undefined"?null:window.webkitAudioContext||window.AudioContext;a("webaudio",function(l,k,g,m){var n=this,d=a.webaudio.getContext(),j=null,h=null,f=null;n.start.apply(n,arguments);j=d.createJavaScriptNode(n.bufferSize,0,n.channelCount);function e(v){var o=v.outputBuffer,q=o.numberOfChannels,s,p,r=o.length,w=o.size,t=new Array(q),u;n.ready();h=h&&h.length===r*q?h:new Float32Array(r*q);f=f&&f.length===h.length?f:new Float32Array(r*q);h.set(f);for(s=0;s=this.buffer.length){this.loadBuffer()}c[d]=this.buffer[this.offset++]}},loadBuffer:function(){this.offset=0;a.memcpy(this.zeroBuffer,0,this.buffer,0);this.emit("audioprocess",[this.buffer,this.channelCount])}};a.Proxy=b;a.prototype.createProxy=function(d){var c=new a.Proxy(d,this.channelCount);c.parentSink=this;this.on("audioprocess",c.callback);return c}}(this.Sink));(function(a){(function(){function b(c,d){if(c&&d){b[c]=d}else{if(c&&b[c] instanceof Function){a.interpolate=b[c]}}return b[c]}a.interpolation=b;b("linear",function(c,g){var f=Math.floor(g),e=f+1,d=g-f;e=e=c.length-0.5?c[0]:c[Math.round(d)]});b("linear")}());a.resample=function(j,b,o,p,d){var h=arguments.length,f=h===2?b:h===3?b/o:p/b*d/o,g=j.length,c=Math.ceil(g/f),m=new Float32Array(c),k,e;for(k=0,e=0;k=h){d.splice(g--,1)}}}};b.writeBuffersSync=function(e){var d=this.syncBuffers,c=e.length,f=0,g=0;for(;f