Tone.js/Tone/source/OmniOscillator.js
Yotam Mann a4cc79cfde stopped state doesn't wait for on ended event
the oneneded event is inconsistent when the source is not connected
directly to Master (such as in the case of an LFO).

Fixes #34
2014-10-08 11:59:31 -04:00

231 lines
No EOL
6.4 KiB
JavaScript

define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator", "Tone/source/PulseOscillator", "Tone/source/PWMOscillator"],
function(Tone){
"use strict";
/**
* @class An OmniOscillator can be a sine|square|triangle|sawtooth|pulse|pwm
*
* @extends {Tone.Oscillator}
* @constructor
* @param {frequency} frequency frequency of the oscillator (meaningless for noise types)
* @param {string} type the type of the oscillator
*/
Tone.OmniOscillator = function(){
var options = this.optionsObject(arguments, ["frequency", "type"], Tone.OmniOscillator.defaults);
Tone.Source.call(this);
/**
* the frequency control
* (doesn't do anything for noises)
* @type {Tone.Signal}
*/
this.frequency = new Tone.Signal(options.frequency);
/**
* the detune control
* (doesn't do anything for noises)
* @type {Tone.Signal}
*/
this.detune = new Tone.Signal(options.detune);
/**
* the type of the oscillator source
* @type {string}
* @private
*/
this._sourceType = undefined;
/**
* the oscillator
* @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
* @private
*/
this._oscillator = null;
/**
* callback which is invoked when the oscillator is stoped
* @type {function()}
*/
this.onended = options.onended;
//set the oscillator
this.setType(options.type);
};
Tone.extend(Tone.OmniOscillator, Tone.Oscillator);
/**
* default values
* @static
* @type {Object}
* @const
*/
Tone.OmniOscillator.defaults = {
"frequency" : 440,
"detune" : 0,
"type" : "sine",
"width" : 0.4, //only applies if the oscillator is set to "pulse",
"modulationFrequency" : 0.4, //only applies if the oscillator is set to "pwm",
"onended" : function(){}
};
/**
* start the oscillator
* @param {Tone.Time} [time=now] the time to start the oscillator
*/
Tone.OmniOscillator.prototype.start = function(time){
if (this.state === Tone.Source.State.STOPPED){
this.state = Tone.Source.State.STARTED;
this._oscillator.start(time);
}
};
/**
* start the oscillator
* @param {Tone.Time} [time=now] the time to start the oscillator
*/
Tone.OmniOscillator.prototype.stop = function(time){
if (this.state === Tone.Source.State.STARTED){
if (!time){
this.state = Tone.Source.State.STOPPED;
}
this._oscillator.stop(time);
}
};
/**
* set the type of the oscillator
* @param {string} type sine|square|triangle|sawtooth|pulse|pwm
*/
Tone.OmniOscillator.prototype.setType = function(type){
if (type === "sine" || type === "square" || type === "triangle" || type === "sawtooth"){
if (this._sourceType !== OmniOscType.Oscillator){
this._sourceType = OmniOscType.Oscillator;
this._createNewOscillator(Tone.Oscillator);
}
this._oscillator.setType(type);
} else if (type === "pwm"){
if (this._sourceType !== OmniOscType.PWMOscillator){
this._sourceType = OmniOscType.PWMOscillator;
this._createNewOscillator(Tone.PWMOscillator);
}
} else if (type === "pulse"){
if (this._sourceType !== OmniOscType.PulseOscillator){
this._sourceType = OmniOscType.PulseOscillator;
this._createNewOscillator(Tone.PulseOscillator);
}
} else {
throw new TypeError("Tone.OmniOscillator does not support type "+type);
}
};
/**
* @returns {string} the type of oscillator
*/
Tone.OmniOscillator.prototype.getType = function(){
if (this._sourceType === OmniOscType.PulseOscillator){
return "pulse";
} else if (this._sourceType === OmniOscType.PWMOscillator){
return "pwm";
} else if (this._sourceType === OmniOscType.Oscillator){
return this._oscillator.getType();
}
};
/**
* connect the oscillator to the frequency and detune signals
* @private
*/
Tone.OmniOscillator.prototype._createNewOscillator = function(OscillatorConstructor){
if (this._oscillator !== null){
var oldOsc = this._oscillator;
oldOsc.stop();
oldOsc.onended = function(){
oldOsc.dispose();
oldOsc = null;
};
}
this._oscillator = new OscillatorConstructor();
this.frequency.connect(this._oscillator.frequency);
this.detune.connect(this._oscillator.detune);
this._oscillator.connect(this.output);
if (this.state === Tone.Source.State.STARTED){
this._oscillator.start();
}
this._oscillator.onended = this._onended.bind(this);
};
/**
* internal onended callback
* @private
*/
Tone.OmniOscillator.prototype._onended = function(){
this.onended();
};
/**
* set the width of the PulseOscillator
* @throws {Error} If the type of oscillator is not "pulse"
* @param {number} width the width of the pulse oscillator
*/
Tone.OmniOscillator.prototype.setWidth = function(width){
if (this._sourceType === OmniOscType.PulseOscillator){
this._oscillator.setWidth(width);
} else {
throw new Error("Invalid call to 'setWidth'. OmniOscillator type must be set to type 'pulse'.");
}
};
/**
* set the modulation frequency of the PWMOscillator
* @throws {Error} If the type of oscillator is not "pwm"
* @param {Tone.Time} freq the modulation frequency of the pwm
*/
Tone.OmniOscillator.prototype.setModulationFrequency = function(freq){
if (this._sourceType === OmniOscType.PWMOscillator){
this._oscillator.setModulationFrequency(freq);
} else {
throw new Error("Invalid call to 'setModulationFrequency'. OmniOscillator type must be set to type 'pwm'.");
}
};
/**
* bulk setter
* @param {Object} params
*/
Tone.OmniOscillator.prototype.set = function(params){
if (!this.isUndef(params.type)) this.setType(params.type);
if (!this.isUndef(params.onended)) this.onended = params.onended;
if (!this.isUndef(params.frequency)) this.setFrequency(params.frequency);
if (!this.isUndef(params.detune)) this.detune.setValue(params.detune);
if (!this.isUndef(params.width)) this.setWidth(params.width);
if (!this.isUndef(params.modulationFrequency)) this.setModulationFrequency(params.modulationFrequency);
Tone.Source.prototype.set.call(this, params);
};
/**
* clean up
*/
Tone.OmniOscillator.prototype.dispose = function(){
Tone.Source.prototype.dispose.call(this);
this.detune.dispose();
this.frequency.dispose();
this._oscillator.dispose();
this.detune = null;
this.frequency = null;
this._oscillator = null;
this._sourceType = null;
};
/**
* @enum {string}
*/
var OmniOscType = {
PulseOscillator : "PulseOscillator",
PWMOscillator : "PWMOscillator",
Oscillator : "Oscillator"
};
return Tone.OmniOscillator;
});