Tone.js/Tone/instrument/PolySynth.js

153 lines
4 KiB
JavaScript
Raw Normal View History

2014-09-04 02:35:27 +00:00
define(["Tone/core/Tone", "Tone/instrument/MonoSynth", "Tone/source/Source"],
2014-08-25 17:26:26 +00:00
function(Tone){
"use strict";
2014-08-25 17:26:26 +00:00
/**
* @class Creates a polyphonic synthesizer out of
* the monophonic voice which is passed in.
*
* @constructor
* @extends {Tone}
* @param {number|Object} [polyphony=6] the number of voices to create
* @param {function=} [voice=Tone.MonoSynth] the constructor of the voices
* uses Tone.MonoSynth by default
* @param {Object} voiceOptions the options to pass to the voice
*/
Tone.PolySynth = function(){
var options = this.optionsObject(arguments, ["polyphony", "voice", "voiceOptions"], Tone.PolySynth.defaults);
/**
* the output
* @type {GainNode}
*/
this.output = this.context.createGain();
/**
* the array of voices
* @private
* @type {Array}
*/
this._voices = new Array(options.polyphony);
/**
* the queue of free voices
* @private
* @type {Array}
*/
this._freeVoices = [];
/**
* keeps track of which notes are down
* @private
* @type {Object}
*/
this._activeVoices = {};
//create the voices
for (var i = 0; i < options.polyphony; i++){
var v = new options.voice(options.voiceOptions);
this._voices[i] = v;
v.connect(this.output);
}
//make a copy of the voices
this._freeVoices = this._voices.slice(0);
};
Tone.extend(Tone.PolySynth);
/**
* the defaults
* @const
* @static
* @type {Object}
*/
Tone.PolySynth.defaults = {
"polyphony" : 4,
"voice" : Tone.MonoSynth,
"voiceOptions" : {
"portamento" : 0
}
};
/**
* trigger the attack
* @param {string|number|Object} value the value of the note to start
* @param {Tone.Time=} [time=now] the start time of the note
2014-09-04 02:35:27 +00:00
* @param {number=} velocity the velocity of the note
2014-08-25 17:26:26 +00:00
*/
2014-09-04 02:35:27 +00:00
Tone.PolySynth.prototype.triggerAttack = function(value, time, velocity){
2014-08-25 17:26:26 +00:00
var stringified = JSON.stringify(value);
if (this._activeVoices[stringified]){
2014-09-04 02:35:27 +00:00
this._activeVoices[stringified].triggerAttack(value, time, velocity);
2014-08-25 17:26:26 +00:00
} else if (this._freeVoices.length > 0){
var voice = this._freeVoices.shift();
voice.triggerAttack(value, time);
this._activeVoices[stringified] = voice;
}
2014-09-04 02:35:27 +00:00
};
/**
* trigger the attack and release after the specified duration
*
* @param {number|string} note the note as a number or a string note name
* @param {Tone.Time} duration the duration of the note
* @param {Tone.Time=} time if no time is given, defaults to now
* @param {number=} velocity the velocity of the attack (0-1)
*/
Tone.PolySynth.prototype.triggerAttackRelease = function(value, duration, time, velocity){
time = this.toSeconds(time);
this.triggerAttack(value, time, velocity);
this.triggerRelease(time + this.toSeconds(duration));
2014-08-25 17:26:26 +00:00
};
/**
* trigger the release of a note
* @param {string|number|Object} value the value of the note to release
* @param {Tone.Time=} [time=now] the release time of the note
*/
Tone.PolySynth.prototype.triggerRelease = function(value, time){
//get the voice
var stringified = JSON.stringify(value);
var voice = this._activeVoices[stringified];
if (voice){
voice.triggerRelease(time);
this._freeVoices.push(voice);
this._activeVoices[stringified] = null;
}
};
/**
* set the options on all of the voices
* @param {Object} params
*/
Tone.PolySynth.prototype.set = function(params){
for (var i = 0; i < this._voices.length; i++){
this._voices[i].set(params);
}
};
2014-09-04 02:35:27 +00:00
/**
* set volume method borrowed form {@link Tone.Source}
* @function
*/
Tone.PolySynth.prototype.setVolume = Tone.Source.prototype.setVolume;
2014-08-25 17:26:26 +00:00
/**
* clean up
*/
Tone.PolySynth.prototype.dispose = function(){
Tone.prototype.dispose.call(this);
for (var i = 0; i < this._voices.length; i++){
this._voices[i].dispose();
this._voices[i] = null;
}
this._voices = null;
this._activeVoices = null;
this._freeVoices = null;
};
return Tone.PolySynth;
});