spessasynth_lib
Version:
MIDI and SoundFont2/DLS library for the browsers with no compromises
167 lines (151 loc) • 5.19 kB
JavaScript
/**
* fancy_chorus.js
* purpose: creates a simple chorus effect node
*/
/**
* @typedef {{
* oscillator: OscillatorNode,
* oscillatorGain: GainNode,
* delay: DelayNode
* }} ChorusNode
*/
/**
* @typedef {Object} ChorusConfig
* @property {number?} nodesAmount - the amount of delay nodes (for each channel) and the corresponding oscillators
* @property {number?} defaultDelay - the initial delay, in seconds
* @property {number?} delayVariation - the difference between delays in the delay nodes
* @property {number?} stereoDifference - the difference of delays between two channels (added to the right channel)
* @property {number?} oscillatorFrequency - the initial delay time oscillator frequency, in Hz.
* @property {number?} oscillatorFrequencyVariation - the difference between frequencies of oscillators, in Hz
* @property {number?} oscillatorGain - how much will oscillator alter the delay in delay nodes, in seconds
*/
const NODES_AMOUNT = 4;
const DEFAULT_DELAY = 0.03;
const DELAY_VARIATION = 0.013;
const STEREO_DIFF = 0.03;
const OSC_FREQ = 0.2;
const OSC_FREQ_VARIATION = 0.05;
const OSC_GAIN = 0.003;
export const DEFAULT_CHORUS_CONFIG = {
nodesAmount: NODES_AMOUNT,
defaultDelay: DEFAULT_DELAY,
delayVariation: DELAY_VARIATION,
stereoDifference: STEREO_DIFF,
oscillatorFrequency: OSC_FREQ,
oscillatorFrequencyVariation: OSC_FREQ_VARIATION,
oscillatorGain: OSC_GAIN
};
export class FancyChorus
{
/**
* Creates a fancy chorus effect
* @param output {AudioNode} - the target output node
* @param config {ChorusConfig} - the configuration for the chorus
*/
constructor(output, config = DEFAULT_CHORUS_CONFIG)
{
const context = output.context;
this.input = context.createChannelSplitter(2);
const merger = context.createChannelMerger(2);
/**
* @type {ChorusNode[]}
*/
const chorusNodesLeft = [];
/**
* @type {ChorusNode[]}
*/
const chorusNodesRight = [];
let freq = config.oscillatorFrequency;
let delay = config.defaultDelay;
for (let i = 0; i < config.nodesAmount; i++)
{
// left node
this._createChorusNode(
freq,
delay,
chorusNodesLeft,
0,
merger,
0,
context,
config
);
// right node
this._createChorusNode(
freq,
delay + config.stereoDifference,
chorusNodesRight,
1,
merger,
1,
context,
config
);
freq += config.oscillatorFrequencyVariation;
delay += config.delayVariation;
}
merger.connect(output);
this.merger = merger;
this.chorusLeft = chorusNodesLeft;
this.chorusRight = chorusNodesRight;
}
/**
* Disconnects and deletes the chorus effect
*/
delete()
{
this.input.disconnect();
delete this.input;
this.merger.disconnect();
delete this.merger;
for (const chorusLeftElement of this.chorusLeft)
{
chorusLeftElement.delay.disconnect();
chorusLeftElement.oscillator.disconnect();
chorusLeftElement.oscillatorGain.disconnect();
delete chorusLeftElement.delay;
delete chorusLeftElement.oscillatorGain;
delete chorusLeftElement.oscillatorGain;
}
for (const chorusRightElement of this.chorusRight)
{
chorusRightElement.delay.disconnect();
chorusRightElement.oscillator.disconnect();
chorusRightElement.oscillatorGain.disconnect();
delete chorusRightElement.delay;
delete chorusRightElement.oscillatorGain;
delete chorusRightElement.oscillatorGain;
}
}
/**
* @param freq {number}
* @param delay {number}
* @param list {ChorusNode[]}
* @param input {number}
* @param output {AudioNode}
* @param outputNum {number}
* @param context {BaseAudioContext}
* @param config {ChorusConfig}
* @private
*/
_createChorusNode(freq, delay, list, input, output, outputNum, context, config)
{
const oscillator = context.createOscillator();
oscillator.type = "sine";
oscillator.frequency.value = freq;
const gainNode = context.createGain();
gainNode.gain.value = config.oscillatorGain;
const delayNode = context.createDelay();
delayNode.delayTime.value = delay;
oscillator.connect(gainNode);
gainNode.connect(delayNode.delayTime);
oscillator.start(context.currentTime /*+ delay*/);
this.input.connect(delayNode, input);
delayNode.connect(output, 0, outputNum);
list.push({
oscillator: oscillator,
oscillatorGain: gainNode,
delay: delayNode
});
}
}