Skip to content

Tutorials · Sound and Music · Chapter 10

Moods

50 minutes Uses: Music, AudioSource, AudioMix, Area, play_music, stop_music, stop_sound, position_of, nearest, position, node, in_group, move_node

By the end

  • A music asset, music/crypt.data: four Tracks, calm with an Intro, danger, found and caught, the last two playing once
  • Six Rules: calm and danger crossfade into each other, the sting and the found phrase cut in at once, and each hands back to calm at its end; and a Default Transition
  • The crypt’s level opening on the asset’s calm, and why the room’s own track and the alcove’s go
  • ghost.rgs asking for danger as the ghost comes within Near of him and for calm once it is beyond Far, and for the sting as it touches him
  • The music box, found, falling silent and playing its found phrase, once
  • Who plays the music now: the level and the scripts, by the asset’s track names, and the rules say how each change sounds
On this page

Four more pieces of music

Part 3 makes the music follow the game. Until now the crypt had one music, the calm, which a room’s track or a script started and stopped. Here it gets four more, made for the crypt and in the starter with the rest: crypt-danger.wav, the calm’s key and tempo made dark, a low pad throbbing under the tune in pieces, 24 seconds, as long as the calm; crypt-intro.wav, two bars, 6 seconds, that swell up into the calm’s first; found.wav, the music box found, 8.5 seconds with its ring; and caught.wav, the ghost’s catch, a falling run and a sagging chord, 1.5 seconds.

Leave all four on Auto, as they come: a music asset’s clips are held whole whatever Stream says.

A music asset

A music asset holds a level’s music as named tracks, and the rules for getting from one to another. The level plays it; a script asks for a track by its name, and the asset’s rule for the change says how it sounds: a cut, a crossfade, or a wait for the end of the playing track.

  1. In Assets, click Assets in the path bar, then choose Create → New folder, type music and press Enter: a folder at the project’s top.
  2. Click the music folder in the tree. Its row lights up and the path bar reads Assets / music: Create now writes into it.
  3. Choose Create → New data asset → Music. In the field under the bar, which reads music, the type’s name, type crypt over it and press Enter. music/crypt.data is written, and opens in the Inspector, which draws it in place of the selection: crypt.data, MusicGraph, with no tracks and no rules yet, and its own Revert and Save.
The Assets panel: Search, Filter, Details, Unreferenced, Create and Refresh in its bar; under it the path bar reading Assets / music; the tree with art, audio and fonts folded, music open and lit in copper with crypt.data under it, scenes folded, then alcove.rgs, bell.rgs, bridge.rgs and door.rgs
music clicked: the path bar reads Assets / music, and crypt.data is written in it.

Where Create writes is the folder last clicked in the tree, or the folder of the file last clicked, and the path bar names it. A click on a folder that is open also folds it, and it is still the one Create writes into. Assets, at the start of the path bar, is the project’s top again.

Each + on one of its lists adds a row that is a copy of the row above it, so a row is edited rather than started from nothing; the first + on an empty list, with no row above, adds one as a row comes.

Four tracks

  1. Press + beside Tracks: a track, 1, with Looping ticked, as a track comes. Type calm in its Name, drag crypt-calm.wav from Assets onto its Clip, and crypt-intro.wav onto its Intro.
  2. Press + beside Tracks again: 2, a copy of calm. Name it danger, drop crypt-danger.wav on its Clip, and clear its Intro: click the slot and pick (none), under the search box of the list it opens.
  3. Press + again: 3. Name it found, drop found.wav on its Clip, and untick Looping.
  4. Press + again: 4, a copy of found. Name it caught and drop caught.wav on its Clip. Press Save.
