/build/js/main_compressed.js
JavaScript | 4404 lines | 3105 code | 1059 blank | 240 comment | 362 complexity | 97cebfccf9ce8d09f8d1033c011bd123 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /* Copyright 2013 Chris Wilson
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- /*
- This monkeypatch library is intended to be included in projects that are
- written to the proper AudioContext spec (instead of webkitAudioContext),
- and that use the new naming and proper bits of the Web Audio API (e.g.
- using BufferSourceNode.start() instead of BufferSourceNode.noteOn()), but may
- have to run on systems that only support the deprecated bits.
- This library should be harmless to include if the browser supports
- unprefixed "AudioContext", and/or if it supports the new names.
- The patches this library handles:
- if window.AudioContext is unsupported, it will be aliased to webkitAudioContext().
- if AudioBufferSourceNode.start() is unimplemented, it will be routed to noteOn() or
- noteGrainOn(), depending on parameters.
- The following aliases only take effect if the new names are not already in place:
- AudioBufferSourceNode.stop() is aliased to noteOff()
- AudioContext.createGain() is aliased to createGainNode()
- AudioContext.createDelay() is aliased to createDelayNode()
- AudioContext.createScriptProcessor() is aliased to createJavaScriptNode()
- OscillatorNode.start() is aliased to noteOn()
- OscillatorNode.stop() is aliased to noteOff()
- AudioParam.setTargetAtTime() is aliased to setTargetValueAtTime()
- This library does NOT patch the enumerated type changes, as it is
- recommended in the specification that implementations support both integer
- and string types for AudioPannerNode.panningModel, AudioPannerNode.distanceModel
- BiquadFilterNode.type and OscillatorNode.type.
- */
- (function (global, exports, perf) {
- 'use strict';
- function fixSetTarget(param) {
- if (!param) // if NYI, just return
- return;
- if (!param.setTargetAtTime)
- param.setTargetAtTime = param.setTargetValueAtTime;
- }
- if (window.hasOwnProperty('webkitAudioContext') &&
- !window.hasOwnProperty('AudioContext')) {
- window.AudioContext = webkitAudioContext;
- AudioContext.prototype.internal_createGain = AudioContext.prototype.createGain;
- AudioContext.prototype.createGain = function() {
- var node = this.internal_createGain();
- fixSetTarget(node.gain);
- return node;
- };
- AudioContext.prototype.internal_createDelay = AudioContext.prototype.createDelay;
- AudioContext.prototype.createDelay = function() {
- var node = this.internal_createDelay();
- fixSetTarget(node.delayTime);
- return node;
- };
- AudioContext.prototype.internal_createBufferSource = AudioContext.prototype.createBufferSource;
- AudioContext.prototype.createBufferSource = function() {
- var node = this.internal_createBufferSource();
- if (!node.start) {
- node.start = function ( when, offset, duration ) {
- if ( offset || duration )
- this.noteGrainOn( when, offset, duration );
- else
- this.noteOn( when );
- }
- }
- if (!node.stop)
- node.stop = node.noteoff;
- fixSetTarget(node.playbackRate);
- return node;
- };
- AudioContext.prototype.internal_createDynamicsCompressor = AudioContext.prototype.createDynamicsCompressor;
- AudioContext.prototype.createDynamicsCompressor = function() {
- var node = this.internal_createDynamicsCompressor();
- fixSetTarget(node.threshold);
- fixSetTarget(node.knee);
- fixSetTarget(node.ratio);
- fixSetTarget(node.reduction);
- fixSetTarget(node.attack);
- fixSetTarget(node.release);
- return node;
- };
- AudioContext.prototype.internal_createBiquadFilter = AudioContext.prototype.createBiquadFilter;
- AudioContext.prototype.createBiquadFilter = function() {
- var node = this.internal_createBiquadFilter();
- fixSetTarget(node.frequency);
- fixSetTarget(node.detune);
- fixSetTarget(node.Q);
- fixSetTarget(node.gain);
- return node;
- };
- if (AudioContext.prototype.hasOwnProperty( 'createOscillator' )) {
- AudioContext.prototype.internal_createOscillator = AudioContext.prototype.createOscillator;
- AudioContext.prototype.createOscillator = function() {
- var node = this.internal_createOscillator();
- if (!node.start)
- node.start = node.noteOn;
- if (!node.stop)
- node.stop = node.noteOff;
- fixSetTarget(node.frequency);
- fixSetTarget(node.detune);
- return node;
- };
- }
- if (!AudioContext.prototype.hasOwnProperty('createGain'))
- AudioContext.prototype.createGain = AudioContext.prototype.createGainNode;
- if (!AudioContext.prototype.hasOwnProperty('createDelay'))
- AudioContext.prototype.createDelay = AudioContext.prototype.createDelayNode;
- if (!AudioContext.prototype.hasOwnProperty('createScriptProcessor'))
- AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode;
- }
- }(window));
- /**
- * @author alteredq / http://alteredqualia.com/
- * @author mr.doob / http://mrdoob.com/
- */
- Detector = {
- canvas: !! window.CanvasRenderingContext2D,
- webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
- workers: !! window.Worker,
- fileapi: window.File && window.FileReader && window.FileList && window.Blob,
- getWebGLErrorMessage: function () {
- var element = document.createElement( 'div' );
- element.id = 'webgl-error-message';
- element.style.fontFamily = 'monospace';
- element.style.fontSize = '13px';
- element.style.fontWeight = 'normal';
- element.style.textAlign = 'center';
- element.style.background = '#fff';
- element.style.color = '#000';
- element.style.padding = '1.5em';
- element.style.width = '400px';
- element.style.margin = '5em auto 0';
- if ( ! this.webgl ) {
- element.innerHTML = window.WebGLRenderingContext ? [
- 'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />',
- 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
- ].join( '\n' ) : [
- 'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>',
- 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
- ].join( '\n' );
- }
- return element;
- },
- addGetWebGLMessage: function ( parameters ) {
- var parent, id, element;
- parameters = parameters || {};
- parent = parameters.parent !== undefined ? parameters.parent : document.body;
- id = parameters.id !== undefined ? parameters.id : 'oldie';
- element = Detector.getWebGLErrorMessage();
- element.id = id;
- parent.appendChild( element );
- }
- };
- // AudioDetector.js / https://github.com/sole/AudioDetector.js
- // Based on alteredq & mrdoob's Detector.js https://github.com/mrdoob/three.js/blob/master/examples/js/Detector.js
- AudioDetector = {
- REVISION: 3,
- webAudioSupport: typeof(window.AudioContext) === 'function' || typeof( window.webkitAudioContext ) === 'function',
- oggSupport: document.createElement('audio').canPlayType('audio/ogg'),
- errorMessages: {
- 'webAudioSupport': 'Your browser does not seem to support the <a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html" style="color:#000">Web Audio API</a>.<br/>' +
- 'Find out how to get it <a href="http://chromium.googlecode.com/svn/trunk/samples/audio/index.html" style="color:#000">here</a>.',
- 'oggSupport': 'Your browser does not seem to support OGG audio.<br/>' +
- 'Find out how to get it <a href="https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements" style="color:#000">here</a>.'
- },
- getErrorMessage: function ( message ) {
- var element = document.createElement( 'div' );
- element.style.fontFamily = 'monospace';
- element.style.fontSize = '13px';
- element.style.fontWeight = 'normal';
- element.style.textAlign = 'center';
- element.style.background = '#fff';
- element.style.color = '#000';
- element.style.padding = '1.5em';
- element.style.width = '350px';
- element.style.margin = '2em auto';
- element.style.zIndex = 1000;
- element.style.position = 'relative';
- element.style.top = '0px';
- element.style.left = '0px';
- element.style.border = '6px solid red';
- element.innerHTML = message;
- return element;
- },
- detects: function( conditions ) {
- if( ! ( conditions instanceof Array ) ) {
- this.showErrorMessage('<span style="font-size: 200%;">Oi!</span> <strong>conditions</strong> must be an Array with conditions to be checked');
- return false;
- }
- for(var i = 0; i < conditions.length; i++) {
- var propertyName = conditions[i];
-
- if(this.errorMessages[propertyName] !== undefined) {
- var checkResult = this[propertyName];
- if(!checkResult) {
- this.showErrorMessage(this.errorMessages[propertyName]);
- return false;
- }
- }
- }
- return true;
- },
- showErrorMessage: function ( message, parameters ) {
- var parent, id, element;
- parameters = parameters || {};
- parent = parameters.parent !== undefined ? parameters.parent : document.body;
- id = parameters.id !== undefined ? parameters.id : 'audio-error-message';
- element = AudioDetector.getErrorMessage(message);
- element.id = id;
- parent.appendChild( element );
-
- element.style.position = 'absolute';
- element.style.top = '100px';
- element.style.left = ((window.innerWidth - element.clientWidth) / 2) + 'px';
- }
- };
- // sorollet.js - http://github.com/sole/sorollet.js
- var SOROLLET = SOROLLET || {
- REVISION: '2'
- };
- SOROLLET.Math = {
- randSeed : 1,
- normalize: function(value, minimum, maximum) {
- return (value - minimum) / (maximum - minimum);
- },
- interpolate: function(normValue, minimum, maximum) {
- return minimum + (maximum - minimum) * normValue;
- },
- map: function(value, in_min, in_max, out_min, out_max) {
- if(in_min == in_max) {
- return out_min;
- }
- return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min);
- },
- randf : function() {
- this.randSeed *= 16807;
- return (this.randSeed) / 0x80000000;
- },
- clip: function(value, minV, maxV) {
- return Math.max(Math.min(value, maxV), minV);
- }
- }
- 'use strict';
- SOROLLET.Voice = function() {
-
- this.buffer = [];
- this.position = 0;
- this.currentNote = null;
- this.currentVolume = 0;
- this.internalSamplePosition = 0;
- this.setSamplingRate( 44100 );
- this.wave1Function = this.getSineBuffer;
- this.wave1Octave = 5;
- this.wave1Volume = 0.5;
- this.wave1Phase = 0;
-
- this.wave2Function = this.getSquareBuffer;
- this.wave2Octave = 4;
- this.wave2Volume = 0.5;
- this.wave2Phase = 0;
- this.waveMixFunction = this.mixAdd;
-
- this.noiseAmount = 0.0;
- this.noiseMixFunction = this.noiseAdd;
- this.volumeEnvelope = new SOROLLET.ADSR(0.5, 0, 1, 1, 1);
- this.pitchEnvelope = new SOROLLET.ADSR(0, 0, 1, 0, 1);
- this.volumeEnvelope.setOutputRange( 0, 1 );
- this.pitchEnvelope.setOutputRange( 0, 0 );
- };
- SOROLLET.Voice.prototype = {
- constructor: SOROLLET.Voice,
-
- setSamplingRate : function( value ) {
- this.samplingRate = value;
- this.inverseSamplingRate = 1.0 / value;
- },
- noteToFrequency: function(note, octave) {
- return 440.0 * Math.pow(2, ((note - 57.0 + (octave - 4.0) * 12.0) / 12.0));
- },
- zeroBuffer: function(buffer, numSamples) {
- for(var i = 0; i < numSamples; i++) {
- buffer[i] = 0;
- }
- },
- getTime: function() {
- return this.internalSamplePosition * this.inverseSamplingRate;
- },
- getSineBuffer : function getSineBuffer(buffer, numSamples, pos, frequency, phase) {
- var value,
- cst = 2.0 * Math.PI * frequency * this.inverseSamplingRate;
- for(var i = 0; i < numSamples; ++i) {
- value = Math.sin(cst * pos + phase);
- buffer[i] = value;
- pos++;
- }
- },
- getTriangleBuffer: function getTriangleBuffer(buffer, numSamples, pos, frequency, phase) {
- var period = 1.0 / frequency,
- semiperiod = period * 0.5,
- value,
- ft = semiperiod * 0.5;
- for(var i = 0; i < numSamples; ++i) {
- var t = (i + pos + phase) * this.inverseSamplingRate + ft;
- if(t % period < semiperiod) {
- value = 2.0 * ((t % semiperiod) / semiperiod) - 1.0;
- } else {
- value = 1.0 - 2.0 * (t % semiperiod) / semiperiod;
- }
- buffer[i] = value;
- }
- },
- getSquareBuffer: function getSquareBuffer(buffer, numSamples, pos, frequency, phase) {
- var period = 1.0 / frequency,
- halfPeriod = period * 0.5,
- value;
- for(var i = 0; i < numSamples; i++) {
- var t = (i + pos + phase) * this.inverseSamplingRate;
- if(t % period < halfPeriod) {
- value = 1.0;
- } else {
- value = -1.0;
- }
- buffer[i] = value;
- }
- },
- getSawtoothBuffer: function getSawtoothBuffer(buffer, numSamples, pos, frequency, phase) {
- var period = 1.0 / frequency,
- value;
- for(var i = 0; i < numSamples; i++) {
- var t = (pos + phase) * this.inverseSamplingRate;
- value = 2.0 * ((t % period) * frequency) - 1.0;
- buffer[i] = value;
- pos++;
- }
- },
- mixAdd: function(v1, v2) {
- return v1 + v2;
- },
- mixSubstract: function(v1, v2) {
- return v1 - v2;
- },
- mixMultiply: function(v1, v2) {
- return v1 * v2;
- },
- mixDivide: function(v1, v2) {
- if(v2 == 0) {
- v2 = 0.0001;
- }
- return v1 / v2;
- },
- noiseAdd: function(noiseValue, waveValue, notNoiseAmount) {
- return noiseValue + waveValue;
- },
- noiseMix: function(noiseValue, waveValue, notNoiseAmount) {
- return waveValue * notNoiseAmount + noiseValue;
- },
- noiseMultiply: function(noiseValue, waveValue, notNoiseAmount) {
- return noiseValue * waveValue;
- },
-
- getNoiseBuffer: function(buffer, numSamples) {
- for(var i = 0; i < numSamples; i++) {
- buffer[i] = Math.random() * 2 - 1;
- }
- },
- sendNoteOn: function(note, volume) {
- this.position = 0;
- this.internalSamplePosition = 0;
- this.currentNote = note;
- this.currentVolume = volume;
- var t = this.getTime();
- this.volumeEnvelope.beginAttack(t);
- this.pitchEnvelope.beginAttack(t);
- },
- sendNoteOff: function() {
- var t = this.getTime();
- this.volumeEnvelope.beginRelease(t);
- this.pitchEnvelope.beginRelease(t);
- },
-
- getBuffer: function(numSamples) {
-
- var wave1Buffer = [],
- wave2Buffer = [],
- noiseBuffer = [],
- bufferPitch1 = [],
- bufferPitch2 = [],
- bufferAmp = [],
- tmpBuffer = [],
- currentTime = this.getTime(),
- // Local references
- buffer = this.buffer,
- bufferTime = currentTime,
- currentNote = this.currentNote,
- wave1Octave = this.wave1Octave,
- wave2Octave = this.wave2Octave,
- wave1Volume = this.wave1Volume,
- wave1Phase = this.wave1Phase,
- wave2Phase = this.wave2Phase,
- wave2Volume = this.wave2Volume,
- inverseSamplingRate = this.inverseSamplingRate,
- noiseAmount = this.noiseAmount,
- notNoiseAmount = 1 - noiseAmount,
- zeroBufferFn = this.zeroBuffer,
- noteToFrequencyFn = this.noteToFrequency,
- getNoiseBufferFn = this.getNoiseBuffer,
- wave1Function = this.wave1Function,
- wave2Function = this.wave2Function,
- waveMixFunction = this.waveMixFunction,
- clipFn = SOROLLET.Math.clip;
- zeroBufferFn(buffer, numSamples);
- if( this.volumeEnvelope.state == SOROLLET.ADSR.STATE_DONE ) {
- this.currentNote = null;
- currentNote = null;
- }
- if(this.currentNote === null) {
- return buffer;
- }
- zeroBufferFn(wave1Buffer, numSamples);
- zeroBufferFn(wave2Buffer, numSamples);
- zeroBufferFn(noiseBuffer, numSamples);
- zeroBufferFn(bufferPitch1, numSamples);
- zeroBufferFn(bufferPitch2, numSamples);
- zeroBufferFn(bufferAmp, numSamples);
- // Fill the amp and pitch buffers for this run
-
- for (var i = 0; i < numSamples; i++) {
- var pitchEnv = this.pitchEnvelope.update(bufferTime),
- sampleNote = currentNote + pitchEnv;
- bufferPitch1[i] = this.noteToFrequency(sampleNote, wave1Octave);
- bufferPitch2[i] = this.noteToFrequency(sampleNote, wave2Octave);
- bufferAmp[i] = this.volumeEnvelope.update(bufferTime);
-
- bufferTime += inverseSamplingRate;
- }
- if(this.wave1Volume > 0) {
- var pos = this.position;
-
- for(var i = 0; i < numSamples; i++) {
- var frequency = bufferPitch1[i];
-
- this.wave1Function(tmpBuffer, 1, pos, frequency, wave1Phase);
- wave1Buffer[i] = tmpBuffer[0];
- pos++;
- }
- }
- if(this.wave2Volume > 0) {
- var pos = this.position;
- for(var i = 0; i < numSamples; i++) {
- var frequency = bufferPitch2[i];
-
- this.wave2Function(tmpBuffer, 1, pos, frequency, wave2Phase);
- wave2Buffer[i] = tmpBuffer[0];
- pos++;
- }
- }
- if(noiseAmount > 0) {
- getNoiseBufferFn(noiseBuffer, numSamples);
- }
- for(var i = 0; i < numSamples; i++) {
- var osc1 = wave1Buffer[i] * wave1Volume,
- osc2 = wave2Buffer[i] * wave2Volume;
- buffer[i] = waveMixFunction(osc1, osc2);
- if(noiseAmount > 0) {
- var noiseValue = noiseBuffer[i] * noiseAmount;
- buffer[i] = this.noiseMixFunction(noiseValue, buffer[i], notNoiseAmount);
- }
- // Apply amp envelope
- buffer[i] *= bufferAmp[i];
- // Clamp
- buffer[i] = clipFn(buffer[i], -1, 1);
- }
- this.position += numSamples;
- this.internalSamplePosition += numSamples;
- return buffer;
- },
- functionToIndex: function(f, functionsList ) {
- for( var i = 0; i < functionsList.length; i++) {
- var o = functionsList[i];
- if( o.func == f ) {
- return i;
- }
- }
- return -1;
- },
- getParams: function() {
- return {
- wave1Function: this.functionToIndex( this.wave1Function, this.waveFunctions ),
- wave1Octave: this.wave1Octave,
- wave1Volume: this.wave1Volume,
- wave1Phase: this.wave1Phase,
- wave2Function: this.functionToIndex( this.wave2Function, this.waveFunctions ),
- wave2Octave: this.wave2Octave,
- wave2Volume: this.wave2Volume,
- wave2Phase: this.wave2Phase,
- waveMixFunction: this.functionToIndex( this.waveMixFunction, this.waveMixFunctions ),
- noiseAmount: this.noiseAmount,
- noiseMixFunction: this.functionToIndex( this.noiseMixFunction, this.noiseMixFunctions ),
- volumeEnvelope: this.volumeEnvelope.getParams(),
- pitchEnvelope: this.pitchEnvelope.getParams()
- };
- },
- setParams: function( params ) {
- this.wave1Function = this.waveFunctions[ params.wave1Function ].func;
- this.wave1Octave = params.wave1Octave;
- this.wave1Volume = params.wave1Volume;
- this.wave1Phase = params.wave1Phase;
-
- this.wave2Function = this.waveFunctions[ params.wave2Function ].func;
- this.wave2Octave = params.wave2Octave;
- this.wave2Volume = params.wave2Volume;
- this.wave2Phase = params.wave2Phase;
- this.waveMixFunction = this.waveMixFunctions[ params.waveMixFunction ].func;
- this.noiseAmount = params.noiseAmount;
- this.noiseMixFunction = this.noiseMixFunctions[ params.noiseMixFunction ].func;
- this.volumeEnvelope.setParams( params.volumeEnvelope );
- this.pitchEnvelope.setParams( params.pitchEnvelope );
- }
- };
- SOROLLET.Voice.prototype.waveFunctions = [
- { func: SOROLLET.Voice.prototype.getSineBuffer, name: 'sine' },
- { func: SOROLLET.Voice.prototype.getTriangleBuffer, name: 'triangle' },
- { func: SOROLLET.Voice.prototype.getSquareBuffer, name: 'square' },
- { func: SOROLLET.Voice.prototype.getSawtoothBuffer, name: 'sawtooth' }
- ];
- SOROLLET.Voice.prototype.waveMixFunctions = [
- { func: SOROLLET.Voice.prototype.mixAdd, name: 'add' },
- { func: SOROLLET.Voice.prototype.mixSubstract, name: 'substract' },
- { func: SOROLLET.Voice.prototype.mixMultiply, name: 'multiply' },
- { func: SOROLLET.Voice.prototype.mixDivide, name: 'divide' }
- ];
- SOROLLET.Voice.prototype.noiseMixFunctions = [
- { func: SOROLLET.Voice.prototype.noiseAdd, name: 'add' },
- { func: SOROLLET.Voice.prototype.noiseMix, name: 'mix' },
- { func: SOROLLET.Voice.prototype.noiseMultiply, name: 'multiply' }
- ];
- 'use strict';
- SOROLLET.ADSR = function( attackLength, decayLength, sustainLevel, releaseLength, timeScale ) {
- this.state = this.STATE_DONE;
- this.timeScale = timeScale;
- this.attackStartTime = 0;
- this.attackEndTime = 0;
- this.decayEndTime = 0;
- this.releaseStartTime = 0;
- this.releaseEndValue = 0;
- this.releaseStartValue = 0;
-
- this.__unscaledAttackLength = 0;
- this.attackLength = 0;
- this.__unscaledDecayLength = 0;
- this.decayLength = 0;
- this.sustainLevel = 0.5;
- this.__unscaledReleaseLength = 0;
- this.releaseLength = 0;
-
- this.lastValue = 0;
- this.setAttack( attackLength );
- this.setDecay( decayLength );
- this.setSustainLevel( sustainLevel );
- this.setRelease( releaseLength );
- this.setOutputRange( 0, 1 );
- }
- SOROLLET.ADSR.prototype = {
- constructor: SOROLLET.ADSR,
- STATE_ATTACK: 0,
- STATE_DECAY: 1,
- STATE_SUSTAIN: 2,
- STATE_RELEASE: 3,
- STATE_DONE: 4,
- setOutputRange : function( minimumValue, maximumValue ) {
- this.outputMinimumValue = minimumValue;
- this.outputMaximumValue = maximumValue;
- },
- setAttack: function( v ) {
- this.__unscaledAttackLength = v;
- this.attackLength = v * this.timeScale;
- },
- setDecay: function( v ) {
- this.__unscaledDecayLength = v;
- this.decayLength = v * this.timeScale;
- this.decayEndTime = this.attackEndTime + this.decayLength;
- },
- setSustainLevel: function( v ) {
- this.sustainLevel = v;
- },
- setRelease: function( v ) {
- this.__unscaledReleaseLength = v;
- this.releaseLength = v * this.timeScale;
- this.releaseEndTime = this.releaseStartTime + this.releaseLength;
- },
- setTimeScale: function( v ) {
- this.timeScale = v;
- this.setAttack( this.__unscaledAttackLength );
- this.setDecay( this.__unscaledDecayLength );
- this.setRelease( this.__unscaledReleaseLength );
- },
- beginAttack: function( time ) {
- this.state = this.STATE_ATTACK;
- this.attackStartTime = time;
- this.attackEndTime = time + this.attackLength;
- this.decayEndTime = this.attackEndTime + this.decayLength;
- },
- beginRelease: function( time ) {
- this.state = this.STATE_RELEASE;
- this.releaseStartValue = this.lastValue;
- this.releaseStartTime = time;
- this.releaseEndTime = time + this.releaseLength;
- },
- update: function( time ) {
- var scaledSustainLevel,
- value = 0,
- scaledValue = 0.5,
- map = SOROLLET.Math.map,
- interpolate = SOROLLET.Math.interpolate;
- scaledSustainLevel = map( this.sustainLevel, 0, 1, this.outputMinimumValue, this.outputMaximumValue );
- if( this.state == this.STATE_DONE ) {
- scaledValue = this.outputMinimumValue;
- } else if( this.state == this.STATE_ATTACK ) {
- if( time > this.attackEndTime ) {
- this.state = this.STATE_DECAY;
- scaledValue = this.outputMaximumValue;
- } else {
- scaledValue = map( time, this.attackStartTime, this.attackEndTime, this.outputMinimumValue, this.outputMaximumValue );
- }
- } else if( this.state == this.STATE_DECAY ) {
- if( time > this.decayEndTime ) {
- this.state = this.STATE_SUSTAIN;
- scaledValue = scaledSustainLevel;
- } else {
- scaledValue = map( time, this.attackEndTime, this.decayEndTime, this.outputMaximumValue, scaledSustainLevel );
- }
- } else if( this.state == this.STATE_SUSTAIN ) {
- scaledValue = scaledSustainLevel;
- } else if( this.state == this.STATE_RELEASE ) {
- if( time > this.releaseEndTime ) {
- this.state = this.STATE_DONE;
- scaledValue = this.outputMinimumValue;
- } else {
- scaledValue = map( time, this.releaseStartTime, this.releaseEndTime, this.releaseStartValue, this.outputMinimumValue );
- }
- }
- this.lastValue = scaledValue;
- return scaledValue;
- },
- getParams: function() {
- return {
- attack: this.__unscaledAttackLength,
- decay: this.__unscaledDecayLength,
- sustain: this.sustainLevel,
- release: this.__unscaledReleaseLength,
- outputMin: this.outputMinimumValue,
- outputMax: this.outputMaximumValue,
- timeScale: this.timeScale
- };
- },
- setParams: function( params ) {
- this.timeScale = params.timeScale;
- this.setOutputRange( params.outputMin, params.outputMax );
- this.setAttack( params.attack );
- this.setDecay( params.decay );
- this.setSustainLevel( params.sustain );
- this.setRelease( params.release );
- }
- };
- SOROLLET.Player = function( _samplingRate ) {
- 'use strict';
- var samplingRate = _samplingRate,
- inverseSamplingRate = 1.0 / samplingRate,
- secondsPerRow, secondsPerTick,
- lastPlayedTime = 0, // XXX KILL
- lastRowTime = 0, // XXX KILL
- loopStart = 0,
- outBuffer = [],
- scope = this;
- this.bpm = 100;
- this.linesPerBeat = 4;
- this.ticksPerLine = 12;
- this.currentRow = 0;
- this.currentOrder = 0;
- this.currentPattern = 0;
- this.repeat = true;
- this.finished = false;
- this.voices = [];
- this.patterns = [];
- this.orderList = [];
- this.eventsList = [];
- this.nextEventPosition = 0; // TODO position->index? or position ~~~ samples?
- this.timePosition = 0;
- this.position = 0;
-
- EventTarget.call( this );
- updateRowTiming();
- function updateRowTiming() {
- secondsPerRow = 60.0 / (scope.linesPerBeat * scope.bpm);
- secondsPerTick = secondsPerRow / scope.ticksPerLine;
- }
- this.play = function() {
- // having an updated event list is ESSENTIAL to playing!
- this.buildEventsList();
- }
- this.stop = function() {
- this.position = 0;
- loopStart = 0;
- //this.nextEventPosition = 0;
- this.jumpToOrder( 0, 0 );
- }
- this.jumpToOrder = function( orderIndex, row ) {
- // TODO if the new pattern to play has less rows than the current one,
- // make sure we don't play out of index
- changeToOrder( orderIndex );
- if( row === undefined ) {
- row = this.currentRow;
- }
- changeToRow( row );
-
- this.updateNextEventToOrderRow( orderIndex, row );
- var prevPosition = this.position;
- this.position = this.eventsList[ this.nextEventPosition ].timestampSamples + loopStart;
- }
- this.updateNextEventPosition = function() {
- var p = 0;
- for(var i = 0; i < this.eventsList.length; i++ ) {
-
- var ev = this.eventsList[i];
- if( ev.timestampSamples >= this.position ) {
- break;
- }
- p = i;
- }
- this.nextEventPosition = p;
- }
- this.updateNextEventToOrderRow = function( order, row ) {
- var p = 0;
-
- for(var i = 0; i < this.eventsList.length; i++) {
- var ev = this.eventsList[i];
- p = i;
- if( ev.TYPE_ROW_CHANGE == ev.type && ev.row == row && ev.order == order ) {
- break;
- }
- }
- this.nextEventPosition = p;
- }
- this.buildEventsList = function() {
- var t = 0,
- orderIndex = 0,
- patternIndex,
- pattern,
- samples = 0,
- samplesPerRow,
- trackCount = this.voices.length, // TODO it doesn't need to be a 1:1 correspondence
- lastTrackInstrument = new Array( trackCount ),
- lastTrackNote = new Array( trackCount );
- for (var i = 0; i < trackCount; i++) {
- lastTrackInstrument[i] = null;
- lastTrackNote[i] = null;
- }
- this.eventsList = [];
- samplesPerRow = (secondsPerRow * samplingRate + 0.5) >> 0; // Note: this should change if speed commands are implemented
- while ( orderIndex < this.orderList.length ) {
- var orderEv = new SOROLLET.PlayerEvent();
- orderEv.timestamp = t;
- orderEv.timestampSamples = samples;
- orderEv.type = orderEv.TYPE_ORDER_POSITION_CHANGE;
- orderEv.order = orderIndex;
- this.eventsList.push( orderEv );
- patternIndex = this.orderList[ orderIndex ];
- var ev = new SOROLLET.PlayerEvent();
- ev.timestamp = t;
- ev.timestampSamples = samples;
- ev.type = ev.TYPE_PATTERN_CHANGE;
- ev.pattern = patternIndex;
- this.eventsList.push( ev );
- pattern = this.patterns[ patternIndex ];
- for( var i = 0; i < pattern.rows.length; i++ ) {
- var ev = new SOROLLET.PlayerEvent();
- ev.timestamp = t;
- ev.timestampSamples = samples;
- ev.type = ev.TYPE_ROW_CHANGE;
- ev.row = i;
- ev.order = orderIndex;
-
- this.eventsList.push( ev );
- for (var j = 0; j < trackCount; j++) {
- var cell = pattern.getCell(i, j);
- // ~~ NOTE ON ~~ //
- if( cell.note !== null && cell.noteOff !== true /* TODO && pCell->getInstrument() != INSTRUMENT_NULL*/ ) {
- // TODO instrument = pCell->getInstrument();
- var ev = new SOROLLET.PlayerEvent();
- ev.timestamp = t;
- ev.timestampSamples = samples;
- ev.type = ev.TYPE_NOTE_ON;
- ev.note = cell.note
- // TODO ev.instrument = instrument;
- ev.instrument = j; // TODO tmp (see above)
- ev.volume = cell.volume;
-
- this.eventsList.push( ev );
- // TODO buildArpeggios(pCell, t, samples, mfSecondsPerRow, samplesPerRow, instrument, note, fVolume);
- // TODO Store this for later, so that if we get a new volume event we know to which instrument it applies
- // lastTrackInstrument[j] = instrument;
- // lastTrackNote[j] = note;
- }
- // ~~ NEW VOLUME ~~ //
- /* TODO else if (
- (NOTE_NULL == pCell->getNote() || NOTE_OFF == pCell->getNote()) &&
- INSTRUMENT_NULL == pCell->getInstrument() &&
- VOLUME_NULL != pCell->getVolume())
- {
- if (lastTrackInstrument[j] != INSTRUMENT_NULL)
- {
- event = new SorolletPlayerEvent();
- event->timestamp = t;
- event->timestampSamples = samples;
- event->type = SOROLLET_EVENT_VOLUME;
- event->instrument = lastTrackInstrument[j];
- event->volume = fVolume;
- addEvent(event);
- if (lastTrackNote[j] != NOTE_NULL)
- {
- buildArpeggios(pCell, t, samples, mfSecondsPerRow, samplesPerRow, instrument, lastTrackNote[j], fVolume);
- }
- }
- }*/
- // ~~ NOTE OFF ~~ //
- else if( cell.noteOff === true ) {
- // TODO if (lastTrackInstrument[j] != INSTRUMENT_NULL) {
- var ev = new SOROLLET.PlayerEvent();
- ev.timestamp = t;
- ev.timestampSamples = samples;
- ev.type = ev.TYPE_NOTE_OFF;
- // TODO ev.instrument = lastTrackInstrument[j];
- this.eventsList.push( ev );
- // }
- }
- /* TODO else if (pCell->getNote() != NOTE_OFF && lastTrackNote[j] != NOTE_NULL && lastTrackInstrument[j] != INSTRUMENT_NULL)
- {
- buildArpeggios(pCell, t, samples, mfSecondsPerRow, samplesPerRow, lastTrackInstrument[j], lastTrackNote[j], 1.0f);
- }*/
- }
- t += secondsPerRow;
- samples += samplesPerRow;
- }
- orderIndex++;
- }
- // End of the song --there can only be one of these events!!!
- var ev = new SOROLLET.PlayerEvent();
- ev.timestamp = t;
- ev.timestampSamples = samples;
- ev.type = ev.TYPE_SONG_END;
- this.eventsList.push( ev );
- }
- this.getBuffer = function( numSamples ) {
-
- var outBuffer = [],
- remainingSamples = numSamples,
- bufferEndSamples = this.position + numSamples,
- segmentStartSamples = this.position,
- currentEvent,
- currentEventStart,
- intervalSamples,
- bufferPosition = 0;
-
- for( var i = 0; i < numSamples; i++ ) {
- outBuffer[i] = 0;
- }
- do {
- if( this.finished && this.repeat ) {
- this.jumpToOrder( 0, 0 );
- this.finished = false;
- }
- if( this.nextEventPosition == this.eventsList.length ) {
- return outBuffer;
- }
- currentEvent = this.eventsList[ this.nextEventPosition ];
- currentEventStart = loopStart + currentEvent.timestampSamples;
- if( currentEventStart >= bufferEndSamples ) {
- break;
- }
- intervalSamples = currentEventStart - segmentStartSamples;
- // Get buffer UNTIL the event
- if (intervalSamples > 0) {
-
- processBuffer(outBuffer, intervalSamples, bufferPosition );
-
- remainingSamples -= intervalSamples;
- segmentStartSamples = currentEventStart;
- this.position += intervalSamples;
- bufferPosition += intervalSamples;
- }
- // Apply the event
- if( currentEvent.TYPE_ORDER_POSITION_CHANGE == currentEvent.type ) {
- changeToOrder( currentEvent.order );
- /*} else if( currentEvent.TYPE_PATTERN_CHANGE == currentEvent.type ) {
- //this.currentPattern = currentEvent.pattern;
- changeToPattern( currentEvent.pattern );
- */
- } else if( currentEvent.TYPE_ROW_CHANGE == currentEvent.type ) {
- changeToRow( currentEvent.row );
- } else if( currentEvent.TYPE_NOTE_ON == currentEvent.type) {
- var voice = this.voices[ currentEvent.instrument ];
- voice.sendNoteOn( currentEvent.note, currentEvent.volume );
- /*} TODO else if( currentEvent.TYPE_EVENT_VOLUME == currentEvent.type ) {
- var voice = this.voices[ currentEvent.instrument ];
- voice.sendCurrentNoteVolume( currentEvent.volume );*/
- } else if( currentEvent.TYPE_NOTE_OFF == currentEvent.type ) {
- var voice = this.voices[ currentEvent.instrument ];
- voice.sendNoteOff();
- } else if( currentEvent.TYPE_SONG_END == currentEvent.type ) {
-
- loopStart = currentEventStart;
- this.finished = true;
- changeToEnd();
- }
- this.nextEventPosition++;
- } while ( this.nextEventPosition < this.eventsList.length && remainingSamples > 0 );
- if(remainingSamples > 0) {
- processBuffer( outBuffer, remainingSamples, bufferPosition );
- }
- this.position += remainingSamples;
- this.timePosition += numSamples * inverseSamplingRate;
- return outBuffer;
- }
- function processBuffer( buffer, numSamples, startPosition ) {
- var tmpBuffer = [],
- endPosition = startPosition + numSamples;
- // Process envelopes, if applicable
- /* TODO SorolletPattern* pPattern = &mPatterns[miCurrentPattern];
- for (i = 0; i < miTrackCount; i++)
- {
- if (pPattern->trackHasEnvelopes(i) && mTracksAutomationDevices[i].isActive())
- {
- SorolletDeviceAutomation* deviceAutomation = &(mTracksAutomationDevices[i]);
- SorolletEnvelope** vEnvelopes = pPattern->getTrackEnvelopes(i);
- int numEnvelopes = pPattern->getTrackEnvelopesNumber(i);
- for (j = 0; j < numEnvelopes; j++)
- {
- SorolletEnvelope* pEnvelope = vEnvelopes[j];
- int instrumentIndex = deviceAutomation->getInstrumentIndex();
- int automationParameterIndex = pEnvelope->getAutomationParameterIndex();
- int instrumentParameterIndex = deviceAutomation->getParameterMappings()[automationParameterIndex];
- float value = pEnvelope->getValueAtRow(miCurrentRow);
- mVoices[i].setVSTParameter(instrumentParameterIndex, value);
- }
- }
- }*/
- // ~~~~
- for( var i = startPosition; i < endPosition; i++ ) {
- buffer[ i ] = 0;
- }
- for (var i = 0; i < scope.voices.length; i++) {
-
- var voice = scope.voices[i];
- tmpBuffer = voice.getBuffer( numSamples );
- for (var j = 0; j < numSamples; j++) {
- buffer[ j + startPosition ] += tmpBuffer[ j ];
- }
- }
- for (var i = startPosition; i < endPosition; i++) {
- buffer[i] = SOROLLET.Math.clip( buffer[i], -1.0, 1.0 );
- }
- }
- function changeToEnd() {
- scope.dispatchEvent({ type: 'songEnded' });
- }
- function changeToRow( value ) {
- var previousValue = scope.currentRow;
-
- scope.currentRow = value;
- scope.dispatchEvent({ type: 'rowChanged', row: value, previousRow: previousValue, pattern: scope.currentPattern, order: scope.currentOrder });
- }
- function changeToPattern( value ) {
- var previousValue = scope.currentPattern;
-
- scope.currentPattern = value;
- scope.dispatchEvent({ type: 'patternChanged', pattern: value, previousPattern: previousValue, order: scope.currentOrder, row: scope.currentRow });
- }
-
- function changeToOrder( value ) {
- var previousValue = scope.currentOrder;
-
- scope.currentOrder = value;
- scope.dispatchEvent({ type: 'orderChanged', order: value, previousOrder: previousValue, pattern: scope.currentPattern, row: scope.currentRow });
- changeToPattern( scope.orderList[ value ] );
- }
- this.setBPM = function( value ){
- this.bpm = value;
- updateRowTiming();
- this.dispatchEvent({ type: 'bpmChanged', bpm: value });
- }
- this.getSecondsPerRow = function() {
- return secondsPerRow;
- }
- this.getCurrentPattern = function() {
- return this.patterns[ this.currentPattern ];
- }
- this.addPattern = function( pattern ) {
- this.patterns.push( pattern );
- this.dispatchEvent({ type: 'change', player: this });
- return this.patterns.length - 1;
- }
- this.addToOrderList = function( patternIndex ) {
- this.orderList.push( patternIndex );
- this.dispatchEvent({ type: 'change', player: this });
- }
- this.addToOrderListAfter = function( patternIndex, orderListIndex ) {
- this.orderList.splice( orderListIndex, 0, patternIndex );
- this.dispatchEvent({ type: 'change', player: this });
- }
- this.removeFromOrderList = function( orderListIndex ) {
- this.orderList.splice( orderListIndex, 1 );
- this.dispatchEvent({ type: 'change', player: this });
- }
- this.setOrderValueAt = function( orderIndex, value ) {
- if( this.orderList.length <= orderIndex ) {
- console.error( 'Sorollet.Player.setOrderValueAt: trying to set value for non-existing order', orderIndex);
- return;
- } else if( this.patterns.length <= value ) {
- console.error( 'Sorollet.Player.setOrderValueAt: trying to set value for non-existing pattern', orderIndex);
- }
- this.orderList[ orderIndex ] = value;
- this.currentPattern = this.orderList[ orderIndex ];
- this.dispatchEvent({ type: 'change', player: this });
- }
- }
- SOROLLET.PlayerEvent = function() {
- this.timestamp = 0;
- this.timestampSamples = 0;
- this.type = null;
- this.instrument = null;
- this.volume = 0;
- };
- SOROLLET.PlayerEvent.prototype = {
- TYPE_NULL: 0,
- TYPE_NOTE_OFF: 1,
- TYPE_NOTE_ON: 2,
- TYPE_VOLUME: 3,
- TYPE_EFFECT: 4,
- TYPE_ROW_CHANGE: 5,
- TYPE_PATTERN_CHANGE: 6,
- TYPE_ORDER_POSITION_CHANGE: 7,
- TYPE_SONG_END: 8
- };
- SOROLLET.Pattern = function( numTracks, length ) {
- 'use strict';
- this.rows = [];
- for( var i = 0; i < length; i++ ) {
-
- var row = [];
-
- for( var j = 0; j < numTracks; j++ ) {
- row.push( new SOROLLET.PatternCell() );
- }
- this.rows.push( row );
- }
- this.getCell = function( i, j ) {
- return this.rows[i][j];
- }
- }
- SOROLLET.PatternCell = function() {
-
- this.reset();
- }
- SOROLLET.PatternCell.prototype = {
- note: null,
- noteOff: false,
- volume: null,
- reset: function() {
- this.note = null;
- this.noteOff = false;
- this.volume = null;
- }
- };
- /**
- * @author mr.doob / http://mrdoob.com/
- */
- var EventTarget = function () {
- var listeners = {};
- this.addEventListener = function ( type, listener ) {
- if ( listeners[ type ] == undefined ) {
- listeners[ type ] = [];
- }
- if ( listeners[ type ].indexOf( listener ) === - 1 ) {
- listeners[ type ].push( listener );
- }
- };
- this.dispatchEvent = function ( event ) {
- for ( var listener in listeners[ event.type ] ) {
- listeners[ event.type ][ listener ]( event );
- }
- };
- this.removeEventListener = function ( type, listener ) {
- var index = listeners[ type ].indexOf( listener );
- if ( index !== - 1 ) {
- listeners[ type ].splice( index, 1 );
- }
- };
- };
- /*
- JS Signals <http://millermedeiros.github.com/js-signals/>
- Released under the MIT license
- Author: Miller Medeiros
- Version: 0.7.4 - Build: 252 (2012/02/24 10:30 PM)
- */
- (function(h){function g(a,b,c,d,e){this._listener=b;this._isOnce=c;this.context=d;this._signal=a;this._priority=e||0}function f(a,b){if(typeof a!=="function")throw Error("listener is a required param of {fn}() and should be a Function.".replace("{fn}",b));}var e={VERSION:"0.7.4"};g.prototype={active:!0,params:null,execute:function(a){var b;this.active&&this._listener&&(a=this.params?this.params.concat(a):a,b=this._listener.apply(this.context,a),this._isOnce&&this.detach());return b},detach:function(){return this.isBound()?
- this._signal.remove(this._listener,this.context):null},isBound:function(){return!!this._signal&&!!this._listener},getListener:function(){return this._listener},_destroy:function(){delete this._signal;delete this._listener;delete this.context},isOnce:function(){return this._isOnce},toString:function(){return"[SignalBinding isOnce:"+this._isOnce+", isBound:"+this.isBound()+", active:"+this.active+"]"}};e.Signal=function(){this._bindings=[];this._prevParams=null};e.Signal.prototype={memorize:!1,_shouldPropagate:!0,
- active:!0,_registerListener:function(a,b,c,d){var e=this._indexOfListener(a,c);if(e!==-1){if(a=this._bindings[e],a.isOnce()!==b)throw Error("You cannot add"+(b?"":"Once")+"() then add"+(!b?"":"Once")+"() the same listener without removing the relationship first.");}else a=new g(this,a,b,c,d),this._addBinding(a);this.memorize&&this._prevParams&&a.execute(this._prevParams);return a},_addBinding:function(a){var b=this._bindings.length;do--b;while(this._bindings[b]&&a._priority<=this._bindings[b]._priority);
- this._bindings.splice(b+1,0,a)},_indexOfListener:function(a,b){for(var c=this._bindings.length,d;c--;)if(d=this._bindings[c],d._listener===a&&d.context===b)return c;return-1},has:function(a,b){return this._indexOfListener(a,b)!==-1},add:function(a,b,c){f(a,"add");return this._registerListener(a,!1,b,c)},addOnce:function(a,b,c){f(a,"addOnce");return this._registerListener(a,!0,b,c)},remove:function(a,b){f(a,"remove");var c=this._indexOfListener(a,b);c!==-1&&(this._bindings[c]._destroy(),this._bindings.splice(c,
- 1));return a},removeAll:function(){for(var a=this._bindings.length;a--;)this._bindings[a]._destroy();this._bindings.length=0},getNumListeners:function(){return this._bindings.length},halt:function(){this._shouldPropagate=!1},dispatch:function(a){if(this.active){var b=Array.prototype.slice.call(arguments),c=this._bindings.length,d;if(this.memorize)this._prevParams=b;if(c){d=this._bindings.slice();this._shouldPropagate=!0;do c--;while(d[c]&&this._shouldPropagate&&d[c].execute(b)!==!1)}}},forget:function(){this._prevParams=
- null},dispose:function(){this.removeAll();delete this._bindings;delete this._prevParams},toString:function(){return"[Signal active:"+this.active+" numListeners:"+this.getNumListeners()+"]"}};typeof define==="function"&&define.amd?define(e):typeof module!=="undefined"&&module.exports?module.exports=e:h.signals=e})(this);var UI = {};
- UI.Element = function () {};
- UI.Element.prototype = {
- setClass: function ( name ) {
- this.dom.className = name;
- return this;
- },
- // styles
- setStyle: function ( style, array ) {
- for ( var i = 0; i < array.length; i ++ ) {
- this.dom.style[ style ] = array[ i ];
- }
- },
- setLeft: function () {
- this.setStyle( 'left', arguments );
- return this;
- },
- setTop: function () {
- this.setStyle( 'top', arguments );
- return this;
- },
- setRight: function () {
- this.setStyle( 'right', arguments );
- return this;
- },
- setBottom: function () {
- this.setStyle( 'bottom', arguments );
- return this;
- },
- setWidth: function () {
- this.setStyle( 'width', arguments );
- return this;
- },
- setHeight: function () {
- this.setStyle( 'height', arguments );
- return this;
- },
- //
- setBorder: function () {
- this.setStyle( 'border', arguments );
- return this;
- },
- setBorderTop: function () {
- this.setStyle( 'borderTop', arguments );
- return this;
- },
- setBorderBottom: function () {
- this.setStyle( 'borderBottom', arguments );
- return this;
- },
- setBorderLeft: function () {
- this.setStyle( 'borderLeft', arguments );
- return this;
- },
- setBorderRight: function () {
- this.setStyle( 'borderRight', arguments );
- return this;
- },
- //
- setMargin: function () {
- this.setStyle( 'margin', arguments );
- return this;
- },
- setMarginTop: function () {
- this.setStyle( 'marginTop', arguments );
- return this;
- },
- setMarginBottom: function () {
- this.setStyle( 'marginBottom', arguments );
- return this;
- },
- setMarginLeft: function () {
- this.setStyle( 'marginLeft', arguments );
- return this;
- },
- setMarginRight: function () {
- this.setStyle( 'marginRight', arguments );
- return this;
- },
- //
- setPadding: function () {
- this.setStyle( 'padding', arguments );
- return this;
- },
- //
- setFloat: function () {
- this.setStyle( 'float', arguments );
- return this;
- },
- //
- setFontSize: function () {
- this.setStyle( 'fontSize', arguments );
- return this;
- },
- setFontWeight: function () {
- this.setStyle( 'fontWeight', arguments );
- return this;
- },
- //
- setColor: function () {
- this.setStyle( 'color', arguments );
- return this;
- },
- setBackgroundColor: function () {
- this.setStyle( 'backgroundColor', arguments );
- return this;
- },
- setDisplay: function () {
- this.setStyle( 'display', arguments );
- return this;
- },
- setOverflow: function () {
- this.setStyle( 'overflow', arguments );
- return this;
- },
- //
- setCursor: function () {
- this.setStyle( 'cursor', arguments );
- return this;
- },
- // content
- setTextContent: function ( value ) {
- this.dom.textContent = value;
- return this;
- },
- // events
- onMouseOver: function ( callback ) {
- this.dom.addEventListener( 'mouseover', callback, false );
- return this;
- },
- onMouseOut: function ( callback ) {
- this.dom.addEventListener( 'mouseout', callback, false );
- return this;
- },
- onClick: function ( callback ) {
- this.dom.addEventListener( 'click', callback, false );
- return this;
- }
- }
- // Panel
- UI.Panel = function ( position ) {
- UI.Element.call( this );
- var dom = document.createElement( 'div' );
- dom.style.position = position || 'relative';
- dom.style.marginBottom = '10px';
- dom.style.userSelect = 'none';
- dom.style.WebkitUserSelect = 'none';
- dom.style.MozUserSelect = 'none';
- this.dom = dom;
- return this;
- };
- UI.Panel.prototype = Object.create( UI.Element.prototype );
- UI.Panel.prototype.add = function () {
- for ( var i = 0; i < arguments.length; i ++ ) {
- this.dom.appendChild( arguments[ i ].dom );
- }
- return this;
- };
- // Text
- UI.Text = function ( position ) {
- UI.Element.call( this );
- var dom = document.createElement( 'span' );
- dom.style.position = position || 'relative';
- dom.style.cursor = 'default';
- this.dom = dom;
- return this;
- };
- UI.Text.prototype = Object.create( UI.Element.prototype );
- UI.Text.prototype.setValue = function ( value ) {
- this.dom.textContent = value;
- return this;
- };
- // Input
- UI.Input = function ( position ) {
- UI.Element.call( this );
- var scope = this;
- var dom = document.createElement( 'input' );
- dom.style.position = position || 'relative';
- dom.style.padding = '2px';
- dom.style.marginTop = '-2px';
- dom.style.marginLeft = '-2px';
- dom.style.border = '1px solid #ccc';
- this.dom = dom;
- this.onChangeCallback = null;
- this.dom.addEventListener( 'change', function ( event ) {
- if ( scope.onChangeCallback ) scope.onChangeCallback();
- }, false );
- return this;
- };
- UI.Input.prototype = Object.create( UI.Element.prototype );
- UI.Input.prototype.getValue = function () {
- return this.dom.value;
- };
- UI.Input.prototype.setValue = function ( value ) {
- this.dom.value = value;
- return this;
- };
- UI.Input.prototype.onChange = function ( callback ) {
- this.onChangeCallback = callback;
- return this;
- };
- // Select
- UI.Select = function ( position ) {
- UI.Element.call( this );
- var scope = this;
- var dom = document.createElement( 'select' );
- dom.style.position = position || 'relative';
- dom.style.width = '64px';
- dom.style.height = '16px';
- dom.style.border = '0px';
- dom.style.padding = '0px';
- this.dom = dom;
- this.onChangeCallback = null;
- this.dom.addEventListener( 'change', function ( event ) {
- if ( scope.onChangeCallback ) scope.onChangeCallback();
- }, false );
- return this;
- };
- UI.Select.prototype = Object.create( UI.Element.prototype );
- UI.Select.prototype.setMultiple = function ( bool ) {
- this.dom.multiple = bool;
- return this;
- };
- UI.Select.prototype.setOptions = function ( options ) {
- while ( this.dom.children.length > 0 ) {
- this.dom.removeChild( this.dom.firstChild );
- }
- for ( var key in options ) {
- var option = document.createElement( 'option' );
- option.value = key;
- option.innerHTML = options[ key ];
- this.dom.appendChild( option );
- }
- return this;
- };
- UI.Select.prototype.getValue = function () {
- return this.dom.value;
- };
- UI.Select.prototype.setValue = function ( value ) {
- this.dom.value = value;
- return this;
- };
- UI.Select.prototype.onChange = function ( callback ) {
- this.onChangeCallback = callback;
- return this;
- };
- // FancySelect
- UI.FancySelect = function ( position ) {
- UI.Element.call( this );
- var scope = this;
- var dom = document.createElement( 'div' );
- dom.style.position = position || 'relative';
- dom.style.background = '#fff';
- dom.style.border = '1px solid #ccc';
- dom.style.padding = '0';
- dom.style.cursor = 'default';
- dom.style.overflow = 'auto';
- this.dom = dom;
- this.onChangeCallback = null;
- this.options = [];
- this.selectedValue = null;
- return this;
- };
- UI.FancySelect.prototype = Object.create( UI.Element.prototype );
- UI.FancySelect.prototype.setOptions = function ( options ) {
- var scope = this;
- while ( scope.dom.children.length > 0 ) {
- scope.dom.removeChild( scope.dom.firstChild );
- }
- scope.options = [];
- var generateOptionCallback = function ( element, value ) {
- return function ( event ) {
- for ( var i = 0; i < scope.options.length; i ++ ) {
- scope.options[ i ].style.backgroundColor = '#f0f0f0';
- }
- element.style.backgroundColor = '#f0f0f0';
- scope.selectedValue = value;
- if ( scope.onChangeCallback ) scope.onChangeCallback();
- }
- };
- for ( var key in options ) {
- var option = document.createElement( 'div' );
- option.style.padding = '4px';
- option.style.whiteSpace = 'nowrap';
- option.innerHTML = options[ key ];
- option.value = key;
- scope.dom.appendChild( option );
- scope.options.push( option );
- option.addEventListener( 'click', generateOptionCallback( option, key ), false );
- }
- return scope;
- };
- UI.FancySelect.prototype.getValue = function () {
- return this.selectedValue;
- };
- UI.FancySelect.prototype.setValue = function ( value ) {
- // must convert raw value into string for compatibility with UI.Select
- // which uses string values (initialized from options keys)
- var key = value ? value.toString() : value;
- for ( var i = 0; i < this.options.length; i ++ ) {
- var element = this.options[ i ];
- if ( element.value === key ) {
- element.style.backgroundColor = '#f0f0f0';
- } else {
- element.style.backgroundColor = '';
- }
- }
- this.selectedValue = value;
- return this;
- };
- UI.FancySelect.prototype.…
Large files files are truncated, but you can click here to view the full file