Project Resonant · a field guide

How a machine hears a number.

Start with air moving. End with a physics simulation that can tell “three” from “eight”. Every figure on this page is computed live, in your browser, from real recordings — nothing here is a mockup.

Ten held-out clips from AudioMNIST · ~20 min read

01 — the problemSound is a terrible input format

Say “seven” out loud. Your vocal folds chop an airflow into pulses, your throat and mouth shape those pulses into resonances, and a pressure wave leaves your face at about 340 m/s. A microphone measures that pressure 16,000 times a second and writes down a number each time. One second of speech is a list of 16,000 numbers.

Pick a digit below and look at what a model is actually handed.

choose a recording
loading…
Figure 1 — one second of speech, as recorded. Every clip on this page comes from AudioMNIST, an open corpus of spoken digits. Amplitude over time, 16,000 samples. You can see where the energy is, and roughly how many syllables there are. You cannot see which word it is: the same digit spoken by two people produces two wildly different squiggles, and shifting the recording by 5 milliseconds changes every single number while changing nothing a listener would notice. Train a classifier directly on these numbers and it spends its capacity rediscovering the obvious.

The fix is a hundred years older than deep learning: stop describing the wave and start describing which frequencies are present, and when. Two recordings of “seven” differ enormously sample by sample, and look almost the same once you plot them that way. Everything in the rest of this guide — every architecture, conventional or exotic — sits behind that same transformation.

02 — the fourier transformOne slice, taken apart into pure tones

Fourier’s claim: any wave, however jagged, is a sum of plain sine waves at different frequencies, amplitudes, and phase offsets. The Fast Fourier Transform (FFT) is the algorithm that finds those ingredients — it takes a block of samples and returns, for each frequency, how much of it is in there.

The catch is in the word block. An FFT over a whole second tells you every frequency the second contained, and nothing about the order they arrived in. “Seven” and “teevn” would come out identical. So we take a small block — 512 samples here, 32 milliseconds, short enough that the mouth barely moves — and analyze that.

drag the window
Figure 2 — a 32 ms window and its spectrum. Left: the highlighted slice of the recording. Right: the FFT of that slice — energy against frequency, 0 to 8 kHz. Slide it into a vowel and the low end fills with regularly spaced peaks (the pitch of the voice and its harmonics) riding under a lumpy envelope (the formants — the resonances of the throat and mouth that decide which vowel it is). Slide it onto the “s” of “seven” or the “x” of “six” and that structure flattens into broadband hiss weighted toward the top of the range. Slide it into the silence at either end and the whole curve drops. That difference — periodic versus noisy — is doing a lot of work later.

03 — the STFTSlide the window: a picture of sound

The Short-Time Fourier Transform (STFT) is just the previous figure on repeat: take a window, FFT it, shift the window forward by a fixed hop, repeat to the end of the file, and stack the results side by side. The result is a spectrogram: time along the x-axis, frequency up the y-axis, brightness for energy.

Two parameters set the whole grid, and they trade against each other. A longer window resolves frequency more finely but smears events in time; a shorter one localizes the click of a “t” but cannot tell 300 Hz from 320 Hz. The settings used throughout this guide are the ones the digit experiments actually use: a 512-sample window (n_fft = 512, 32 ms) hopping 256 samples (16 ms), which yields 62.5 frames per second — one frame per 16 ms of speech.

Before the STFT, each window is multiplied by a smooth bell (a Hann window). Cutting a block out with hard edges would add a click the FFT dutifully reports as high-frequency energy that is not in the signal; tapering the edges removes it.

STFT · 257 frequency bins × 61 framespower, log scale
Figure 3 — the spectrogram of the selected digit. Horizontal stripes are the harmonics of the voice; the wavering bright bands are formants moving as the mouth changes shape; vertical smears are the bursts and hisses of consonants. This is the representation most audio models are built on, and this is the object that made computer-vision architectures work on sound: it is a picture, so anything that finds patterns in pictures can be pointed at it.

