/**
* gang_of_oscillators
*
* Just a bunch of oscillators
*
* [See more synth examples](examples/synth.html)
*
* @plugin
* @category Synth
* @function
* @memberof cracked
* @name cracked#gang_of_oscillators
* @public
* @param {Object} [params] map of optional values
*/
cracked.gang_of_oscillators = function(params) {
/*
//expected format
{
size:16,
lp_freq:20000,
type:sine
}
//or just type as a string
*/
var type = __.isStr(params) ? params : __.isObj(params) && params.type ? params.type : "sine";
var lp_freq = __.isObj(params) && params.lp_freq ? params.lp_freq : 20000;
var size = __.isObj(params) && params.size ? params.size : 16;
__().begin("gang_of_oscillators",params);
__().gain();
for(var i=0;i<size;i++) {
__().begin("v"+(i+1)).osc({type:type}).lowpass(lp_freq).gain(0).end("v"+(i+1)).connect("gain");
}
__.end("gang_of_oscillators");
return cracked;
};
/**
* monosynth
*
* Simple monophonic synth
*
* [See more synth examples](examples/synth.html)
*
* @plugin
* @category Synth
* @function
* @memberof cracked
* @name cracked#monosynth
* @public
* @param {Object} [params] map of optional values
*/
cracked.monosynth = function (params) {
var methods = {
init: function (options) {
var opts = options || {};
/*
expected format
{
lfo_type:"sawtooth",
lfo_intensity:0,
lfo_speed:5
osc_type:"sine",
osc_frequency:440,
osc_detune:0
lp_q:0,
lp_frequency:440
adsr_envelope:0.5
gain_volume:1
}
*/
//set up a basic synth: lfo, sine, lowpass, envelope
//options:
//lfo- type, intensity, speed
//osc- type, frequency, detune
//lowpass- q, frequency
//adsr- envelope
//gain- volume
var lfo_type = opts.lfo_type || "sawtooth",
lfo_intensity = opts.lfo_intensity || 0,
lfo_speed = opts.lfo_speed || 5,
osc_type = opts.osc_type || "sine",
osc_frequency = opts.osc_frequency || 440,
osc_detune = opts.osc_detune || 0,
lp_q = opts.lp_q || 0,
lp_frequency = opts.lp_frequency || 440,
adsr_envelope = opts.adsr_envelope || 0.5,
gain_volume = opts.gain_volume || 1;
__().begin("monosynth", params).
lfo({
gain:lfo_intensity,
frequency:lfo_speed,
type:lfo_type
}).
osc({
detune:osc_detune,
frequency:osc_frequency,
type:osc_type
}).
lowpass({
q: lp_q,
frequency:lp_frequency
}).
adsr({
envelope:adsr_envelope
}).
gain({
gain:gain_volume
}).
end("monosynth");
},
noteOn: function (params) {
//process incoming arguments for this note
var args = params || {};
var freq = __.isNum(params) ? __.pitch2freq(params) : __.pitch2freq(args.pitch);
var vel = __.isNum(args.velocity) ? args.velocity/127 : 0.5;
var env = args.envelope || [0.01,0.1,0.5];
//loop thru selected nodes
cracked.each("monosynth", function (el, index, arr) {
//select any internal oscillator nodes the monosynth contains (using "el.search(osc)")
//and then call frequency() passing in the pitch argument we got w noteOn.
cracked.exec("frequency", [freq], el.search("osc"));
//apply the velocity to the output gain
cracked.exec("volume", [vel], el.search("gain"));
//grab internal adsr and call trigger, pass the envelope parameter we received
cracked.exec("adsr", ["trigger", env], el.search("adsr"));
});
},
noteOff: function (params) {
cracked.each("monosynth", function (el, index, arr) {
params = __.ifUndef(params,0.1);
var p = __.isNum(params) ? params : __.ifUndef(params.envelope,0.1);
//call the adsr release
cracked.exec("adsr", ["release",p], el.search("adsr"));
});
}
};
if (methods[params]) {
methods[params].apply(this, Array.prototype.slice.call(arguments, 1));
} else {
methods.init(params);
}
return cracked;
};
/**
* polysynth
*
* Simple polyphonic synth
*
* [See more synth examples](examples/synth.html)
*
* @plugin
* @category Synth
* @function
* @memberof cracked
* @name cracked#polysynth
* @public
* @param {Object} [params] map of optional values
*/
cracked.polysynth = function (params) {
var methods = {
init: function (options) {
var opts = options || {};
/*
expected format
{
lfo_type:"sawtooth",
lfo_intensity:0,
lfo_speed:5
osc_type:"sine",
osc_frequency:440,
osc_detune:0
lp_q:0,
lp_frequency:440
adsr_envelope:0.5
gain_volume:1
}
*/
//set up a basic synth: lfo, sine, lowpass, envelope
//options:
//lfo- type, intensity, speed
//osc- type, frequency, detune
//lowpass- q, frequency
//adsr- envelope
//gain- volume
params = params || {};
//defaults
params.lfo_type = opts.lfo_type || "sawtooth";
params.lfo_intensity = opts.lfo_intensity || 0;
params.lfo_speed = opts.lfo_speed || 5;
params.osc_type = opts.osc_type || "sine";
params.osc_frequency = opts.osc_frequency || 440;
params.osc_detune = opts.osc_detune || 0;
params.lp_q = opts.lp_q || 0;
params.lp_frequency = opts.lp_frequency || 440;
params.adsr_envelope = opts.adsr_envelope || 0.5;
params.gain_volume = opts.gain_volume || 1;
//we'll add a map so we can track active voices
params.active_voices = {};
//just a stub we'll attach voices to in the noteon method
__().begin("polysynth", params).
gain({
gain:params.gain_volume
}).
end("polysynth");
},
noteOn: function (params) {
//process incoming arguments for this note
var args = params || {};
var note_number = __.isNum(params) ? params : args.pitch;
var freq = __.pitch2freq(note_number);
var vel = __.isNum(args.velocity) ? args.velocity/127 : 0.5;
var env = args.envelope || [0.01,0.1,0.5];
var instance_id = note_number+"_"+Date.now();
//loop thru selected nodes, filtering on the type polysynth
cracked.each("polysynth", function (el, index, arr) {
//get the settings that were stored when the object was created
var voices = el.getParams().settings.active_voices;
var settings = el.getParams().settings;
//if not currently active
if(!voices[note_number]) {
//ignore the grid while we're creating the voice
__.loop("toggle_grid");
//create a new voice
__().lfo({
type:settings.lfo_type,
gain:settings.lfo_intensity,
frequency:settings.lfo_speed,
id:instance_id+"_lfo",
class:instance_id+"_class",
modulates:"frequency"
}).osc({
id:instance_id+"_osc",
class:instance_id+"_class",
frequency:freq,
type:settings.osc_type,
detune: settings.osc_detune
}).adsr({
envelope:env,
id:instance_id+"_adsr",
class:instance_id+"_class"
}).lowpass({
id:instance_id+"_lp",
class:instance_id+"_class",
frequency:settings.lp_frequency,
q:settings.lp_q
}).gain({
id:instance_id+"_gain",
class:instance_id+"_class",
gain:vel
}).connect(el);
//flip it back before we start it up
__.loop("toggle_grid");
//start it up
cracked.exec("start", [], __.find("."+instance_id+"_class"));
//trigger the envelope
cracked.exec("adsr", ["trigger", env], __.find("#"+instance_id+"_adsr"));
voices[note_number]=instance_id;
}
});
},
noteOff: function (params) {
cracked.each("polysynth", function (el, index, arr) {
//the only params should be the pitch and the (optional) envelope release time
var note_number = __.isNum(params) ? params : params.pitch;
var release = __.ifUndef(params.envelope,0.1);
//get the active voices map
var voices = el.getParams().settings.active_voices;
//and the instance id
var instance_id = note_number ? voices[note_number] : false;
//if its active
if(instance_id) {
//call the adsr release
cracked.exec("adsr", ["release", release], __.find("#"+instance_id+"_adsr"));
//schedule the removal of the voice after it's done playing
cracked.exec("remove", [((release*1000)+250)], __.find("."+instance_id+"_class"));
//clear the active status so it can be run again
delete voices[note_number];
}
});
},
update:function (params) {
//update synth params from control
cracked.each("polysynth", function (el, index, arr) {
//get the active voices map
var settings = el.getParams().settings;
var voices = el.getParams().settings.active_voices;
//iterate over the node's params and update with any new values
//any new voices will created with these values
Object.keys(params).map(function(setting,index,arr){
settings[setting]=params[setting];
});
//iterate over the voices currently playing and update their values
Object.keys(voices).map(function(pitch,index,arr){
var instance_id = voices[pitch];
Object.keys(params).map(function(param,index,arr){
switch (param) {
case "lfo_speed":
cracked.exec("frequency", [params[param]], __.find("#"+instance_id+"_lfo"));
break;
case "lfo_intensity":
cracked.exec("volume", [params[param]], __.find("#"+instance_id+"_lfo"));
break;
case "lp_frequency":
cracked.exec("frequency", [params[param]], __.find("#"+instance_id+"_lp"));
break;
case "lp_q":
cracked.exec("q", [params[param]], __.find("#"+instance_id+"_lp"));
break;
}
});
});
});
}
};
if (methods[params]) {
methods[params].apply(this, Array.prototype.slice.call(arguments, 1));
} else {
methods.init(params);
}
return cracked;
};