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
29

Making Music with the Web Audio API, JSConf Colombia 2023

Steve Kinney

November 16, 2023
Tweet

Transcript

  1. Steve Kinney — JSConf Colombia 2023
    Making Music
    with the Web Audio API.

    View full-size slide

  2. Hi, I’m Steve.
    I work at Temporal.

    View full-size slide

  3. https://
    synthesizzler.vercel.app
    Also, you can scan this code at any
    time.

    View full-size slide

  4. Someone snuck a synthesizer
    into your web browser.

    View full-size slide

  5. const context = new AudioContext();

    View full-size slide

  6. const oscillator = context.createOscillator();

    View full-size slide

  7. oscillator.connect(context.destination);

    View full-size slide

  8. oscillator.connect(context.destination);
    const context = new AudioContext();
    const oscillator = context.createOscillator();

    View full-size slide

  9. oscillator.connect(context.destination);
    const context = new AudioContext();
    const oscillator = context.createOscillator();

    View full-size slide

  10. oscillator.connect(volume);
    const context = new AudioContext();
    const oscillator = context.createOscillator();
    const volume = context.createGain();
    volume.connect(context.destination);

    View full-size slide

  11. const oscillator = context.createOscillator();
    oscillator.type = 'sine';
    oscillator.frequency.value = 440;
    oscillator.connect(context.destination);
    oscillator.start();

    View full-size slide

  12. oscillator.start();
    oscillator.stop();
    oscillator.start(); This won’t work.

    View full-size slide

  13. oscillator.stop();
    oscillator.disconnect();
    oscillator = null;

    View full-size slide

  14. Let’s take a look at this in
    action.

    View full-size slide

  15. A3
    220 Hz
    A4
    440 Hz
    A5
    880 Hz

    View full-size slide

  16. A3
    220 Hz
    A4
    440 Hz
    B4 C5 C#5 D5 D#5 E5 F5 F#5 G5 G#5

    View full-size slide

  17. https://synthesizzler.vercel.app/
    notes

    View full-size slide

  18. 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);
    }

    View full-size slide

  19. 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

    View full-size slide

  20. 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

    View full-size slide

  21. 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);

    View full-size slide

  22. 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);

    View full-size slide

  23. 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 };
    };

    View full-size slide

  24. Emits a keyDown event

    View full-size slide

  25. https://synthesizzler.vercel.app/
    keys

    View full-size slide

  26. ⏰ Keeping time.

    View full-size slide

  27. get secondsPerBeat() {
    return 60 / this.beatsPerMinute;
    }

    View full-size slide

  28. 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);
    }

    View full-size slide

  29. 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;
    };

    View full-size slide

  30. https://synthesizzler.vercel.app/
    metronome

    View full-size slide

  31. https://synthesizzler.vercel.app/
    step-sequencer

    View full-size slide

  32. Someone snuck a synthesizer
    into your web browser.

    View full-size slide

  33. Someone snuck a web
    browser into your synthesizer.

    View full-size slide

  34. https://synthesizzler.vercel.app/
    theremin

    View full-size slide

  35. Music is pretty
    awesome.

    View full-size slide

  36. The web is pretty
    awesome.

    View full-size slide

  37. Music and the web are even
    more awesome when their
    together.

    View full-size slide

  38. Thank you!
    @stevekinney
    https://temporal.io

    View full-size slide