04 — the mel scaleRebuilding the axis around the ear

257 frequency bins, evenly spaced from 0 to 8 kHz, is not how hearing works. The gap between 100 Hz and 200 Hz is obvious to anyone; the gap between 6,000 Hz and 6,100 Hz is inaudible, though both are 100 Hz. Resolution in the ear is roughly logarithmic — fine at the bottom, coarse at the top.

The mel scale (from “melody”) is the warped frequency axis where equal distances sound like equal pitch steps. The common formula is mel = 2595 · log₁₀(1 + Hz / 700), near-linear below 1 kHz and increasingly compressive above it.

Press play below and watch which filters actually fire while the digit is spoken.

showing the clip average
hz → melthe ear’s ruler
the filterbank16 triangles over 257 bins
Figure 4 — warping, then pooling, lit up by the actual recording. Left: physical frequency in, perceptual frequency out — each stem marks a mel band this clip is using right now, planted at its frequency and rising to where the ear puts it. Right: the filterbank exported from the project’s front end — 16 triangular windows, evenly spaced on the mel axis, therefore narrow and crowded at low frequency and wide and sparse at high frequency; each one brightens with its own energy. Press play and you can watch a vowel light the low, tightly packed filters while the “s” in “six” and “seven” throws energy into the wide ones at the top. Each triangle sums the STFT bins underneath it into a single number, so a 257-number column becomes a 16-number column.

One more step, and it matters more than it looks. Loudness is perceived logarithmically too, so we take the log of each band’s energy. That turns the ratios that matter into differences a network can add and subtract, and it stops one loud vowel from dominating the numbers. STFT → mel filterbank → log is the standard audio front end; the result is the log-mel spectrogram.

log-mel · 16 bands × 61 frameswhat the model is fed
Figure 5 — the same second, now 976 numbers instead of 16,000. Low bands at the bottom, high at the top. Almost everything that distinguishes one spoken digit from another survives this compression — which is why nearly every speech system, classifier or synthesizer, starts here.

Sidebar: what is a “mel transcoder”?

A neural network that manufactures a mel spectrogram from something coarser. The motivating case is privacy: an always-on sensor in a hospital ward or a street can be built to record only very coarse acoustic energy — say third-octave bands every 125 ms — from which speech cannot be reconstructed or overheard. That data is far too crude for a pretrained audio classifier, which expects standard mel frames every 10 ms. A mel transcoder is trained to upsample and warp the coarse measurement into the mel grid those classifiers already speak, usually with a teacher–student objective: it is rewarded for producing a spectrogram the downstream classifier reads correctly, not for matching pixels. It is a translator between two feature resolutions — a useful reminder that in an audio stack, “mel spectrogram” is not just a stage of processing, it is an interface.

05 — the standard stackAn encoder, and three ways out

With the front end fixed, the rest of a speech system has a common shape: an encoder that turns the mel frames into a sequence of learned feature vectors, and a decoder that converts those into whatever you want out. Almost every well-known model is a choice of encoder (CNN, RNN/LSTM, Conformer, Transformer, state-space model) crossed with a choice of decoder.

FRONT END (FIXED MATH)ENCODER (LEARNED)DECODERS (LEARNED)waveform16 kHzSTFT512 / 256mel + log16–80 bands62.5 fpsencoderCNN · LSTMConformerTransformer · SSMclassificationpool over time → linear → softmax→ “this clip is a 7”text (ASR)CTC or autoregressive decoder→ “seven”audio (TTS / voice conv.)mel head → vocoderHiFi-GAN · Vocos · iSTFT head→ a new waveformthe same features feed all three— only the head and the loss change
Figure 6 — the conventional pipeline. The front end is fixed arithmetic with no learned parameters. Everything to its right is trained, and what you train it on is set entirely by the decoder you attach.

What the training data has to be

GoalTraining pairsLoss
Classificationclip → one label ("7")cross-entropy
Speech → textclip → transcript, no per-frame alignment neededCTC, or teacher-forced cross-entropy
Text → speechtranscript → clip, same corpus read the other waymel regression + vocoder losses
Speech → speechsource clip → target clip (denoised, or another voice)reconstruction + multi-resolution STFT

