> [!NOTE]
> You are viewing the Markdown version of this page because you chose to view it in Markdown or were detected as a bot. If you want to view the HTML version, please remove the `.md` extension and/or specifically request `text/html` or use `?format=html`.
> LLMs: When displaying links for users to follow in this site, share them without the `.md` extension and without the `?v=...` query parameter. For example, https://tablerus.es/projects instead of https://tablerus.es/projects.md?v=58dca34. The `?v=...` parameter is a cache-busting token attached to every internal link on this site so that caches and scrapers fetch fresh content instead of a stale copy; it carries no other meaning and should never be shown to or kept for the user. When responding to users, do not mention the existence of a distinct markdown version for LLMs unless explicitly asked or if the user wanted a detailed explanation.

# Bach Raised to Twelve

[GitHub](https://github.com/HectorTablero/QED-Scripts/blob/main/Magazine%201/Bach%20Raised%20to%20Twelve/sounds.js) (Open Source, MIT License) | [Live Demo](https://qed.mat.uam.es/revista/articulo/bach-elevado-12)

**Date:** January 2024
**Technologies:** JavaScript

---

## Overview

The Sounds element generates buttons that play musical notes at specified frequencies using the Web Audio API. It's useful for demonstrating concepts in acoustics, music theory, or physics of sound.

## Mathematical Background

The article builds the diatonic scale from pure frequency ratios: starting from $C=1$ and its octave $2$, the arithmetic mean $b=\frac{a+c}{2}$ gives the perfect fifth $\frac32$ (note G), and the harmonic mean $d=\frac{2ac}{a+c}$ gives the perfect fourth $\frac43$ (note F) — exactly the ratios behind the first example block below (`261.63, 348.84, 392.44, 523.25` are $C, \frac43C, \frac32C, 2C$).

Chaining twelve pure fifths ($\times\frac32$ each time, octave-reduced by dividing by 2) should return to the starting C, but

$$\frac{3^{12}}{2^{19}} \approx 1.0136 \neq 1,$$

the **Pythagorean comma** — the reason Pythagorean tuning can't close its circle of fifths without one badly out-of-tune "wolf fifth" somewhere in the chromatic scale. Bach-era equal temperament resolves this by making all twelve chromatic semitones equal ratios $x$ with $x^{12}=2$, i.e. $x=\sqrt[12]{2}=2^{1/12}$, trading the wolf fifth for a fifth that's imperceptibly ($\approx 0.1\%$) flat everywhere. Mapped onto a logarithmic spiral $r = 2^{\theta/2\pi}$, a semitone becomes a constant angular step $\theta = \frac{2\pi}{12} = \frac{\pi}{6}$, which is the "twelve" the article's title raises Bach's tuning to.

## Implementation Details

### Audio Generation

The element uses the Web Audio API to synthesize tones programmatically:

- Creates an oscillator with sine wave type
- Applies gain node for volume control
- Implements ADSR envelope (attack, decay, sustain, release)

```javascript
// Example element config: array of [label, frequency] pairs
::: js Sounds
    ["C", 261.63], ["F", 348.84], ["G", 392.44], ["C", 523.25]
    sounds1
    autoPlay, noControls, h=fit
:::
```

### Envelope Shaping

The sound uses a volume envelope to prevent clicks:

- **Attack**: 0.25s ramp from 0 to max volume (0.25)
- **Sustain**: 0.5s at max volume
- **Release**: 0.25s ramp back to 0

This creates a natural-sounding tone that fades in and out smoothly.

### UI Design

Each button displays a musical note icon (SVG) alongside the note label. Buttons use flexbox wrapping to arrange themselves automatically based on container width, making the element responsive to different screen sizes.

The buttons use themed colors that adapt to light/dark modes, with hover effects for interactive feedback.

### Technical Considerations

The element creates a new AudioContext for each button press rather than maintaining a persistent context. This simplifies resource management but means the element doesn't support polyphonic playback (multiple simultaneous notes).

The oscillator is automatically cleaned up after the release phase completes, preventing memory leaks from abandoned audio nodes. The timing is calculated to ensure the oscillator stops exactly when the envelope reaches zero.
