Skip to content
DEV505 / Sound ManagerDOCUMENTATION

DEV505 / SOUND LAB / 08

A little groove.

Crossfade two tracks and keep a little dancer moving.

Peach Sunset is coming in while the previous track fades out. The two gain meters show both plays are active during the transition.
Jukebox in Unity: two tracks during a transition. The real scene controls and status readouts are visible.

Peach Sunset is coming in while the previous track fades out. The two gain meters show both plays are active during the transition.

In Unity’s Project window, open Assets/DEV505/SoundManager/Samples/08-Jukebox/Demo.unity. The supplied scene already has its Sound Manager, event registrations, generated keys, camera, and Audio Listener. Press Play, wait for the demo to be ready, and click the Game view before using the keyboard. If you are setting up a separate scene, follow Your first sound first.

Control Action
Space Play or pause.
1 / 2 / 3 Select one of the three tracks.
Left / Right Previous or next track.
S Stop music.
R Toggle automatic next-track behavior.
Track cards and volume slider Choose music and adjust its shared volume.

Start Mint Morning and let it reach full level. Choose Peach Sunset. For roughly 2.5 seconds, both tracks are alive: the first recedes as the next arrives. Pause during a transition, then resume. Both recordings and their fade progression should continue together.

The event is 2D stereo music. The scene still needs its configured Audio Listener, but the jukebox’s distance from that listener does not attenuate these tracks.

The first track is playing while DEV505 dances. The demo uses the track's stored BPM value to set the dance speed; it does not analyze the music in real time.
Jukebox in Unity: mint Morning is playing. The real scene controls and status readouts are visible.

The first track is playing while DEV505 dances. The demo uses the track's stored BPM value to set the dance speed; it does not analyze the music in real time.

The transition has finished and playback is paused. The dancer pauses with the music.
Jukebox in Unity: take a musical pause. The real scene controls and status readouts are visible.

The transition has finished and playback is paused. The dancer pauses with the music.

Track supplies the audio clip, Gain shapes the transition level, and Volume supplies the listener's chosen volume. Each track plays through its own instance of this graph.
Jukebox in Unity: the Jukebox graph. The graph nodes and their connections are visible.

Track supplies the audio clip, Gain shapes the transition level, and Volume supplies the listener's chosen volume. Each track plays through its own instance of this graph.

Unity's Debug Inspector shows the imported Track parameter and its three allowed clips: Mint Morning, Peach Sunset, and Midnight Pixels. This is a read-only inspection of the compiled event; author changes in the graph.
Jukebox in Unity: the three allowed tracks. The saved event values are visible in the Inspector.

Unity's Debug Inspector shows the imported Track parameter and its three allowed clips: Mint Morning, Peach Sunset, and Midnight Pixels. This is a read-only inspection of the compiled event; author changes in the graph.

Track is an Asset parameter. Its allowed list contains Mint Morning, Peach Sunset, and Midnight Pixels. Supplying the chosen clip in the initial context tells the playback node what to start. A clip that is outside the allowed list is not a substitute track; handle the refused context instead.

Gain is each play’s transition amount. Volume is the listener’s volume preference, applied to both plays. Keeping them separate means moving the volume slider does not overwrite the fade.

Gain is shaped by a sine function and multiplied by Volume before reaching Play Audio. The demo script drives the incoming and outgoing Gain values during a track change.
Jukebox in Unity: shape the fade, then apply volume. The graph nodes and their connections are visible.

Gain is shaped by a sine function and multiplied by Volume before reaching Play Audio. The demo script drives the incoming and outgoing Gain values during a track change.

Gain rises and falls at 0.4 units per second, so a full 0-to-1 change takes 2.5 seconds. The graph shapes it with sin(Gain × π / 2) and multiplies by Volume. With opposing full fades, this gives an equal-power curve: the middle of the transition avoids the level dip of a simple linear blend. The perceived result still depends on the loudness and content of both recordings.

The controller follows this order:

  1. Start the selected Track with Gain 0, so it cannot begin at full level before the fade is set up.
  2. If accepted, keep the old handle as the outgoing play and the new one as current.
  3. Set outgoing Gain to 0 and incoming Gain to 1. Let graph smoothing do the fade.
  4. Read the outgoing parameter’s current value. Stop that play only once it has reached silence.
Start the next track quietly · excerpt
var context = SoundPlayContext.At(transform.position, owner)
.With(SoundParameters.Jukebox.Track, selectedClip)
.With(SoundParameters.Jukebox.Gain, 0f)
.With(SoundParameters.Jukebox.Volume, volume);
var result = SoundBus.Play(Sounds.Jukebox, context);

The recipe supplies the ready service and owner, and retains handles only after acceptance. Once both handles exist:

Ask the graph to crossfade · excerpt
SoundBus.SetFloat(outgoing, SoundParameters.Jukebox.Gain, 0f);
SoundBus.SetFloat(current, SoundParameters.Jukebox.Gain, 1f);

Setting a target of zero is not proof that the old track is silent yet. Stopping immediately would cut off its fade. The demo permits two Jukebox instances; it keeps the latest requested selection while a transition is underway and starts it when room is available. That selection queue is controller behavior, not built into the graph.

Pause applies to both handles and freezes their graph progression. Do not retire the outgoing track while paused just because its target is zero. Normal Stop in the full demo fades the music toward silence; stopping while paused cleans it up directly. Disable cleanup also ends all music owned by the controller.

DEV505’s dance and record movement use authored BPM metadata for each track. The demo is not detecting tempo or analyzing an audio spectrum. The crossfade is not beat matched, and the elapsed-time display is an estimate rather than an exact DSP playback position. Those are deliberate boundaries of this sample.

  • The new track jumps in loudly. Give it initial Gain 0 in the context, before playback begins.
  • The old track cuts off. Wait for Current gain to reach zero; Target becomes zero immediately.
  • One song keeps playing during pause. Pause current and outgoing handles together.
  • Rapid choices are refused. The graph allows two plays. The demo queues the latest choice; the smaller recipe asks you to wait for the current transition.
  • The dancer is out of step with an edited track. Update its authored BPM metadata; it is not doing automatic beat detection.

These are the saved graph settings. A play can supply different initial parameter values. Float smoothing is measured in units per second; a rate of 0 applies changes immediately.

Sounds.Jukebox

Position
2D
Overlapping plays
2 · RejectNew
Cooldown
None
Owner loss
Stop
Keep Alive
Off — ends when its work is finished
ParameterTypeDefaultRangeRise / fall rate
TrackAssetJukebox_MintMorningAllowed clips belowNot smoothed
GainFloat10–10.4 / 0.4
VolumeFloat0.650–14 / 4

Track allowed clips: Jukebox_MintMorning.wav, Jukebox_PeachSunset.wav, Jukebox_MidnightPixels.wav.

Signals: None authored.

For the meaning of these settings, see Playback settings. The default numbers above come from the Unity graph audit stored with this documentation.

Open the complete integration recipe for the script, Inspector setup, a short test, and cleanup. Use Play context for initial values and placement, and SoundBus for playback controls.

All Jukebox Unity captures includes further states and readable graph details, with steps to reproduce each view.