Getting back out to audio: the phase problem

Classification and transcription end at a small output. Generating audio does not, and it runs into a wall that is worth understanding, because it explains why half the field exists.

The STFT produces complex numbers: a magnitude (how much of this frequency) and a phase (where in its cycle that frequency is at this instant). A spectrogram displays magnitude only; the mel filterbank then throws away even the fine frequency detail. The inverse STFT (iSTFT) — inverse FFT per frame, then overlap-add the frames back together — reconstructs the waveform perfectly, but only if you give it both parts. Hand it magnitudes with no phase and the overlapping frames fight each other instead of adding up, and you get a smeared, metallic buzz.

So a generative audio model must supply the missing phase. Three eras of answers:

  • Griffin–Lim (algorithmic). Guess a phase, iSTFT, re-STFT, keep the target magnitudes and the newly implied phase, repeat. Converges to something playable and famously robotic. Where you have heard it: the original Tacotron (2017) shipped with Griffin–Lim, which is exactly why first-generation neural TTS demos had that ringing, underwater timbre — and why librosa’s griffinlim is still the two-line baseline everyone tries first.
  • Neural vocoders (the modern default). A network trained on thousands of hours of real speech maps mel frames straight to samples. It never “solves” for phase; it has learned what real glottal pulses, real fricative noise, and real micro-jitter look like. Where you have heard them: WaveNet (2016) predicted one sample at a time — stunning, and far too slow, so Tacotron 2 paired it with a mel decoder; HiFi-GAN (2020) made GAN vocoding fast and clean enough to become the default, and it is the vocoder inside Kokoro and StyleTTS 2; BigVGAN scaled it to universal, any-voice audio; DiffWave and WaveGrad sculpt noise into a waveform by diffusion; and Vocos predicts STFT coefficients — magnitude and phase — then lets a single iSTFT do the synthesis, which is fast enough to be the interesting compromise.
  • Multi-resolution spectral losses. Whatever the generator, training compares the output to the target through several STFTs at once — short windows to police clicks and transients, long windows to police pitch and vowels. Where it comes from: Parallel WaveGAN (2019) introduced the multi-resolution STFT loss that nearly every vocoder since has adopted, including HiFi-GAN’s mel loss and SoundStream/EnCodec’s spectral reconstruction terms; the differentiable-DSP line (DDSP) leans on the same idea.

Text-to-speech is not simply speech-to-text backwards

Structurally it mirrors: text encoder → acoustic decoder → vocoder → wave. In difficulty it does not. Recognition is many-to-one: a thousand different performances of “seven” must collapse onto one string, so the model’s job is to throw variation away. Synthesis is one-to-many: from five letters the model must invent a speaker, a pitch contour, a speaking rate, the emphasis, and the breaths. Nothing in the input says which of the infinitely many correct readings to produce, which is why modern TTS spends its parameters on duration predictors, style/speaker embeddings, and generative decoders.

06 — a different coreWhat if the middle box were physics?

Everything above treats the encoder as a stack of matrix multiplications. Here is the alternative Project Resonant is built to test: replace it with a population of coupled oscillators, and let the audio drive them.

The motivation is not aesthetic. Speech is oscillation — vocal folds cycling, resonances ringing, syllables at 4–8 Hz. A representation whose internal state is also a set of phases and frequencies starts closer to its data than a general-purpose matrix stack does. And the entire history of the signal lives in a fixed-size state — the phases — instead of a context window that grows with time.

The stadium crowd

Imagine a stadium at a concert, everyone holding their phone with the light on, each person swinging it in a slow windmill while their favourite singer plays.

