sw-synth
Version:
Lightweight sound synthesizer designed for real-time user interaction using the Web Audio API
101 lines • 4.07 kB
JavaScript
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