Project: Sound & Beats
The problem
A sine wave is not just a picture — it is a sound. Given the wave math from Graphs, generate real tones in the browser, combine two close pitches to hear beats, and shape notes with an envelope.
Tone math
A pure tone of frequency \(f\) Hz at amplitude \(A\) is:
Musical pitch is logarithmic: A4 = 440 Hz and each semitone up multiplies by \(2^{1/12}\):
where \(n\) counts semitones from A4 (so A5 is \(n = 12\), C5 is \(n = 3\)).
Play two close frequencies together and you hear beats — a slow pulsing at the difference frequency:
Piano tuners use exactly this: the beats vanish when the strings match. Try 440 Hz + 442 Hz → 2 beats per second.
Full build (Web Audio)
var actx = new (window.AudioContext || window.webkitAudioContext)();
function tone(freq, startIn, dur, vol) {
var osc = actx.createOscillator();
var gain = actx.createGain();
osc.type = 'sine';
osc.frequency.value = freq;
var t0 = actx.currentTime + startIn;
// sine-shaped attack/decay envelope — no clicks
gain.gain.setValueAtTime(0.0001, t0);
gain.gain.exponentialRampToValueAtTime(vol, t0 + 0.03);
gain.gain.setValueAtTime(vol, t0 + dur - 0.08);
gain.gain.exponentialRampToValueAtTime(0.0001, t0 + dur);
osc.connect(gain).connect(actx.destination);
osc.start(t0);
osc.stop(t0 + dur + 0.05);
}
function noteOffset(semitones) { return 440 * Math.pow(2, semitones / 12); }
// A major arpeggio: A4, C#5, E5, A5
[0, 4, 7, 12].forEach(function (n, i) {
tone(noteOffset(n), i * 0.28, 0.3, 0.25);
});
print('arpeggio playing: A4 C#5 E5 A5');
// Beats demo: uncomment to hear 2 beats/sec
// tone(440, 0, 2.0, 0.2);
// tone(442, 0, 2.0, 0.2);
Browsers require a user gesture before audio starts — run this from a click (the playground’s Run button counts).
Try it
- Play a C major scale (offsets from A4: C5=3, D5=5, E5=7, F5=8, G5=10, A5=12, B5=14, C6=15). Verify each frequency against a tuner app.
- Uncomment the beats demo. Then change 442 → 443.5 and predict the new beat rate before listening.
- Visualize it: draw \(\sin(2\pi\cdot440t) + \sin(2\pi\cdot442t)\) on canvas for \(t\) in \([0, 1]\) second and find the 2-beat envelope in the picture.
Next: Project: Easing & Motion — sine curves that make interfaces feel alive.