# 4. Radio Station Pitfalls
Part of [[In-Game Radio Stations]]. Previous: [[3. DJ Chatter Ducking and Receivers]].
> [!note] Verification status
> Seek and scheduling behaviour as cited in Part 2 (`timeSamples`, `PlayScheduled` past-time rules). Pause/`dspTime` interaction as documented for `AudioSettings.dspTime` (advances with processed audio samples). **No new code; nothing compiled.**
## Continuity that "almost" works
- **Rewriting origin on tune-out.** The station then restarts. Origins are set once, at boot (or New Game).
- **Using `Time.time` for the clock.** It diverges from the audio thread and pauses differently. Use `AudioSettings.dspTime`.
- **Forgetting playlist wrap.** `FindAt` must modulo `TotalDuration` on looping stations or you will run off the end and go silent after one pass.
- **Shuffling every tune-in.** The clock walks a sequence. Shuffle that sequence once. Shuffling again makes `stationTime` point at a different clip.
- **Desync after pause.** If you set `AudioListener.pause = true`, `dspTime` stops and continuity is preserved. If you pause gameplay but not audio, the radio correctly keeps going - which may surprise a designer who used `Time.timeScale = 0` and expected silence. Be explicit ([[2. Audio Mixer Snapshots and Exposed Parameters]]).
## Pops when seeking or stitching
- Seeking a heavily compressed clip to an arbitrary sample can click. Unity's `SetScheduledEndTime` page explains why: frame-based lossy codecs do not like hard cuts. Prefer songs imported so seeks are reasonable (Compressed In Memory, or a format/bitrate you have tested), and hide residual clicks with a 20-40 ms volume ramp if you hear them.
- Calling `Play()` then setting `timeSamples` (wrong order) starts at 0 and then jumps - you *hear* the seek. Assign clip, set `timeSamples`, then `Play()` as `PlayEntryNow` does.
- Scheduling the next song *after* the current one has already ended leaves a gap. `Update` checks `dspTime + scheduleAhead >= nextBoundary`. If a hitch makes you late, `PlayScheduled` in the past starts as soon as possible and drops the missed audio - a small dropout beats a throw.
## Streams and load cost
`PlayScheduled` exists in part so streamed files can open and buffer without a CPU spike. Still:
- Do not `Resources.Load` on the boundary frame.
- A station with twenty 4-minute songs all set to Decompress On Load will hurt memory. That is an import-settings problem, not a scripting one.
- `Audio Random Container` (see [[Audio Mixers and Character Audio]]) is the wrong tool for a radio playlist you intend to seek into; it is the right tool for footsteps.
## Score vs radio
If both [[Music Mood Mixer]] stems and the radio play at 0 dB, the mix turns to mud and Rogers' "music should be more exciting than the action" test fails because *everything* is exciting. One snapshot (`RadioOn`) should decide the foreground. Do not call `TransitionTo` from both the mood director and the receiver without a single arbitrator.
## Voice use
A radio needs two track sources plus one DJ source - three real voices, priority 0 on the tracks so they are not virtualized (the Audio Source reference: priority 0 is most important, 256 least, default 128; use 0 for music). Do not also keep a silent source per station "so they're really playing." That is the thing the virtual clock exists to avoid, and it will wreck a Quest voice budget ([[4. Interactable Audio Pitfalls and Quest]]).
## Diegetic receivers that outlive their object
`PlayClipAtPoint` (see [[Interactable Audio]]) spawned a temporary source that could not route to your mixer and died with no owner - bad for radio. `RadioPlayer` should live in a persistent gameplay object, not on the car that gets destroyed at the end of a race. The *receiver* sits on the car and talks to the player. If you destroy the object that owns `RadioPlayer`, every radio in the level goes silent.
## Input fights
`RadioReceiver.Update` reads `Keyboard.current` and will fight any other script that also uses R / `,` / `.`. Once the Input System actions are authored ([[Input System]]), delete the fallback `Update` so a text field or a vehicle camera modifier can own those keys.
## What this is not
This is not a streaming internet radio, an Icecast client, or a licensed soundtrack backend. It is an in-world playlist machine with a convincing lie about continuity. A later queued tutorial covers driving real hardware (Eurorack, Moog Subharmonicon and Mother-32) from Unity; that is a different problem, and this radio should not pretend to be a live broadcast unless you actually hook live input.
## Related follow-ons
- [[Spatial Audio and Reverb Zones]] - make the boombox occupy space, including on Quest 2
- [[Music Mood Mixer]] - who ducks whom
- [[FMOD vs Built-in Mixer and Procedural Synth]] - FMOD playlists and programmer instruments if this outgrows ScriptableObjects