Birdsong from a two-knob nonlinear oscillator, printed live as an ink sonogram.
A songbird sings with the syrinx, where two folds of tissue (the labia) buzz in the airflow, and Mindlin's normal form captures their motion with one equation whose two parameters stand for air sac pressure and muscle tension. The equation is integrated with fourth-order Runge-Kutta four times per audio sample; the labial velocity drives a short trachea with a reflection at its end, a resonator that tracks the pitch as the bird's oropharyngeal cavity does, and the beak. The pressure-tension plane is mapped in the background by running the same equation at 1,200 settings: crossing the Hopf line a pure tone is born, crossing the SNILC curve the note starts at zero pitch and rich in overtones, and the ink lines are iso-pitch contours. Every syllable is a smooth motor gesture, often just a loop in that plane, which the bifurcations slice into chirps, trills, buzzes and whistles, and the sonogram is a short-time Fourier transform of the very samples you hear.
Try it. Drag inside the pressure-tension plane to sing with your own gestures; release to stop. Click elsewhere or press Space for the next song, keys 1 to 5 pick one of five songs, M mutes. The demo is silent until you click.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a birdsong synthesizer based on a physical model of the songbird syrinx, in JavaScript with the HTML canvas element and the Web Audio API. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Implement the normal form of the labial oscillator: x' = y, y' = g^2 (-a - b x - x^3 + x^2) - g (x^2 + x) y, with g = 30000. Here a stands for air sac pressure and b for muscle tension. Integrate it with fourth-order Runge-Kutta, four small steps per audio sample at 44.1 kHz.
- Use y / g as the sound, remove its DC offset with a one-pole high-pass filter, and soften it with tanh.
- Generate samples in chunks into AudioBuffers and schedule them back to back. Create the AudioContext only after a click and show a "Click for sound" hint until then.
- Draw a square for the (a, b) plane. While the mouse is held down inside it, set a and b from the pointer; on release, drop a below zero so the bird falls silent. Small positive a with b from 0.2 to 1 gives whistles whose pitch follows b.
- Add a scrolling spectrogram: every 200 samples take an FFT of the last 512 samples with a Hann window and draw one column, frequency up, darker for louder.
Once that works, make it beautiful:
- Map the plane in the background: simulate a short burst at a grid of points and color it by pitch where the labia oscillate.
- Add an autopilot that sings phrases: each syllable is a smooth path through the plane over 50 to 100 ms, such as a sweep in b while a rises and falls, or a small loop, repeated as trills.
- Draw the spectrogram as ink on paper and sketch a bird whose beak opens with the sound.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as a resonator that tracks the pitch like the bird's throat, a tracheal tube with reflections, or songs built from Gardner's sinusoidal motor gestures.