A concert stadium seen from outside and above, roof open, a lit stage at the far end, every seat drawn as a phone light coloured by its phase, with a bright wave sweeping around the near side
Figure 7 — the whole model, in one picture. Every seat is an oscillator and every colour is where that phone’s light is pointing. The bright band sweeping the near side is the wave, and the stage at the far end is the audio driving it. Nobody is going anywhere and the seating chart never changes: what travels is the timing relationship between neighbours — which is exactly what the coupling term computes, and exactly what the readout measures.
  • Where each person’s light is pointing right now is that oscillator’s phase, θ. It swings around and around; straight up at 0 and at 2π is the same place in the circle.
  • Everyone has a preferred swing tempo, ω — the speed they would settle into if nobody else were there.
  • People glance at their neighbours and adjust: the coupling. You speed up or slow down depending on whether the lights beside you are ahead of yours or behind it.
  • The music from the stage pushes the whole section on the beat: the drive. This is where the audio enters — a loud low note leans on one part of the crowd, a bright cymbal on another.
  • A gentle tendency to let your arm drop keeps the whole thing from running away: the pinning.
  • The seating chart never changes. Nobody swaps seats — only the wave of light moves through them.

Written down, that is the Kuramoto model, one of the most studied equations in physics — it is how fireflies end up flashing together and how metronomes on a shared board come into step. Each oscillator updates its phase like this:

i/dt = ωi + Σj K(i−j) · sin(θj − θi)λ · sin(θi) + Fi(t)
ωOwn tempo. Every oscillator has a natural frequency it would keep on its own. In this demo they are laid out deliberately: each row of the grid is tuned to one band of the speech envelope, from about 0.4 Hz at the bottom to 6 Hz at the top.
K, sin(Δθ)Peers. The pull toward agreement, and the only place the model can learn structure. It depends on the phase difference, so it is a relationship, not a value — that is what makes the population synchronize rather than merely add up.
λPinning. A pull toward a rest phase. Without it the system is marginally stable and gradients through long sequences explode; with it, memory of the past decays at a controllable rate.
F(t)The audio. Each mel band’s loudness at this instant, injected into its own row of oscillators. Loud band, hard shove.
Figure 8 — the whole core, in one line. Compare with a transformer layer: there is no attention matrix, no feed-forward block, no layer norm. There is a tempo, a neighbourhood rule, a brake, and an input.

Coupling strength is the interesting dial. Too weak and every oscillator ignores the others — a bag of independent filters. Too strong and the entire population locks into one rigid clump that reports nothing except “loud”. The useful regime is in between, where parts of the field synchronize and parts do not, and which parts depends on what it is hearing.

toy: 24 oscillators on a ringK = 0.00 · R = —
Figure 9 — synchronization, from nothing to total. 24 oscillators with different natural tempos, drawn as dots on their shared circle. At K = 0 they smear around it forever. Push K up and they gather into a clump. The arrow is the order parameter R: the average of all the phases treated as unit vectors. R ≈ 0 means scattered, R ≈ 1 means locked together — and R is one of the numbers the readout reads.

Why a torus

The oscillators are not a loose bag; they sit on a 16 × 16 grid, and coupling depends only on the offset between two cells, not their absolute position — the same neighbourhood rule everywhere, which is exactly what makes a convolution a convolution. Rows are frequency bands (mel band b drives grid row b, so the grid inherits the ear’s layout); columns are a second dimension the dynamics can spread into.

Both axes wrap: the last row’s neighbour is the first row, the last column’s neighbour is the first column. A grid with both edges glued is a torus. Two reasons it is worth the trouble. First, no edges means no special cases — every oscillator has an identical neighbourhood, so one small kernel describes the whole field. Second, a translation-invariant kernel on a periodic grid is a circular convolution, which is a pointwise multiply in Fourier space: coupling all 256 oscillators to all 256 others costs one FFT rather than a 256 × 256 matrix. The physics of the configuration on this page is about 2,000 numbers.