NameClipIntroLoopingWhy
calmcrypt-calm.wavcrypt-intro.wavtickedthe crypt opens on the intro, which runs into the loop; the name chapter 5’s alcove.rgs already asks for
dangercrypt-danger.wavnonetickedthe same length and key as calm
foundfound.wavnoneuntickeda phrase that resolves and stops: it plays once
caughtcaught.wavnoneuntickedthe sting: it plays once
The Inspector’s column, widened, drawing crypt.data, MusicGraph, with Revert and Save: Tracks, 4 items; 1 calm, Name calm, Clip crypt-calm.wav, Intro crypt-intro.wav, Layers no items, Looping ticked; 2 danger, Clip crypt-danger.wav, Intro (none), Looping ticked; 3 found, Clip found.wav, Intro (none), Looping unticked; 4 caught, Clip caught.wav, Intro (none), Looping unticked
The asset’s four Tracks, each read by its place and its name.
The music asset’s Tracks
The pieces of music the asset can play, a row each. One plays at a time; a level opens on one, and a script asks for another by its name. The Inspector reads each row by its place and its name, 1 calm.
A track’s Name
What play_music, a rule and a level’s Track call it by.
A track’s Clip
The sound the track plays, and loops while Looping is ticked. The ▶ beside it plays it, as beside every clip slot.
Intro
A clip the track plays once before its Clip, running straight into it with no gap: the intro’s last sample, then the loop’s first. It plays every time the track starts, not only the first. Empty for none: click the slot and pick (none) to empty it.
A track’s Looping
Ticked, the track plays until another takes its place. Unticked, it plays once and stops, and the music is silent after it unless something waits for its end, as a rule’s AtEnd below does.

Six rules

A rule says how the music gets from one track to another. A rule has no name, so it reads by its place; its From and To are track names, and an empty From means any track.

  1. Press + beside Rules: rule 1, which comes as a rule does, reading any to nothing, a CrossFade of 1 second. Type calm in its From and danger in its To, or pick each from the list beside it, and set its Seconds to 1.5.
  2. Press +: rule 2, a copy. Set From to danger, To to calm, and Seconds to 3.
  3. Press +: rule 3. Clear From, which then reads any; set To to caught and How to Immediate.
  4. Press +: rule 4. Set From to caught, To to calm and How to AtEnd.
  5. Press +: rule 5. Clear From; set To to found and How to Immediate.
  6. Press +: rule 6. Set From to found, To to calm and How to AtEnd.
  7. Set the Default Transition’s Seconds to 2, and leave the Playlist empty. Press Save.
FromToHowWhy
calmdangerCrossFade, 1.5 sthe threat arrives quickly; halfway, both are heard
dangercalmCrossFade, 3 sit eases off, slower than it came
(any)caughtImmediatethe sting cuts whatever plays
caughtcalmAtEndcalm comes back as the sting’s last sample ends
(any)foundImmediatethe phrase starts whole; a crossfade would fade in its first note
foundcalmAtEndcalm comes back where the phrase ends
The same asset further down: Rules, 6 items; 1, From calm, To danger, How CrossFade, Seconds 1.50 s; 2, From danger, To calm, How CrossFade, Seconds 3.00 s; 3, From any, greyed, To caught, How Immediate; 4, From caught, To calm, How AtEnd; 5, From any, To found, How Immediate; 6, From found, To calm, How AtEnd; Default Transition CrossFade, Seconds 2.00 s; Playlist with Clips no items, Shuffle unticked, Seed 0 and Position 0
The six Rules, the Default Transition and the empty Playlist.
The music asset’s Rules
How the music changes from one track to another, a row each. When a track is asked for, the rule whose From is the playing track and whose To is the one asked for decides; a rule whose From is empty stands for any track. With no rule for the pair, the Default Transition does.
A rule’s From
The track being left, by its name. Empty, it reads any, and the rule is for every track. The list beside it picks a name from the asset’s tracks.
A rule’s To
The track being asked for, by its name.
A rule’s How
Immediate cuts: the playing track stops and the new one starts, on the step it is asked for. CrossFade fades the playing track out as the new one comes in, over its Seconds. AtEnd lets the playing track reach the end of its pass, its loop or its one play, and starts the new one there, with no gap; the new track waits until then, and a track asked for in the meantime calls it off.
A CrossFade rule’s Seconds
How long the two tracks overlap, one fading out as the other comes in, from 0 to 30. The fade is straight in gain: halfway, each track is at half its own level.
Default Transition
The How for any change no rule names, with the same three choices. A new asset’s is a CrossFade of 1 second. No change the crypt makes in this chapter falls to it: the opening and the alcove start calm from no music, which a crossfade starts at once. Chapter 11 gives it a case.
The Default Transition’s Seconds
The overlap of the default crossfade: 2 here, set from the 1 it comes with.

