UNPKG

dot-audio

Version:

A simple web audio library for making synthesizers

242 lines (210 loc) 7.38 kB
import DotAudioNode from 'nodes/core/DotAudioNode' import GainEnvelope from 'nodes/components/GainEnvelope' import Oscillator from 'nodes/sources/Oscillator' import { getNoteFrequency } from 'src/util/util' const defaultProps = { waveform: 'sine', frequency: 440, detune: 0, gainAttack: 0, gainDecay: 0, gainSustain: 1, gainRelease: 0, gainAmount: 0.75, } /** * General-purpose synth node consisting of an Oscillator connected to a GainEnvelope. * * @example * const synth = new Dot.Synth(AC, { gainDecay: 0.25, gainSustain: 0 }) * * synth.connect(AC.destination) * synth.noteOn('F#4') * * @extends DotAudioNode * @param {AudioContext} AC - Audio context * @param {Object} opts - Initialization options * @param {String} opts.waveform - Initial waveform (default: 'sine') * @param {Boolean} opts.frequency - Frequency of the oscillator (default: 440) * @param {Number} opts.detune - Detune value of the oscillator (default: 0) * @param {Number} opts.gainAttack - Attack time of the gain envelope (default: 0) * @param {Number} opts.gainDecay - Decay time of the gain envelope (default: 0) * @param {Number} opts.gainSustain - Sustain value of the gain envelope (default: 1) * @param {Number} opts.gainRelease - Release time of the gain envelope (default: 0) * @param {Number} opts.gainAmount - Modifier value of the gain envelope (default: 0.75) * @params * frequency - Frequency of the oscillator * detune - Detune value of the oscillator * gain - Gain value of the gain node * @returns {Synth} Synth Node */ class Synth extends DotAudioNode { constructor(AC, opts = {}) { super(AC) this.name = 'Synth' this.osc = new Oscillator(this.AC, { start: true }) this.gainEnv = new GainEnvelope(this.AC) this.currentNote = null this.params = { frequency: this.osc.getParam('frequency'), detune: this.osc.getParam('detune'), gain: this.gainEnv.getParam('gain'), } this.inputs = null this.outputs = [this.gainEnv] // Initialize const initProps = { ...defaultProps, ...opts } this.setWaveform(initProps.waveform) this.setFrequency(initProps.frequency) this.setDetune(initProps.detune) this.setGainAttack(initProps.gainAttack) this.setGainDecay(initProps.gainDecay) this.setGainSustain(initProps.gainSustain) this.setGainRelease(initProps.gainRelease) this.setGainAmount(initProps.gainAmount) // Connections this.osc.connect(this.gainEnv) return this } // --- Public Methods --- // - Getters - /** * Get the note that is currently being played. * @returns {String} Current note */ getCurrentNote = () => this.currentNote // Oscillator /** * Get the waveform of the oscillator. * @returns {String} Oscillator type */ getWaveform = () => this.osc.getType() /** * Get the frequency of the oscillator. * @returns {Number} Oscillator frequency */ getFrequency = () => this.params.frequency.value /** * Get the detune value of the oscillator. * @returns {Number} Oscillator detune */ getDetune = () => this.params.detune.value // Gain Envelope /** * Get the attack time of the gain envelope. * @returns {Number} Gain attack time */ getGainAttack = () => this.gainEnv.getAttack() /** * Get the decay time of the gain envelope. * @returns {Number} Gain decay time */ getGainDecay = () => this.gainEnv.getDecay() /** * Get the sustain value of the gain envelope. * @returns {Number} Gain sustain value */ getGainSustain = () => this.gainEnv.getSustain() /** * Get the release time of the gain envelope. * @returns {Number} Gain release time */ getGainRelease = () => this.gainEnv.getRelease() /** * Get the modifier value of the gain envelope. * @returns {Number} Gain amount */ getGainAmount = () => this.gainEnv.getModifier() // - Setters - // Oscillator /** * Set the waveform of the oscillator. * @param {String} val - Waveform */ setWaveform = (val) => this.osc.setType(val) /** * Set the frequency of the oscillator. * Calls the setFrequency method of the oscillator. * @param {Number} val - Frequency * @param {Number} [time] - update time in seconds (optional) */ setFrequency = (val, time) => this.osc.setFrequency(val, time) /** * Set the detune of the oscillator. * Calls the setDetune method on the oscillator. * @param {Number} val - Detune value * @param {Number} [time] - update time in seconds (optional) */ setDetune = (val, time) => this.osc.setDetune(val, time) // Gain Envelope /** * Set the attack time of the gain envelope. * Calls the setAttack method on the gain envelope. * @param {Number} val - Attack time */ setGainAttack = (val) => this.gainEnv.setAttack(val) /** * Set the decay time of the gain envelope. * Calls the setDecay method on the gain envelope. * @param {Number} val - Decay time */ setGainDecay = (val) => this.gainEnv.setDecay(val) /** * Set the sustain value of the gain envelope. * Calls the setSustain method on the gain envelope. * @param {Number} val - Sustain value */ setGainSustain = (val) => this.gainEnv.setSustain(val) /** * Set the release time of the gain envelope. * Calls the setRelease method on the gain envelope. * @param {Number} val - Release time */ setGainRelease = (val) => this.gainEnv.setRelease(val) /** * Set the gain modifier of the gain envelope. * Calls the setModifier method on the gain envelope. * @param {Number} val - Modifier amount */ setGainAmount = (val) => this.gainEnv.setModifier(val) // - Note Methods - /** * Plays the note given. * Sets the frequency of the oscillator and calls triggerAttack on the gain envelope. * @param {String} note - Note to be played */ noteOn = (note) => this._noteOn(note) /** * Releases the note given if it matches the current note. * If a note is not given, it will release any current note being played. * Calls triggerRelease on the gain envelope. * @param {String} [note] - Note to be released (optional) */ noteOff = (note) => this._noteOff(note) /** * Stops any note currently being played. * Calls triggerStop on the gain envelope. */ noteStop = () => this._noteStop() // --- Private Methods --- _noteOn = (note) => { if (!note) { console.error('Note must be provided to play') return } this.currentNote = note this.osc.setFrequency(getNoteFrequency(note)) this.gainEnv.triggerAttack() } _noteOff = (note) => { // Do not release if the note if different from the current note if (note && note !== this.currentNote) return this.currentNote = null this.gainEnv.triggerRelease() } _noteStop = () => { this.currentNote = null this.gainEnv.triggerStop() } } export default Synth