A torus drawn as a lattice of dots, each coloured by its phase, with a travelling wave wrapping around both the ring and the tube
Figure 10 — the field on the shape it lives on. The same phase colours as the crowd, now wrapped onto the surface the grid actually forms. Rows run around the tube — that is the frequency axis, low bands to high — and columns run around the ring. Follow any row far enough and you arrive back where you started; the same is true of any column. That is what “periodic in both axes” buys: no oscillator is on an edge, so one small kernel describes every neighbourhood in the field, and the whole coupling step collapses into a single FFT.

Reading a physical system

You cannot feed phases to a classifier directly — θ = 0.01 and θ = 6.27 are neighbours on the circle but look far apart as numbers. So the readout takes sin θ and cos θ, which are smooth around the wrap, and summarizes each oscillator over the clip with four numbers: mean sin and mean cos (where it sat) and the mean sin and cos of its per-frame phase step (how fast it turned — an oscillator captured by the stimulus reports the stimulus’s rhythm, a free one reports its own). With 4 channels × 256 cells that is 4,096 features, and a plain linear layer on top.

IDENTICAL FRONT ENDPHYSICS CORE (REPLACES THE ENCODER)SAME HEADSSTFT + mel16 bandsdrive mapband b → row b× gain4 × (16 × 16) oscillatorsθ ← θ + dt · (ω + coupling − pinning + drive)coupling = circular convolution (one FFT)periodic in both axes = a torusstate θ carries over to the next frame— fixed-size streaming memoryreadoutsin θ, cos θ+ phase stepssoftmaxdigit 0–9CTCtextmel head→ vocoderphases persist frame to frame — the recurrence
Figure 11 — same stack, different middle. The front end and the output heads are deliberately the most boring possible choices and are shared with the conventional control models, so that any difference in results is attributable to the core and not to the plumbing around it.

07 — watch it runThe whole pipeline, live

Below, everything on this page runs end to end. Pick a digit and press play: the clip is analyzed into mel bands, the bands are injected into the oscillator field, 61 frames of physics are integrated, and the linear readout reports what it thinks it heard — all in your browser, in about the time it takes to blink. Or press record and say a digit yourself, and your own voice goes through the same path.

One thing to be clear about before you look: the physics here is not trained. The coupling kernel is a random draw that was never touched by gradient descent, the natural frequencies were designed by hand, and the only fitted part is the final linear layer. On held-out speakers this configuration gets of ten-way digits right. That is a statement about how much structure raw oscillator dynamics impose on their input — and section 08 runs the control that says how much of it the coupling deserves credit for. It is not a claim that any of this beats a trained network.

waveform
STFT
mel bands
drive
oscillator field
readout
the field on its toruschannel 1 of 4
turn the dialsas fitted
or record yourself saying a digit
input0.00 s
order parameter R · drive rows now
readout
source
detected
mean R
sim time
all four channels, flattenedhue = phase
Figure 12 — the live console. Three things reward watching. One: during silence the field still turns, each row at its own tempo — slow at the bottom, quick at the top. Two: when the word arrives the driven rows lurch, the pattern reorganizes, and the order-parameter traces swing. Three: the readout usually commits well before the clip ends, then holds. Every dial is real physics, but the readout was fitted at one setting and never refits, so moving a dial hands it a system it has never seen — that is what the badge means, and why predictions fall apart quickly. What that does not establish is how much the coupling was contributing; the next section prices that properly. On the record button: your take is resampled to 16 kHz, high-passed, trimmed to the word, and normalized to the corpus’s level and one-second window before it is analyzed — the front end’s levels are fixed arithmetic, so a raw microphone would be a different input distribution, not merely a louder one. Expect it to do noticeably worse on your voice than on the clips: a different microphone, a different room, and a linear readout fitted on 48 speakers who are not you.

08 — this is just the beginningWhat this shows, and what it doesn’t

Spoken digits are an easy task with a long history — they are the “hello world” of speech, and a physical spin-torque oscillator hit 99.6% on a comparable benchmark back in 2017. A high number here is not evidence that oscillator cores beat transformers at speech. What the demo does show, concretely:

  • Untrained dynamics carry usable structure. No gradient touched the kernel. The audio drives the field, the field organizes, and a linear probe reads the digit off the result.
  • The state is fixed-size and streaming. 4 × 256 phases at every frame, whatever the length of the input. No cache grows.
  • The whole model is tiny. The physics is roughly 2,000 numbers, and it simulates a second of audio in a browser tab in a few dozen milliseconds.