The crypt’s level

  1. Click the Levels tab and click The Crypt row.
  2. Drag crypt.data from music in Assets onto the row’s Music button. A Track list appears beside it: pick calm.
  3. Leave the Title row’s Music as it is: the castle’s loop.
The Levels panel: Levels, 2 in order; 1 Title, scenes/title.ron, startup; 2 The Crypt, scenes/crypt.ron, selected, with Up, Down, Open, Play, Scene and Remove, a button reading Music: crypt.data and a list reading Track: calm; and Then open: (none)
The crypt’s level: its Music the asset, its Track calm.
A level’s Track, in the Levels panel
With a music asset as the level’s Music, the track the level opens on, picked from the asset’s tracks. A clip as the level’s Music has no Track.

What goes

The crypt’s music was the room’s own track, the looping Autoplay on Crypt, and the alcove played it again by its trigger calm. A level’s Music beats a room’s own track, and one music plays at a time, so with the level’s set neither would ever be heard. They go.

  1. Select Crypt, and remove its AudioSourceComponent with the bin icon at the right of its header.
  2. Select alcove, and remove its AudioSourceComponent the same way, its trigger calm with it. Its Alcove stays.
  3. Select mix. In Effects, Music, open slot 1, the Gain, and set it from -4 to -7 dB. Press Ctrl+S.

The ghost’s moods

The ghost decides the mood. Each step it reads how far the knight is: once he is within Near of it, it asks for danger; once he is beyond Far, for calm. Its touch asks for the sting before it sends him back to the hall.

  1. In Assets, double-click ghost.rgs. In the Code tab, replace everything in it with the script below, and press Ctrl+S.
  2. Select ghost: its Ghost now shows Near 64, Far 96 and Close. Leave them.
rgs ghost.rgs
/// The ghost, drifting its round through the flooded passage. Near the
/// knight it turns the crypt's music to danger, and once it is far from him
/// again, back to calm. A knight its Area touches is caught: the music cuts
/// to a sting, and he is sent back to where he started, in the entrance hall.
component Ghost : Area {
    /// Where a knight the ghost touches is sent back to: his start in the
    /// entrance hall.
    back_to: Vec2,
    /// How near the knight the ghost turns the music to danger.
    #[suffix("u")]
    near: f32 = 64.0,
    /// How far from him it turns the music back to calm. Farther than near,
    /// so a ghost drifting along the edge does not turn it back and forth.
    #[suffix("u")]
    far: f32 = 96.0,
    /// Whether it has turned the music to danger, or to the sting that waits
    /// for calm, so that it asks for each change once and not on every step.
    #[readonly]
    close: bool = false,

    fn loop() {
        let knight = nearest("knight");
        if knight != node(0) {
            let apart = position().distance(position_of(knight));
            // danger and calm are tracks of the crypt's music asset, the
            // level's Music: its rules say how one turns into the other.
            if !close && apart < near {
                play_music("danger");
                close = true;
            } else if close && apart > far {
                play_music("calm");
                close = false;
            }
        }
    }

    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            // The sting cuts in at once, whatever is playing.
            play_music("caught");
            // Still close: once he is far from the ghost, it asks for calm,
            // which waits for the sting's end.
            close = true;
            move_node(other, back_to);
        }
    }
}
The Inspector narrowed to ghost, on the ghost: its Ghost component with Back To x 120.0, y 112.0, Near 64.00 u, Far 96.00 u, and Close unticked and dimmed
The ghost’s script: Near, Far, and Close, which the game writes.
play_music, by a track’s name
With a music asset as the level’s Music, a name that is one of its tracks asks for that track, and the asset’s rule for the change says how it comes in. Asking for the track already playing leaves it playing. A name the asset does not have plays a trigger of that name on the script’s own node, as chapter 5’s did.
nearest and position_of
nearest("knight") is the nearest other node in the group knight, or node(0), nobody, when there is none; position_of is where a node stood as the step began. With the ghost’s own position(), .distance(...) is how far apart they are.
Near and Far, the ghost’s
How near the knight turns the music to danger, and how far from him it turns back to calm, in world units, u. Far is farther than Near, so a ghost drifting along the edge of Near does not turn the music back and forth.
Close, the ghost’s
Whether it has asked for danger, or for the sting, so that it asks for each change once. #[readonly] shows it and keeps it out of your hands: the script writes it.

