# Sound geometry

The closures in a machine that makes a sound by moving something: a spiral groove, a pivoted tonearm's tracking error, an exponential horn, a spring governor, a tuned comb, and a pinned barrel.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/sound-geometry.json
```

Registry item: `sound-geometry` · [`https://robocn.dev/r/sound-geometry.json`](https://robocn.dev/r/sound-geometry.json)

## Notes

- Pure functions over plain objects. No React, no dependencies, and no acoustics: nothing here computes a frequency response, a horn's cutoff, a radiation impedance, a spring's torque curve or a decay, and nothing plays a sound.
- The tonearm is the piece that earns the file. Its tracking error is a number a drawing would otherwise quietly get wrong, and it is what lets `turntable-deck` and `gramophone-horn` share one solver while telling the truth about how differently they track.
- A step sequencer is a pinned barrel unrolled flat, which is why `combLift` drives a music box's tine and a droid's beater alike.

## Usage

```tsx
import { groovePose, tonearmPose, governorPose, pinBarrel, combLift } from "@/lib/robocn/sound"

const side = groovePose(0.4, { outer: 146, inner: 60, pitch: 0.12 })
const arm = tonearmPose(side.radius, { mounting: 220.3, effective: 239.3, offset: 24.2 })
arm.trackingError                       // degrees, and it changes sign between the nulls

const governor = governorPose(0.15)     // { speed: 0.5, spread: 0.25, governing: false }
const barrel = pinBarrel(["x...x...", "..x...x."])
combLift(barrel, 0, 4)                  // 1 at the pin, 0 the instant after
```

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `groovePose` | `(progress, geometry) => GroovePose` | — | Where the stylus is standing and how many revolutions that is. The spiral gears the arm to the platter: one revolution moves the stylus in by exactly one groove pitch. |
| `grooveTurns` | `(geometry) => number` | — | Revolutions in a whole side: the playable band divided by the groove pitch. |
| `grooveProgress` | `(radius, geometry) => number` | — | The inverse, for a caller that knows where the stylus is standing. |
| `grooveSpiralPath` | `(geometry, turns?, stepsPerTurn?) => string` | — | The groove as artwork: one Archimedean spiral drawn with the number of visible turns you ask for. |
| `tonearmPose` | `(radius, geometry) => TonearmPose` | — | A triangle with two fixed sides, so a groove radius fixes the arm angle. Returns the stylus, the arm angle, the overhang and the tracking error — the angle between the cartridge and the groove's tangent. |
| `tonearmNulls` | `(geometry, inner, outer, samples?) => number[]` | — | The radii where the cartridge sits exactly square to the groove. A well set up arm has two inside the record; an acoustic one may have none. |
| `hornProfile` | `(geometry, steps?) => HornSection[]` | — | An exponential or conical horn sampled into sections, throat first, ready to be built into a solid. |
| `hornRadius` | `(along, geometry) => number` | — | The radius at one station along the axis. Exponential by default: the area doubles over a constant distance. |
| `flareRate` | `(geometry) => number` | — | The flare constant, so the area doubles every ln 2 divided by it. Zero for a cone. |
| `governorPose` | `(wind, options?) => GovernorPose` | — | What a wind-up drive does: the speed holds while the spring has torque and sags proportionally below the knee, and the flyweights stand out with the square of the speed until they reach their stop. |
| `combTines` | `(count, options?) => CombTine[]` | — | A comb tuned by length, up a scale. A cantilever's frequency goes as one over the length squared, so an octave up is one over root two the length. |
| `pinBarrel` | `(pattern, steps?) => Barrel` | — | Pins laid out from a pattern, one row per tine: any non-blank character is a pin at that step. Malformed rows produce a barrel that turns and plucks nothing. |
| `combLift` | `(barrel, tine, position, options?) => number` | — | How far a pin has bent its tine: rising as the pin comes round, exactly 1 at the step, and nothing after. That discontinuity is the pluck. |
| `combRelease` | `(barrel, tine, position, options?) => number` | — | The other half: 1 at the instant of release, falling away over the tail. |
| `barrelStep` | `(barrel, position) => number` | — | The step standing under the comb, wrapped into the barrel in both directions. |

## Source

- `src/lib/robocn/sound.ts`
