Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making Music with the Web Audio API, JSConf Colombia 2023

Steve Kinney
November 16, 2023
31

Making Music with the Web Audio API, JSConf Colombia 2023

Steve Kinney

November 16, 2023
Tweet

Transcript

  1. oscillator.connect(volume); const context = new AudioContext(); const oscillator = context.createOscillator();

    const volume = context.createGain(); volume.connect(context.destination);
  2. A3 220 Hz A4 440 Hz B4 C5 C#5 D5

    D#5 E5 F5 F#5 G5 G#5
  3. const A4 = 440; const A4_NOTE_NUMBER = 69; const TWELFTH_ROOT_OF_TWO

    = Math.pow(2, 1 / 12); export function getFrequency() { const noteNumber = noteToNumber(note); return A4 * Math.pow(TWELFTH_ROOT_OF_TWO, noteNumber - A4_NOTE_NUMBER); }
  4. Note Frequency (hz) A 440.00 A̅ 476.67 B 513.33 C

    550.00 C̅ 586.67 D 623.33 D̅ 660.00 E 696.67 F 733.33 F̅ 770.00 G 806.67 G̅ 843.33 A 880.00
  5. Note Frequency (hz) Frequency (hz) A 440.00 A̅ 476.67 B

    513.33 C 550.00 550.00 C̅ 586.67 595.83 D 623.33 641.67 D̅ 660.00 687.50 E 696.67 733.33 F 733.33 779.17 F̅ 770.00 825.00 G 806.67 870.83 G̅ 843.33 916.67 A 880.00 962.50 A̅ 1008.33 B 1054.17 C 1100.00
  6. const oscillator = context.createOscillator(); const gain = context.createGain(); oscillator.connect(gain); gain.connect(context.destination);

    oscillator.type = waveType; oscillator.frequency.value = frequency; gain.gain.setValueAtTime(0, startTime); gain.gain.linearRampToValueAtTime(1, startTime + duration / 100); gain.gain.exponentialRampToValueAtTime(0.0001, startTime + duration); oscillator.start(startTime); oscillator.stop(startTime + duration + 0.05);
  7. const startTime = context.currentTime; const duration = 1; gain.gain.setValueAtTime(0, startTime);

    gain.gain.linearRampToValueAtTime(1, startTime + duration / 100); gain.gain.exponentialRampToValueAtTime(0.0001, startTime + duration); oscillator.start(startTime); oscillator.stop(startTime + duration + 0.05);
  8. const startOscillator = ( context, note, ): OscillatorAndGain = {

    const oscillator = context.createOscillator(); const gain = context.createGain(); oscillator.frequency.value = getFrequency(note); gain.gain.value = 0.01; oscillator.connect(gain); gain.connect(context.destination); gain.gain.linearRampToValueAtTime(1, context.currentTime + 0.1); oscillator.start(); return { oscillator, gain }; };
  9. public start() { if (this.on) return; this.on = true; this.currentBeat

    = 0; this.tick(); } public stop() { this.on = false; this.nextScheduledBeat = null; if (this.interval) clearTimeout(this.interval); }
  10. public tick = () = { if (!this.on) return; if

    (!this.nextScheduledBeat) { this.nextScheduledBeat = this.context.currentTime; } this.incrementBeat(); this.onTick(this.currentBeat, this.nextScheduledBeat); this.interval = setTimeout(this.tick, this.secondsPerBeat * 1000); this.nextScheduledBeat += this.secondsPerBeat; };
  11. +