Tone.js/Tone/source/Oscillator.js

256 lines
6.3 KiB
JavaScript
Raw Normal View History

2014-12-19 21:39:50 +00:00
define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/source/Source", "Tone/core/Transport"],
2014-06-15 21:36:52 +00:00
function(Tone){
"use strict";
2014-06-15 21:36:52 +00:00
/**
2014-07-20 22:17:24 +00:00
* @class Oscilator with start, pause, stop and sync to Transport methods
2014-06-15 21:36:52 +00:00
*
* @constructor
2014-06-16 01:00:22 +00:00
* @extends {Tone.Source}
2015-06-14 00:20:36 +00:00
* @param {Frequency} [frequency=440] starting frequency
2014-12-02 06:42:08 +00:00
* @param {string} [type="sine"] type of oscillator (sine|square|triangle|sawtooth)
2015-02-27 16:19:45 +00:00
* @example
* var osc = new Tone.Oscillator(440, "sine");
2014-06-15 21:36:52 +00:00
*/
Tone.Oscillator = function(){
var options = this.optionsObject(arguments, ["frequency", "type"], Tone.Oscillator.defaults);
2015-02-02 01:38:06 +00:00
Tone.Source.call(this, options);
2014-06-17 16:15:10 +00:00
/**
* the main oscillator
* @type {OscillatorNode}
* @private
2014-06-17 16:15:10 +00:00
*/
this._oscillator = null;
2014-08-21 05:03:51 +00:00
2014-06-17 16:15:10 +00:00
/**
2015-02-27 16:19:45 +00:00
* The frequency control signal in hertz.
2015-06-13 23:50:39 +00:00
* @type {Frequency}
* @signal
2014-06-17 16:15:10 +00:00
*/
this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);
2014-06-15 21:36:52 +00:00
2014-07-20 22:17:24 +00:00
/**
2015-02-27 16:19:45 +00:00
* The detune control signal in cents.
2015-06-13 23:50:39 +00:00
* @type {Cents}
* @signal
2014-07-20 22:17:24 +00:00
*/
this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);
2014-07-20 22:17:24 +00:00
/**
* the periodic wave
* @type {PeriodicWave}
* @private
*/
this._wave = null;
/**
* the phase of the oscillator
* between 0 - 360
* @type {number}
* @private
*/
this._phase = options.phase;
/**
* the type of the oscillator
* @type {string}
* @private
*/
2015-03-01 00:35:27 +00:00
this._type = null;
2014-06-17 16:15:10 +00:00
//setup
2015-03-01 00:35:27 +00:00
this.type = options.type;
this.phase = this._phase;
2015-04-05 18:53:27 +00:00
this._readOnly(["frequency", "detune"]);
2014-06-15 21:36:52 +00:00
};
2014-06-16 01:00:22 +00:00
Tone.extend(Tone.Oscillator, Tone.Source);
/**
* the default parameters
* @type {Object}
*/
Tone.Oscillator.defaults = {
"type" : "sine",
"frequency" : 440,
"detune" : 0,
"phase" : 0
};
2014-06-15 21:36:52 +00:00
/**
* start the oscillator
2015-06-14 00:20:36 +00:00
* @param {Time} [time=now]
2015-02-02 02:32:07 +00:00
* @private
2014-06-15 21:36:52 +00:00
*/
2015-02-02 02:32:07 +00:00
Tone.Oscillator.prototype._start = function(time){
//new oscillator with previous values
this._oscillator = this.context.createOscillator();
this._oscillator.setPeriodicWave(this._wave);
//connect the control signal to the oscillator frequency & detune
this._oscillator.connect(this.output);
this.frequency.connect(this._oscillator.frequency);
this.detune.connect(this._oscillator.detune);
//start the oscillator
this._oscillator.start(this.toSeconds(time));
2014-06-19 05:40:16 +00:00
};
/**
* stop the oscillator
2015-02-27 16:19:45 +00:00
* @private
2015-06-14 00:20:36 +00:00
* @param {Time} [time=now] (optional) timing parameter
* @returns {Tone.Oscillator} this
2014-06-19 05:40:16 +00:00
*/
2015-02-02 02:32:07 +00:00
Tone.Oscillator.prototype._stop = function(time){
2015-02-23 05:29:49 +00:00
if (this._oscillator){
this._oscillator.stop(this.toSeconds(time));
this._oscillator = null;
}
return this;
2014-06-15 21:36:52 +00:00
};
/**
2015-02-27 16:19:45 +00:00
* Sync the signal to the Transport's bpm. Any changes to the transports bpm,
* will also affect the oscillators frequency.
* @returns {Tone.Oscillator} this
2015-02-27 16:19:45 +00:00
* @example
2015-06-14 01:54:20 +00:00
* Tone.Transport.bpm.value = 120;
* osc.frequency.value = 440;
* osc.syncFrequency();
* Tone.Transport.bpm.value = 240;
* // the frequency of the oscillator is doubled to 880
2014-06-15 21:36:52 +00:00
*/
Tone.Oscillator.prototype.syncFrequency = function(){
Tone.Transport.syncSignal(this.frequency);
return this;
2014-06-15 21:36:52 +00:00
};
/**
2015-02-27 16:19:45 +00:00
* Unsync the oscillator's frequency from the Transport.
2015-06-14 01:54:20 +00:00
* See Tone.Oscillator#syncFrequency.
* @returns {Tone.Oscillator} this
*/
Tone.Oscillator.prototype.unsyncFrequency = function(){
2015-02-21 19:06:27 +00:00
Tone.Transport.unsyncSignal(this.frequency);
return this;
};
2014-06-15 21:36:52 +00:00
/**
2015-02-27 16:19:45 +00:00
* The type of the oscillator: either sine, square, triangle, or sawtooth.
2015-06-14 01:54:20 +00:00
* <br><br>
* Uses PeriodicWave internally even for native types so that it can set the phase.
* PeriodicWave equations are from the
* <a href="https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp&sq=package:chromium">Web Audio Source code</a>
2014-06-16 01:00:22 +00:00
*
* @memberOf Tone.Oscillator#
* @type {string}
* @name type
2015-02-27 16:19:45 +00:00
* @example
* osc.type = "square";
2014-06-15 21:36:52 +00:00
*/
Object.defineProperty(Tone.Oscillator.prototype, "type", {
get : function(){
return this._type;
},
set : function(type){
var originalType = type;
var fftSize = 4096;
var periodicWaveSize = fftSize / 2;
var real = new Float32Array(periodicWaveSize);
var imag = new Float32Array(periodicWaveSize);
var partialCount = 1;
var partial = /(sine|triangle|square|sawtooth)(\d+)$/.exec(type);
if (partial){
partialCount = parseInt(partial[2]);
type = partial[1];
partialCount = Math.max(partialCount, 2);
periodicWaveSize = partialCount;
}
var shift = this._phase;
for (var n = 1; n < periodicWaveSize; ++n) {
var piFactor = 2 / (n * Math.PI);
var b;
switch (type) {
case "sine":
b = (n <= partialCount) ? 1 : 0;
break;
case "square":
b = (n & 1) ? 2 * piFactor : 0;
break;
case "sawtooth":
b = piFactor * ((n & 1) ? 1 : -1);
break;
case "triangle":
if (n & 1) {
b = 2 * (piFactor * piFactor) * ((((n - 1) >> 1) & 1) ? -1 : 1);
} else {
b = 0;
}
break;
default:
throw new TypeError("invalid oscillator type: "+type);
}
if (b !== 0){
real[n] = -b * Math.sin(shift * n);
imag[n] = b * Math.cos(shift * n);
} else {
real[n] = 0;
imag[n] = 0;
}
}
var periodicWave = this.context.createPeriodicWave(real, imag);
this._wave = periodicWave;
if (this._oscillator !== null){
this._oscillator.setPeriodicWave(this._wave);
}
this._type = originalType;
}
});
2015-02-01 20:48:20 +00:00
2014-12-19 21:39:50 +00:00
/**
2015-02-27 16:19:45 +00:00
* The phase of the oscillator in degrees.
* @memberOf Tone.Oscillator#
2015-06-14 00:20:36 +00:00
* @type {Degrees}
* @name phase
2015-02-27 16:19:45 +00:00
* @example
* osc.phase = 180; //flips the phase of the oscillator
2014-12-19 21:39:50 +00:00
*/
Object.defineProperty(Tone.Oscillator.prototype, "phase", {
get : function(){
return this._phase * (180 / Math.PI);
},
set : function(phase){
this._phase = phase * Math.PI / 180;
//reset the type
this.type = this._type;
}
});
2014-12-19 21:39:50 +00:00
/**
* dispose and disconnect
* @return {Tone.Oscillator} this
*/
2015-02-02 03:05:24 +00:00
Tone.Oscillator.prototype.dispose = function(){
Tone.Source.prototype.dispose.call(this);
if (this._oscillator !== null){
this._oscillator.disconnect();
this._oscillator = null;
}
2015-04-05 18:53:27 +00:00
this._wave = null;
this._writable(["frequency", "detune"]);
this.frequency.dispose();
this.frequency = null;
this.detune.dispose();
this.detune = null;
2015-02-02 03:05:24 +00:00
return this;
};
return Tone.Oscillator;
});