UNPKG

sw-synth

Version:

Lightweight sound synthesizer designed for real-time user interaction using the Web Audio API

101 lines 4.07 kB
import { AperiodicOscillator, UnisonOscillator, } from 'aperiodic-oscillator'; import { VoiceBase } from './base.js'; export { AperiodicWave } from 'aperiodic-oscillator'; /** Returns default parameters for {@link OscillatorVoice}. */ export function defaultParams() { return { audioDelay: 0.001, type: 'triangle', attackTime: 0.01, decayTime: 0.3, sustainLevel: 0.8, releaseTime: 0.01, }; } /** Returns default parameters for {@link UnisonVoice}. */ export function defaultUnisonParams() { const result = defaultParams(); result.type = 'sawtooth'; result.stackSize = 3; result.spread = 1.5; return result; } export class OscillatorVoiceBase extends VoiceBase { constructor(context, destination, log, oscillatorClass) { super(context, destination, log); this.oscillator = new oscillatorClass(this.context); this.oscillator.connect(this.envelope); this.pitchBend.connect(this.oscillator.detune); const now = this.context.currentTime; this.oscillator.start(now); this.oscillator.addEventListener('ended', () => { this.envelope.disconnect(); this.oscillator.disconnect(); }); } noteOn(frequency, velocity, noteId, params, pitchBendRange) { const now = this.context.currentTime + params.audioDelay; this.oscillator.frequency.setValueAtTime(frequency, now); return super.noteOn(frequency, velocity, noteId, params, pitchBendRange); } dispose() { this.oscillator.stop(); if (this.oscillator instanceof UnisonOscillator || this.oscillator instanceof AperiodicOscillator) { this.oscillator.dispose(); } } } export class OscillatorVoice extends OscillatorVoiceBase { constructor(audioContext, destination, log) { super(audioContext, destination, log, OscillatorNode); } noteOn(frequency, velocity, noteId, params, pitchBendRange) { if (params.periodicWave) { if (params.type !== 'custom') { throw new Error("Oscillator type must be set to 'custom' when periodic wave is used."); } this.oscillator.setPeriodicWave(params.periodicWave); } else { if (params.type === 'custom') { throw new Error("Periodic wave must be given when oscillator type is set to 'custom'"); } this.oscillator.type = params.type; } return super.noteOn(frequency, velocity, noteId, params, pitchBendRange); } } export class UnisonVoice extends OscillatorVoiceBase { constructor(audioContext, destination, log) { super(audioContext, destination, log, UnisonOscillator); } noteOn(frequency, velocity, noteId, params, pitchBendRange) { this.oscillator.numberOfVoices = params.stackSize; const now = this.context.currentTime + params.audioDelay; this.oscillator.spread.setValueAtTime(params.spread, now); if (params.periodicWave) { if (params.type !== 'custom') { throw new Error("Oscillator type must be set to 'custom' when periodic wave is used."); } this.oscillator.setPeriodicWave(params.periodicWave); } else { if (params.type === 'custom') { throw new Error("Periodic wave must be given when oscillator type is set to 'custom'"); } this.oscillator.type = params.type; } return super.noteOn(frequency, velocity, noteId, params, pitchBendRange); } } export class AperiodicVoice extends OscillatorVoiceBase { constructor(audioContext, destination, log) { super(audioContext, destination, log, AperiodicOscillator); } noteOn(frequency, velocity, noteId, params, pitchBendRange) { this.oscillator.setAperiodicWave(params.aperiodicWave); return super.noteOn(frequency, velocity, noteId, params, pitchBendRange); } } //# sourceMappingURL=oscillator.js.map