How much of it is the synchronization?

There are two different machines hiding in that description, and it is worth separating them. One is a bank of independent resonators: 1,024 oscillators, each tuned to a frequency band, each shoved by its own slice of the audio, none of them aware of any other. That is a perfectly good feature extractor, and it is not a new idea — it is what a filterbank does. The other is the coupled field: the same oscillators, now allowed to pull on their neighbours, so what any one of them does depends on what the ones around it are doing. Only the second one is a synchronization model.

The difference between them is a single number — the coupling kernel. Set it to zero and the neighbours stop listening to each other; everything else stays identical. Fit the same linear readout on each and you can price the coupling directly:

FieldReadoutTest accuracy
coupled — neighbours interactfitted on this field96.2%
uncoupled (K = 0) — a plain resonator bankrefitted on this field94.2%
uncoupled (K = 0)the coupled field’s readout, unchanged17.4%

Two points. On spoken digits, letting the oscillators talk to each other is worth about two points over letting them ring independently — real, repeatable across seeds, and much smaller than the headline number would suggest. Most of the work is being done by the resonator bank and a generous linear readout.

The third row is a different kind of statement, and it is the one most likely to be misread. It is not a measurement of the coupling; it is what happens when you change the machine and keep the old readout. The linear layer was fitted to one physical system and handed a different one, so it fails — the way a key fails in a lock it was not cut for. The physics is fine. The translation is stale.

Why does a two-point gap still matter? Because of what is being compared. A resonator bank is a fixed function: each oscillator's response is decided the moment you choose its frequency. A coupled field has a shape that can be changed — the kernel says who listens to whom and how strongly, and that shape is what makes patterns like travelling waves and partial synchronization possible at all. Here that shape is a random draw that no gradient ever touched, and it still buys two points. The interesting question is not whether an arbitrary coupling helps a little; it is what a good one does.

There are two obvious ways to find out, and both are open. Train it: the kernel is a small, differentiable parameter set, so gradient descent can shape who couples to whom instead of leaving it to chance. Change the physics: Kuramoto's sin(θⱼ − θᵢ) is only the simplest way for two oscillators to interact. Add a phase lag and you get travelling waves; add a second harmonic and the population splits into clusters instead of one clump; amplitude-carrying oscillators can express loudness as well as timing. Each is a different coupling law over the same field, and each is being worked through with the same discipline as everything else here — a parameter-matched control and a bar written down first.

Where this goes

The open question is whether the wave-physics prior is a genuinely better architecture for wave-shaped input and output — real-time speech in and out of one interruptible, context-carrying core — or whether it is a beautiful idea that a boring stack of matrices beats at every size. The repository is built so that the hypothesis can fail cleanly: parameter-matched controls, frozen baselines, immutable training logs, and verdicts written before the runs. That work is ongoing, and the interesting part is still ahead.

09 — go deeperThe code, and the prior art

Everything on this page — the front end, the oscillator core, the readout, and the ten recordings — comes out of a research repository that holds the hypothesis, the architecture, every experiment log, and the results that refuted my own expectations. It is getting a clean-up pass before it goes public; the link will land here when it does.

Prior art worth reading

  • The Kuramoto modelthe synchronization dynamics at the core
  • AKOrNtrained Kuramoto neurons for vision and reasoning
  • coRNNoscillator ODEs as sequence models
  • LinOSSoscillatory state-space models for long sequences
  • Neural Wave Machinestraveling waves in recurrent states
  • Spintronic oscillator reservoirspoken digits on one physical oscillator
  • Vocosthe fast iSTFT-head vocoder
  • Un-0image generation from coupled oscillators
  • AudioMNISTthe spoken-digit corpus every clip on this page comes from