Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Making Music with the Web Audio API, JSConf Col...
Search
Steve Kinney
November 16, 2023
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Making Music with the Web Audio API, JSConf Colombia 2023
Steve Kinney
November 16, 2023
More Decks by Steve Kinney
See All by Steve Kinney
Enterprise UI, v2
stevekinney
0
38
React_Performance__2022.pdf
stevekinney
0
31
React Performance v2
stevekinney
0
48
Introduction to Testing
stevekinney
0
170
Web Security, Frontend Masters
stevekinney
0
3.9k
React and TypeScript, Turing School
stevekinney
0
380
Redux Workshop, 2021-05-05
stevekinney
2
2.2k
TypeScript and React Utility Types
stevekinney
1
220
A Gentle Introduction to GraphQL Resolvers
stevekinney
1
180
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
187
22k
Navigating Team Friction
lara
192
16k
Design in an AI World
tapps
1
250
The Limits of Empathy - UXLibs8
cassininazir
1
360
The Curious Case for Waylosing
cassininazir
1
390
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
360
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
200
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
390
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
For a Future-Friendly Web
brad_frost
183
10k
30 Presentation Tips
portentint
PRO
1
330
Transcript
Steve Kinney — JSConf Colombia 2023 Making Music with the
Web Audio API.
Hi, I’m Steve. I work at Temporal.
https:// synthesizzler.vercel.app Also, you can scan this code at any
time.
Someone snuck a synthesizer into your web browser.
None
None
None
None
const context = new AudioContext();
None
const oscillator = context.createOscillator();
None
oscillator.connect(context.destination);
oscillator.connect(context.destination); const context = new AudioContext(); const oscillator = context.createOscillator();
None
None
oscillator.connect(context.destination); const context = new AudioContext(); const oscillator = context.createOscillator();
oscillator.connect(volume); const context = new AudioContext(); const oscillator = context.createOscillator();
const volume = context.createGain(); volume.connect(context.destination);
const oscillator = context.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.value = 440;
oscillator.connect(context.destination); oscillator.start();
oscillator.start(); oscillator.stop(); oscillator.start(); This won’t work.
oscillator.stop(); oscillator.disconnect(); oscillator = null;
None
Let’s take a look at this in action.
None
A3 220 Hz A4 440 Hz A5 880 Hz
A3 220 Hz A4 440 Hz B4 C5 C#5 D5
D#5 E5 F5 F#5 G5 G#5
https://synthesizzler.vercel.app/ notes
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); }
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
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
None
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);
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);
None
None
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 }; };
Emits a keyDown event
https://synthesizzler.vercel.app/ keys
⏰ Keeping time.
None
get secondsPerBeat() { return 60 / this.beatsPerMinute; }
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); }
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; };
https://synthesizzler.vercel.app/ metronome
https://synthesizzler.vercel.app/ step-sequencer
Someone snuck a synthesizer into your web browser.
Someone snuck a web browser into your synthesizer.
+
https://synthesizzler.vercel.app/ theremin
None
None
Music is pretty awesome.
The web is pretty awesome.
Music and the web are even more awesome when their
together.
Thank you! @stevekinney https://temporal.io