alcove.rgs is the same code. Only its comments change, to say that calm is now the asset’s track, and that asked for while the found phrase plays, it waits for the phrase’s end. Replace it too:

rgs alcove.rgs
/// The alcove at the end of the crypt, where the music box plays. As the
/// knight comes in, the crypt's music stops, and the box is heard alone. As he
/// leaves, the crypt's music comes back.
component Alcove : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            stop_music();
        }
    }

    fn on_exit(other: NodeId) {
        if in_group(other, "knight") {
            // calm is a track of the crypt's music asset, the level's Music.
            // Asked for while the box's found phrase plays, it waits for the
            // phrase's end.
            play_music("calm");
        }
    }
}

The box, found

When he reaches the music box, its tune falls silent and the music plays the found phrase, once.

  1. Select music_box. Press Add component and choose AreaComponent. In its Shape, set Size to 32, 32 and Offset to 0, 16: the floor in front of the box.
  2. In Assets, click Assets in the path bar, so the script is written at the project’s top, then click Create, choose New script, type music_box and press Enter. Replace everything in music_box.rgs with the script below, and press Ctrl+S.
  3. Select music_box, press Add component and choose MusicBox. Press Ctrl+S.
rgs music_box.rgs
/// The music box, at the end of the crypt. Its tune leads the knight to it.
/// Once he reaches it, it falls silent, and the crypt's music plays its found
/// phrase, once.
component MusicBox : Area {
    /// Whether he has reached it, so that it is found once.
    #[readonly]
    found: bool = false,

    fn on_enter(other: NodeId) {
        if in_group(other, "knight") && !found {
            // Its tune, its own Audio Source's Autoplay, stops.
            stop_sound();
            // A track of the crypt's music asset, whose Looping is unticked:
            // it plays once and stops.
            play_music("found");
            found = true;
        }
    }
}

Heard

Press Run game and Play, or F5 on the crypt with the Sound tab open. The crypt opens on calm, and calm on its intro.

He stands in the gate room, where nothing in the crypt is heard but the music, from the moment the crypt opens. Listen for the intro rising out of silence over its first two seconds; then, six seconds in, the calm’s first bar following the intro’s last with no gap, and the calm going on.
What it sounds like

Out of silence a soft pad swells up over about two seconds, with a few music-box notes; at six seconds it runs on without a break into the crypt’s gentle music-box melody over the pad.

Then walk through the cave into the flooded passage, to the middle of the ghost’s round, where the route turns down to the bell chamber, and wait for the ghost.

He stands in the cave by the passage’s arch while the crypt’s music begins, then walks into the middle of the ghost’s round; the music goes duller as he steps into the passage. Listen at about seven seconds, as the ghost comes near: over a second and a half the calm fades out as the dark danger music comes in, both heard halfway, and danger plays on while the ghost circles him.
What it sounds like

The soft intro and the gentle music-box melody, footsteps; the music turns muffled; then it changes over a second and a half into darker, louder music with a low throbbing pad and the tune in pieces, which plays on.

