Skip to content

Instantly share code, notes, and snippets.

@jinjor
Created February 3, 2019 16:11
Show Gist options
  • Save jinjor/6f0fde37ae1d0971a22b88f38601cf77 to your computer and use it in GitHub Desktop.
Save jinjor/6f0fde37ae1d0971a22b88f38601cf77 to your computer and use it in GitHub Desktop.
const BASE_HELTZ = 440;
function generateId() {
return Math.random()
.toString(36)
.substr(2, 9);
}
function noteToHz(note: number) {
return BASE_HELTZ * 2 ** ((note - 69) / 12);
}
interface Instrument {
id: string;
noteOn(note: number, duration?: number): void;
noteOff(note: number): void;
}
class SimpleInstrument implements Instrument {
id: string;
private gainNode: GainNode;
private oscillators = new Map<number, OscillatorNode>();
constructor(private audioContext: AudioContext) {
this.id = generateId();
this.gainNode = audioContext.createGain();
this.gainNode.gain.value = 0.01;
}
createOscillator(note: number): OscillatorNode {
const oscillator = this.audioContext.createOscillator();
oscillator.type = "square";
oscillator.frequency.value = noteToHz(note);
oscillator.connect(this.gainNode);
this.gainNode.connect(this.audioContext.destination);
return oscillator;
}
cleanupOscillator(note: number, oscillator: OscillatorNode): void {
oscillator.disconnect();
this.oscillators.delete(note);
}
noteOn(note: number, durationInSeconds?: number) {
this.noteOff(note);
const oscillator = this.createOscillator(note);
oscillator.addEventListener("ended", () => {
this.cleanupOscillator(note, oscillator);
});
try {
oscillator.start();
this.oscillators.set(note, oscillator);
if (durationInSeconds) {
oscillator.stop(this.audioContext.currentTime + durationInSeconds);
}
} catch (e) {
oscillator.stop();
}
}
noteOff(note: number) {
const oscillator = this.oscillators.get(note);
if (oscillator) {
oscillator.stop();
}
}
}
const audioCtx = new AudioContext();
const simple = new SimpleInstrument(audioCtx);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment