A music model you can play with, not just prompt. It answers what you play in about 200 milliseconds, on a laptop. The first version took two seconds.
Try both partners on the pads. Then we build, piece by piece, everything that closes that gap.
You need what an audio waveform is and the idea of a network that predicts the next token. We build the rest from zero.
Your notes appear in the top lane. Your partner's answers travel toward the now line in the lane below.
Chapter 0
Why two seconds turns a jam into a fax machine
Sit down at a piano with a friend. You play a chord; they answer with a bassline; you nudge the rhythm; they follow. It works because the gap between your move and their response is tiny, a few tens of milliseconds. You don't experience a conversation. You experience playing together.
Now give that friend a two-second delay. You hit a chord; two seconds of silence; then their reply, for the chord you've already moved on from. That is the first partner on the pads above. The magic is gone, not because the friend is unmusical, but because of latency: the delay between an input and the system's reaction to it.
This is the wall every "AI music generator" has hit. Most models are offline: you type a prompt, wait, and a finished clip drops out. Wonderful for producing a track; useless for playing one. The original Magenta RealTime (MRT, or v1) was a landmark because it generated music continuously and let you steer it as it played. But its reactions lagged by around two seconds. You could conduct it, the way you'd conduct an orchestra over a slow phone line. You could not jam with it.
Magenta RealTime 2 (MRT2) cuts the reaction time from roughly two seconds to about 200 milliseconds, a ~15× improvement, while running on a consumer laptop. Two hundred milliseconds is where steering stops feeling like remote control and starts feeling like play. That one number, and everything the architecture had to become to hit it, is what this lesson is about.
Let's measure the wall on the beat grid. At 120 beats per minute each beat is 500 ms apart. You strike on beat 1; the partner answers after whatever latency you dial in.
Drag the latency. The teal dot is you on beat 1, the warm dot is the reply. Press Hear it to play two bars with a click track.
So the design goal of MRT2, in one sentence: generate high-fidelity stereo music continuously, let a musician change MIDI notes, audio style, and drums at any instant, and react within ~200 ms, all on an Apple-Silicon MacBook. Every architectural choice ahead is downstream of that sentence. Whenever something looks strange ("why not just use a normal Transformer?"), the answer will almost always be: because of the wall.
Here is the road, in order:
Chapter 1
The neural audio codec, and why one instant of music is twelve tokens deep
A language model predicts the next token from a finite vocabulary. Raw audio isn't tokens. One second of CD-quality stereo is 96,000 floating-point numbers: 48,000 samples per second, two channels. You cannot ask a Transformer to predict the next floating-point sample 96,000 times a second; the sequence would be astronomically long and the values continuous. We need to turn the river of audio into a manageable stream of discrete symbols. The device that does this is a neural audio codec.
Think of it as a learned MP3. A classical codec compresses with hand-designed math. A neural codec learns the compression: an encoder network squashes a waveform into a short sequence of integer codes, and a decoder network expands those codes back into a waveform that sounds almost identical. The integers in the middle are exactly the tokens our language model will predict. MRT2's codec is called SpectroStream.
Every later chapter leans on the dimensions, so let's pin them down. Hover or tap any symbol to see what it means. The input waveform is:
0.0123.So a one-second clip is a 48,000 × 2 grid of real numbers. The encoder turns it into a much smaller grid of integers:
Top: a stereo waveform cut into 25 frames of 40 ms. Bottom: the 300 integers the codec turns it into, one column per frame, coarse at the top. Tap a frame.
Why does one frame need twelve tokens instead of one? Because of how the codec quantizes, a scheme called residual vector quantization (RVQ). Suppose you must describe a precise colour using a fixed palette of 1,024 paint chips. Your first chip is the closest single match, but it's a bit off. So you look at the residual, the leftover difference, and pick a second chip that best captures that. Then the leftover of the leftover. Stack 12 chips and you've described the colour far more exactly than any single one could. RVQ does this with sound: token 1 is the coarse approximation of the 40 ms frame, token 2 corrects its error, and so on down to token 12, the finest detail. Coarse to fine, twelve levels deep.
You can hear that ladder. The device below quantizes a short chord one rung at a time.
The grey line is the original sound, zoomed to a few milliseconds. The blue line is what survives with the rungs you allow. Climb from 1 to 12 and listen to the error shrink.
Each rung here chooses between just two codes and works on raw samples, so you can hear every rung matter. SpectroStream's rungs each choose among 1,024 codes and quantize learned features of a 40 ms frame. Same coarse-to-fine logic, far more detail per rung.
Now the compression ratio. SpectroStream squeezes 48 kHz stereo to about 3 kbps. One second is 25 frames of 12 tokens: 300 tokens per second. Against 96,000 raw samples, the codec has shrunk what the language model must predict by 320×. That shrinkage is what makes real-time prediction thinkable.
1 second → 25 frames × 12 tokens = 300 tokens (vs 96,000 samples)
The round trip closes cleanly. At generation time the language model produces a fresh token grid x′, and the decoder turns it back into audio: a′ = Dec(x′). The language model never touches a waveform. It lives entirely on these integer grids, and the codec is the translator at both ends.
Enc → x (25×12 codes per second). The language model predicts the next frame's 12 codes → x′ → Dec → a′ → speakers. Everything else in this lesson happens in the middle, on the integer grid.Chapter 2
The unit of autoregression is the floor on reaction time
This is the idea that is MRT2. Everything else supports one decision: what size piece of audio does the model commit to at a time?
An autoregressive model generates a sequence by repeatedly predicting the next piece and feeding it back in. The crucial knob is how big that piece is: the unit of autoregression. And here is the iron law that ties it to the wall: the model cannot react to your input faster than the unit it's committed to generating. If it's midway through a piece, your change can only take effect at the start of the next one. The unit size is the minimum reaction delay.
The original Magenta RealTime chose a big unit: a 2-second chunk, generated by a T5-style encoder-decoder. The encoder reads its context with bidirectional attention, looking forward and backward across the window. That's powerful, but "looking forward" only makes sense when you hold a whole window, so the model works a chunk at a time. The consequence for latency is brutal: your control change can't land until the next 2-second boundary. Minimum reaction delay, about 2 seconds. The wall, baked into the architecture.
MRT2 shrinks the unit to a single frame: 12 tokens, 40 ms. Instead of committing to two seconds of the future, it commits to forty milliseconds, then reconsiders. To do that it drops the bidirectional encoder (there's nothing ahead to peek at inside a frame that doesn't exist yet) and becomes a decoder-only model with strictly causal attention: each token sees only the past. That's the trade. v1 bought richer context at the cost of a 2-second reaction; MRT2 buys 40 ms granularity at the cost of never peeking ahead. For a live instrument, that's the right trade.
Both models play the same groove. Press play, then twist the knob whenever you like: it asks for a brighter chord. v1 can only change at its next 2-second wall; MRT2 changes on its next 40 ms frame. Choose which one you hear.
Read the gap between the two reaction markers. MRT2's is never more than 40 ms after you act. v1's can be nearly two full seconds. That gap is the 15× improvement, made audible.
Shrinking the unit creates two new problems, and much of the rest of the lesson solves them. First: a frame is still 12 tokens, and rolling those out naively 25 times a second could be too slow, so we need a cheap way to produce them (Chapter 3). Second: a causal decoder that runs forever accumulates an ever-growing history, and attention cost grows with it, so we need to attend to the past without paying for all of it (Chapter 4).
Chapter 3
One reads across time, one reads down the ladder
We just committed to generating one 40 ms frame at a time. But a frame is 12 RVQ tokens, and they aren't independent: token 5 only makes sense as a correction to tokens 1 to 4. Meanwhile frame i depends on the whole musical past. We have dependency in two directions: along time, frame to frame, and along depth, token to token within a frame.
The naive fix is to flatten everything into one sequence of 300 tokens per second and run one giant Transformer. It works, but it re-attends over the entire flattened history for every one of the 12 tokens in every frame. MRT2 splits the labour between two Transformers, a design from the RQ-Transformer family:
once per frame, 25 per second
Reads the history of past frames and compresses it into one context vector: "given everything so far, here's the situation now." The expensive, over-history part.
12 per frame, 300 per second
Small and fast. Given that context vector plus the coarser tokens already chosen, it picks the next finer token. It walks down the ladder, never across time.
You pay for history once per frame, then cheaply expand it into 12 tokens. Here is the probability the two networks model together. It factorises along both axes, frames outside, depth inside:
So to generate frame i, the temporal network fires once; then the depth network fires 12 times, each time conditioned on that vector plus the tokens it has laid down this frame. Decode those 12 codes with SpectroStream and you have 40 ms of fresh stereo. Repeat 25 times for a second.
Step through it. The temporal network fires once and hands over a context vector; the depth network then fills the 12 rungs, each one reading the rungs above. Or generate a full second and watch the counters.
Chapter 4
Sliding windows, and the tokens that hold the softmax up
MRT2 is meant to play indefinitely; a jam can last an hour. But a causal Transformer's attention cost grows with the history it attends to. If frame 90,000 (an hour in) had to attend over all 89,999 before it, real time would collapse. We need to bound the history without the music falling apart. That bound is sliding window attention (SWA).
Each frame attends only to the most recent w frames, a fixed-size window that slides forward. Older frames fall out of view. The cost per frame becomes constant (it depends on w, not on how long you've played), so the model can stream forever at steady speed. The implementation is a rolling cache of the keys and values each past token contributes (a "KV cache"): new entries are written in, entries older than w are evicted.
There's a notorious failure lurking, and MRT2 meets it head on. When the very first tokens of a stream slide out of the window, models tend to deteriorate sharply. Why would dropping ancient, long-irrelevant tokens hurt? Because those first tokens were acting as attention sinks.
The softmax inside attention forces the weights to sum to 1. Every query must put its attention somewhere, even when nothing is important. Models learn to dump that excess onto the first few tokens, a pressure-release valve. Those tokens become load-bearing for their role, not their content. Evict them, and every query's leftover attention has nowhere stable to go; quality craters.
MRT2's fix: a learnable attention-sink embedding, a few permanent trained "tokens" pinned at the start of the window that are never evicted. Every query gets a stable place to park its excess attention, while real musical history scrolls past. The sink stays; the music flows through.
The tape is the frame stream; the bright band is the window of the last 50 frames. Press play and let it run past frame 50, when the first frames get evicted. Turn the sink off and listen to what happens next.
The sound is a dramatization: we degrade a clean loop in proportion to the quality meter, to make the collapse easy to hear.
One more subtlety: position. A Transformer needs some way to know token order. v1 used learned positional embeddings, which don't generalise past the length you trained on; fatal for a model meant to run arbitrarily long. The team tried RoPE (rotary position encoding), then leaned on a striking finding: with causal masking and a sliding window, a decoder can infer order implicitly, the NoPE ("no positional encoding") approach. The causal mask itself tells each token how far back things are, so explicit position signals can go, and the model generalises to any length. One constraint ties it together: the window is sized so the model's reach never exceeds the crop length it trained on, so it's never asked to extrapolate.
Chapter 5
Every control rides the same 40 ms clock as the audio
We can now generate endless, coherent music. But a fixed jam isn't an instrument. The point is that you steer it, live. This chapter is the spine of every control: how an outside signal gets into the generator fast enough to matter.
Formally we move from modelling P(x) to the conditional distribution Pθ,φ(x | c), where c is everything you're telling the model. MRT2 bundles three control streams:
The most important decision about control is easy to skim past: every conditioning signal is tokenised at the audio frame rate, 25 Hz, the same 40 ms grid as the audio tokens. The notes you hold, the style embedding, the drum flag: each is sampled into one value per frame. That means a change can be absorbed by the next frame the model generates. If conditioning lived on a slower clock, say once per second, your input could wait up to a second to be seen, however fast the generator ran. Frame-rate conditioning is what turns Chapter 2's 40 ms granularity into 40 ms responsiveness.
Mechanically, the per-frame control values are concatenated into one conditioning vector for that frame, mapped into multi-channel embeddings, and injected into the temporal decoder through streaming cross-attention. Cross-attention means the generator's frame query attends to the conditioning embeddings, rather than to its own past. Streaming means it happens frame by frame as new control arrives, not once as a prompt at the start.
One column per 40 ms frame. At the playhead the three lanes are read, concatenated, and cross-attended into the temporal decoder, which emits that frame's 12 tokens. Switch a lane off and the model decides that axis for itself.
Chapter 6
The pianoroll, four tokens per pitch, and Auto-Strum
The notes lane, cnotes, is what lets you play MRT2 like an instrument: hold a chord on a MIDI keyboard and the model renders it in the current style. It needs a representation of "which notes are sounding right now" that lives on the 40 ms grid. That representation is a pianoroll.
Picture graph paper. The vertical axis has one row per MIDI pitch, 128 channels, from the lowest rumble to the highest ping. The horizontal axis is time, one column per frame. A cell is lit when its pitch sounds in that frame. That grid is cnotes.
Where do training pianorolls come from? MRT2 was trained on roughly 71,000 hours of instrumental stock music, but as audio, not MIDI. So the team ran a transcription model, MT3, over all of it to infer the notes. The model learns "these pitches, in this style, make this audio" from 71k hours of automatically transcribed examples.
A lit cell isn't enough information, though. Striking a note and holding one that's already ringing sound very different. So each pitch row, each frame, carries one of four tokens:
This vocabulary unlocks the signature note feature, Auto-Strum. Its two modes differ in who decides the attacks:
The model learns the first mode through onset-masking augmentation. During training, some onset and continuation tokens are randomly replaced with a special onset-mask token, hiding when notes were struck. Forced to produce plausible audio anyway, the model learns to invent musical attacks when onset information is missing. At inference, feed it masked onsets and it strums; feed it explicit onsets and it obeys. One trained behaviour, two playing styles.
One bar at 120 BPM: 16 steps, 2 seconds, 50 frames. Tap cells to place notes; touching cells in a row form one held note. Tap a note name to see that row's token stream below. Then play it with Auto-Strum off and on.
cstyle = "grand piano" produces piano; with "fuzz guitar", guitar. The pianoroll says what pitches; the style says what it sounds like; the model fuses both into each frame's 12 RVQ tokens. That separation is why you can hold one chord and morph its timbre live.Chapter 7
MusicCoCa, a frozen style space, and a one-step mapper
The style lane, cstyle, answers "what should it sound like?": genre, mood, instrumentation. You might specify style by text ("warm analog synthwave") or by an audio reference. The model needs one internal notion of style that both can map into. That shared space comes from MusicCoCa.
MusicCoCa embeds music and text about music into the same vector space, a contrastive captioning model for audio in the CLIP family. Train it so a clip of bossa nova and the words "relaxed bossa nova guitar" land near each other, and proximity means stylistic similarity whether a point came from audio or text. MRT2 uses MusicCoCa's quantised (RVQ) style embeddings as cstyle and keeps MusicCoCa frozen: its weights are not trained further inside MRT2.
Freezing exposes a real problem: the train/test modality mismatch. During training, style usually comes from audio. At inference, users often give text. Even in a shared space, text and audio don't land in the same places: one prompt like "lo-fi piano" corresponds to many valid audio renditions, scattered across a region. Feed the generator a lone text point and it may sit slightly off the distribution of audio embeddings it trained on.
MRT2's fix is a small bridge network, a Pixel Mean Flow (pMF) mapper. It takes a text embedding and maps it into the distribution of plausible audio embeddings, learning that one-to-many relationship explicitly. Mean Flow is a generative technique, a cousin of flow matching and diffusion, tuned here for high-quality one-step inference: it jumps from the text point to a valid audio-style point in a single shot, essential inside a 40 ms budget. It's trained on short tags ("techno") and long captions ("driving four-on-the-floor techno with a detuned acid bassline") alike.
A flattened picture of the style space. Each teal point is a text prompt; its purple cloud is the audio that validly realises it. Notice the text points sit off their clouds. Pick a prompt: the mapper jumps, in one step, to a point inside the cloud, and you hear that rendition. Tap anywhere to hear the space itself.
In this toy, a point in the space sets our synth's filter, attack, and detune. In MRT2 the point is a MusicCoCa embedding that conditions the generator every frame.
MusicCoCa (frozen) → style embedding. If the source was text, it also passes through the pMF mapper → a valid audio-style embedding. That becomes cstyle on the 25 Hz bus (Chapter 5), cross-attending into the generator every frame. Change the prompt mid-jam and the vibe follows within a frame or two.Chapter 8
Guidance per signal, and masks as a paintbrush
Three controls ride the bus: style, notes, and the one we deferred, cdrums. This chapter explains drums, then shows how MRT2 lets you balance all three like channels on a desk, and leave channels deliberately blank.
You might expect drums to work like the pianoroll, with exact hits. But a drum hit is instantaneous, and the end-to-end reaction (the ~200 ms we keep meeting) is too slow to place individual kicks and snares tightly. So MRT2 transcribes drum stems from training audio with OaF Drums (Onsets and Frames for drums) and learns a frame-wise drum-presence signal. At inference cdrums is mainly a switch: generate with drums, or a drumless texture. "Drop the drums for this section, bring them back for the chorus."
How does one model both honour your controls and let you dial their strength, or switch one off? Classifier-free guidance (CFG), extended to several signals. Train the model to generate both with a condition and without it, by sometimes dropping the condition in training. At generation time you have two predictions, conditional and unconditional, and you extrapolate: push the output in the direction the condition pulls it, by an adjustable amount. A weight near 1 follows the control about as much as training did; higher exaggerates adherence; toward 0, it barely heeds it. MRT2 does this independently for each of the three signals, so you can crank note adherence while loosening style. Three guidance knobs, one stream.
That machinery is also how the drums switch works: drumless means running the drum signal's guidance toward its negative direction, steering away from drums rather than toward them.
Press play; the loop keeps running while you move the faders. The screen shows the melody you asked for (teal outlines) against what the model plays (warm). Pull notes guidance down and the pitches drift; push style past 8 and it overcooks; take drums to 0 for a drumless texture.
That seg control is the last idea, and the most creative: masking as a paintbrush. During training, MRT2 randomly masks contiguous regions of each control signal, sometimes a stretch of time, sometimes a band of pitches. The model learns to follow controls where they're given and improvise where they're blank. At inference that robustness becomes expressive:
Masking turns missing input from a bug into a dial for how much freedom you grant the model: full control at one end, open-ended jamming at the other.
Chapter 9
Adding up 200 milliseconds
We've built every piece. Now let's account for the 200 ms. Here's the puzzle: the model generates a 40 ms frame at a time, so why is the end-to-end reaction ~200 ms and not ~40? Because reaction time is a chain, and the model's own step is only one link. Follow a single keypress through it:
Add them up and you land near 200 ms, about 5× the frame. The model's compute (the three warm links) is the minority. The buffering at the edges is the real tax, the price of running glitch-free on a general-purpose laptop inside real audio software.
Warm is the model; grey is plumbing. Tune the buffers and the model's speed, then press Hear your total: you tap, and the answer arrives after exactly the delay you built.
The split between links is illustrative; the published figure is the ~200 ms total. Host overhead is held at 25 ms, and model compute divides roughly 45 / 35 / 20 between temporal step, depth decode, and codec.
The compute link stays small on a laptop because of the deployment stack. MRT2 ships as a C++ inference engine built on MLX, Apple's array framework for Apple Silicon, which compiles the model into a .mlxfn container that DAW plugins and standalone apps can load. The 2.4B-parameter base model streams in real time on an M3 Pro or M2 Max; a smaller 230M variant runs on any MacBook Air. (v1 needed a TPU or GPU in the cloud.) The architecture made 40 ms frames possible; MLX made them fast enough on hardware you own.
Chapter 10
The cheat sheet, and where MRT2 sits in the field
You can now read the Magenta RealTime 2 write-up and explain every line: why frames instead of chunks, why two Transformers, why attention sinks, why MusicCoCa is frozen, why the latency is 200 and not 40. Let's lock it in.
MRT2 turns 48 kHz stereo into 300 codec tokens per second with SpectroStream's 12-deep RVQ. A decoder-only model generates one 40 ms frame at a time: a temporal Transformer summarises the windowed past once per frame, a small depth Transformer unrolls the frame's 12 tokens. Sliding-window attention with a learnable attention sink (and NoPE) lets it stream forever at constant cost. Three controls ride a 25 Hz bus: style through frozen MusicCoCa plus a one-step Mean Flow mapper, notes through a 128-channel four-token pianoroll with Auto-Strum, and drums on or off. Each is weighted by its own classifier-free guidance and can be masked for creative freedom. It runs on Apple Silicon through an MLX C++ engine, reacting in ~200 ms: fast enough to jam.
| Quantity | Value | Why it matters |
|---|---|---|
| Frame rate fk | 25 Hz (40 ms per frame) | The autoregressive unit, the floor on responsiveness |
| RVQ depth dc | 12 tokens per frame | Coarse to fine; unrolled by the depth Transformer |
| Codec vocab Vc | 210 = 1,024 | Codes per token slot |
| Tokens per second | 25 × 12 = 300 | vs 96,000 raw samples: 320× compression |
| Bitrate | ~3 kbps at 48 kHz stereo | SpectroStream compression |
| Pianoroll | 128 channels, 4 tokens | off, generic on, onset, continuation |
| Note training data | ~71k hours, MT3-transcribed | Where the pianoroll-to-audio mapping is learned |
| Parameters | 2.4B base, 230M small | vs v1's 760M and 220M |
| Control latency | ~200 ms (~15× vs v1) | The whole point |
| Hardware | M3 Pro or M2 Max; Air for 230M | MLX C++ engine, .mlxfn |
python# MRT2 generation loop (one frame), in pseudo-Python def generate_frame(history, control, guidance, masks): # 1. CONTROL: sample each signal at this frame (25 Hz bus) c_style = mean_flow(musiccoca_text(control.prompt)) # frozen encoder + 1-step mapper c_notes = pianoroll_tokens(control.midi, auto_strum=control.strum) # 128 ch x 4-token vocab c_drums = control.drums_on c = apply_masks(concat(c_style, c_notes, c_drums), masks) # blank regions = freedom # 2. TEMPORAL: summarise the windowed past ONCE (SWA + sink + NoPE) ctx = temporal_theta(history[-W:], sink=learned_sink, cross_attend=c) # cost set by W, not len(history) # 3. DEPTH: unroll 12 RVQ tokens, coarse to fine, each sees the coarser ones frame = [] for j in range(12): logits = cfg_mix(depth_phi(frame, ctx), guidance) # independent weight per signal frame.append(sample(softmax(logits))) # 4. CODEC: 12 codes -> 40 ms of 48 kHz stereo audio return spectrostream_decode(frame) # a' = Dec(x')
Now press Present or Teach and explain the 200 ms budget back, out loud, from memory. If you can account for every link, you own this model. Then go back to the pads and play with the MRT2 partner one more time.