The editor 7.9 seconds into Play, the knight in the middle of the ghost’s round and the ghost, selected, just south of him in the Viewport, its rings round it; the Sound tab: Master, Music and Sfx meters moving; Music: Track danger, Fading out calm, crossfade 47%, danger playing, gain 0.47, calm fading out, gain 0.53; Mix held by the zone the listener is in, "passage"; Voices (9): two on Music, crypt-calm.wav at -5.5 dB and crypt-danger.wav at -6.6 dB, the water at -4.4 dB and the rest silent; the Inspector shows the ghost’s script, Close ticked
The turn to danger in the Sound tab, part way through: danger coming in, calm fading out, each at its share.
The Sound tab’s Music band, with a music asset
Track is the track playing, or coming in. Fading out names the track a crossfade takes out, and how far through the fade is. A row for each track sounding says where it is, playing, fading out, or waiting to take over at the end of the pass, and its gain. Next names a track waiting for the end of this pass, as an AtEnd does. In Voices, a music voice is Heard at its share of the crossfade, the gain above, and not at how loud its music is: part way in, as in the picture, calm’s row still reads over danger’s, while danger, the louder music, is heard over calm.
The game at the same moment: the knight in the middle of the flooded passage, lit by his lantern, the pale ghost just below him and to his right on the water, the arch to the cave on the left
The same moment in the game: the ghost within Near of him.

The ghost goes round him and never gets beyond Far of him there, so the music stays dark. Walk back west, away from it: once it is beyond Far, it asks for calm, and danger eases out over three seconds, calm coming in from its intro. Chapter 11’s first clip has the same ease back to calm, by then from calm’s tune rather than its intro.

From the crypt’s opening he stands on the ghost’s round, by its north-east corner. Listen for the opening music turning dark as the ghost comes round the corner; at about four seconds it touches him: the sting cuts in at once, he is back in the hall by the torches, and as the sting ends the music starts again from its intro, swelling up out of silence over a couple of seconds.
What it sounds like

Water lapping, and a soft swell under it that turns into darker music with a throbbing pad; a falling run on a music box and a low chord that sags; a fire crackling, and out of silence the soft pad swells up again.

By the lever: E, the gate grinds open, and he walks up into the alcove to the box. Listen for the crypt’s music stopping at the alcove’s doorway and the box’s tune heard alone for a moment; as he reaches the box, its tune stops and the found phrase plays, once, and rings away: nothing follows it while he stands there.
What it sounds like

The soft intro, a metal clank, a rising grind and a thud, steps; the music cuts off and a music-box tune is heard alone; then it stops, and a music box falls to a note and climbs a bright chord to a high note that rings and fades to silence.

The Problems tab with seven warnings: four on torch_left, the music asset music/crypt.data’s rules from calm to danger, from danger to calm, from caught to calm and from found to calm never apply, there being no track called calm; a fifth on torch_left, Level The Crypt opens silent, its Music having no track called calm; and one each on alcove and ghost, play_music("calm") played nothing: no music asset has a track called calm
The Problems tab with the track calm renamed: every rule, the level and both scripts that name it.

A track’s name is what everything else calls it by, so the Problems tab follows every name. The asset’s rows and the level’s are the project’s, not a node’s, so each sits on the first node in the Hierarchy with sound of its own, torch_left; a script’s row sits on the node whose script asks. With no Problems row, every name a script asks for is a track of the asset, every rule’s From and To is one, and so is the level’s Track.

Who decides what you hear

The moods

NodeComponentFieldValue
music/crypt.dataMusicTrackscalm (crypt-calm.wav, Intro crypt-intro.wav), danger (crypt-danger.wav), found (found.wav, Looping unticked), caught (caught.wav, Looping unticked)
Rulescalm → danger CrossFade 1.5; danger → calm CrossFade 3; any → caught Immediate; caught → calm AtEnd; any → found Immediate; found → calm AtEnd
Default TransitionCrossFade, 2
The Crypt, in Levelsthe levelMusic, Trackmusic/crypt.data, calm
CryptAudio Sourceremoved
alcoveAudio Sourceremoved
Alcovealcove.rgs, its comments
mixAudio MixMusic slot 1, Gain-7 dB
ghostGhostghost.rgs, rewritten: Near 64, Far 96, Close
music_boxAreaShape Size, Offset32, 32; 0, 16
MusicBoxmusic_box.rgs

Check it works