Skip to content

Tutorials · Sound and Music · Chapter 12

A gallery of sound

120 minutes Uses: Music, AudioSource, AudioMix, AudioZone, AudioListener, Area, Collider, Sprite, Shape, WorldText, Timeline, TileMap, Confiner, Button, Focus, play_music, stop_music, play_sound, set_mix, clear_mix, wait, pulse_number, play_cutscene, change_scene, pressed, in_group

By the end

  • A third button on the title, Gallery, and two levels after the crypt, each a scene of its own: the gallery and the jukebox’s room
  • A radio heard through a wall: a zone whose snapshot ticks a HighPass and a BandPass on Sfx
  • A ghost’s whisper through a script’s mix that ticks a Distortion, and lets go
  • A machine whose hum’s Pitch and Volume wind up and down for ever, with pulse_number
  • A fanfare that hands over to calm at its end, an AtEnd in the gallery’s own music asset
  • A short cutscene whose audio cues play its music, a bow, and stop the music
  • A bell carried across the rooms by a Custom rolloff, every field of its curve set, and a Blend that keeps a tenth of it beyond its reach
  • His steps on boards, each take once a round: Shuffle
  • A jukebox of four songs in a Playlist, shuffled from a Seed, leaning to its side under a Panner on Music, and ducking under the innkeeper’s line
On this page

Two scenes beside the crypt

The crypt is finished. This chapter leaves it as chapter 11 left it, and adds two scenes beside it, scenes/gallery.ron and scenes/jukebox.ron. Each case in them is a small thing you know, a radio, a whisper, a machine, a chest, a show, a bell, a jukebox, and each sets something the crypt leaves as it comes, so that by the end you have used every sound control there is. The title gets a third button, Gallery; Escape in either scene goes back to the title.

The whole gallery in the editor at 104.5%: a band of eight boarded rooms in a row under a grey stone wall, each with a dark sign in its north wall, Radio, Through the wall, Jukebox, Fanfare, Theatre, Whisper, Machine and Far bell; an arch through every wall between them; in the rooms, from the west, a radio, a table and a stool, the knight under a door with a banner either side, a chest, a stone bench with a banner either side, a pale ghost, a machine and a golden bell
The gallery, west to east: eight rooms, each a case, each with its sign.

The gallery’s sounds come from two downloads: the radio’s song, Heavy Boss Battle 1, and five of Kenney’s Music Jingles, the chest’s fanfare and the jukebox’s four songs; and five steps on boards, from Impact Sounds, which chapter 3 had you download. Two of the starter’s made sounds come in too: whisper.wav, a ghost’s breathy whisper, 2.6 seconds, and voice.wav, a line of dialogue with no words, 2.15 seconds.

  1. Download Heavy Boss Battle 1 and Music Jingles from their pages below. Copy the files the list names into your project’s audio folder, each from where it says, the five steps on boards from Impact Sounds with them, and press Refresh in the Assets panel.
  2. Leave them all on Auto, as they come: the song is long and streams, and each jingle and step is short and is held whole.

Nine pictures from the sheet

The gallery’s things are cut from Tiny Dungeon’s sheet, as chapter 4 cut the shut door.

  1. In Assets, double-click art/tilemap_packed.png. In the Sprite sheet tab’s Grid band, set Cell to 16 by 16.
  2. For each row of the table below, click its cell on the sheet, or drag across the cells for one bigger than a cell, type its name into Name in the Regions band, and press Name it.
Regionx, ySizeWhat it is
radio96, 6416 × 16the radio
machine112, 6416 × 16the machine
jukebox48, 8016 × 32, two cells downthe jukebox
chest80, 11216 × 16the chest
performer0, 11216 × 16the performer
innkeeper32, 11216 × 16the innkeeper
table0, 9616 × 16the listening room’s table
stool16, 9616 × 16its stool
dais0, 4848 × 16, three cells acrossthe stone bench the performer stands on

A third button

  1. Open scenes/title.ron. Select options, under title_menu, and press Ctrl+D: a copy under it. Rename it gallery.
  2. In its Text, set Text to Gallery. In its Button, set Action to gallery.
  3. In its Focus, set Up and Previous to options, and Down and Next to play. Select play and set its Up and Previous to gallery; select options and set its Down and Next to gallery. The three are a ring.
  4. Select title_frame and set its Rect’s Offset Max y from 480 to 541: 61 taller, a button and its gap.
  5. Double-click title_menu.rgs and replace everything in it with the script below. Press Ctrl+S.
rgs title_menu.rgs
/// The title's menu: Play opens the crypt, Gallery opens the gallery of sound,
/// and Options swaps this menu for the options panel, whose Back swaps it
/// back. A press clicks, and a move of the focus round the menu blips: the
/// triggers of this node's Audio Source.
component TitleMenu {
    /// Whether the menu is showing, so that it blips for its own focus moves
    /// and not for the options panel's.
    #[hidden]
    shown: bool = true,

    fn loop() {
        // A click on Play, Gallery or Options, or Enter or Space while it
        // holds the focus, presses its action on the game's next step. A
        // sound asked for on the step that changes scene plays on after it.
        if pressed("play") {
            play_sound("click");
            change_scene("crypt");
        }
        if pressed("gallery") {
            play_sound("click");
            change_scene("gallery");
        }
        if pressed("options") {
            play_sound("click");
            hide();
            shown = false;
        }
        // A click on the options panel's Back, Enter or Space while it holds
        // the focus, or Escape through its Shortcut.
        if pressed("back") {
            show();
            shown = true;
        }
        // W or S, or the Up and Down arrows, move the focus round the menu.
        if shown && (pressed("ui_up") || pressed("ui_down")) {
            play_sound("select");
        }
    }
}
The game’s title: The Music Box in orange letters, and under it a brown panel with three beige buttons, Play, Options and Gallery
The title with its third button.

The gallery is 1296 by 192: one band of eight rooms, west to east, each a floor nine cells square, from y 32 to 176, with an arch two rows tall, y 96 to 128, through each wall between them. Each room is a Node at its middle, and everything in it is its child.

  1. Click the Levels tab. Type Gallery into the box in the panel’s bar and press Add level. The new row names a scene for it, scenes/gallery.ron, and warns that the file does not exist. Press Create scene under the warning: the editor writes an empty gallery.ron and opens it.
  2. Click + Add node and choose Node. Rename it Gallery.
  3. Select Gallery, click + Add node and choose Camera Confiner. Rename it confiner, set its Position to 648, 96, the gallery’s middle, and its Bounds to 1296, 192. Until the camera arrives with the knight, confiner carries a warning, and Problems reads “This Confiner works on the active camera and this scene has no active Camera”: leave it.
  4. Select Gallery, click + Add node and choose Tilemap. Rename it stone, and set its Sort Layer to -3, as the crypt’s stone has it: under the rooms’ boards, which come below on -2.
  5. With stone selected, open the Tilemap tab beside the Inspector. Drag art/tilemap_packed.png from Assets onto New tilemap…. The editor writes a new tilemap beside the sheet, art/tilemap_packed.tilemap, and points stone at it; the status line at the foot of the window names the file. Its Tileset fold reads the sheet as it is: tiles 16 by 16, 12 columns, no Margin.
  6. Before you change anything in it, rename it: in Assets, right-click the new file, choose Rename, and type gallery.tilemap. stone still shows it.
  7. In the Layers fold, the new tilemap has two layers, back and ground. Double-click back: its name turns into a box, the name selected. Type floor and press Enter. Rename ground walls the same way. walls, the second layer, is the solid one as it comes: the gear button at the end of its row reads SN, Solid and Blocks nav, and a click on it shows the two ticked. floor’s gear reads nothing.
  8. Click walls, then the + under the rows, which adds an empty layer over the selected one: layer 1, after walls. Rename it decoration. Its gear reads nothing: it stops nobody.
  9. Under Tools, click Rect. Choosing a tool turns on Paint mode at the top of the tab: a drag in the Viewport now paints, and selects nothing.
  10. Paint the table below, a layer at a time: click the layer’s name first, so it is the one you paint on. For each tile the table names, hover the tiles in the picker at the tab’s foot until the tooltip reads its number, #41 for the wall’s face, and click it: the Tile line over the picker shows it. Then drag over the cells it covers, from inside the first to inside the last: both corner cells are painted. Columns count from 0 at x 0 and rows from 0 at y 0, a cell every 16; the cursor row under the Viewport reads where the pointer is.
  11. Press the tab’s Save, which writes the tilemap, and Ctrl+S for the scene. Physics and Mechanisms paints a gallery tile by tile too, if you want the tab at more length.
The editor with gallery.ron open and stone selected and framed, the Tilemap tab open on the right: Paint mode and Save at its top; its Tools fold with Brush, Erase, Line, Rect, Fill, Pick, Stamp and Move; its Layers fold, 3 layers, floor highlighted, walls with its gear reading SN, and decoration, each at z 0, with the add, remove, raise and lower buttons under them; its Tileset fold with Sheet tilemap_packed.png, Tile w 16 h 16, Columns 12, Margin x 0 y 0, Spacing x 0 y 0, Sheet 192x176, 132 tiles, 11 rows, and the sheet drawn under it. The Viewport shows the gallery painted, eight boarded rooms in a band
The gallery’s tilemap in the Tilemap tab: its three layers, floor, walls, solid, and decoration.
LayerRowsColumnsTiles, by the picker’s number
walls00 to 80#1 in every tenth column, 0, 10 … 80, and the wall’s top, #3, between
10 to 80#1 in every tenth column, and the wall’s face, #41, between
2 to 4, 9 and 100, 10 … 80#1
50 and 80; 10 … 70#1 at the two ends; #41 over each arch
6 and 70 and 80#1: the arches are open
80 and 80; 10 … 70#1 at the two ends; #27 under each arch
110 to 80#1 in every tenth column, and the wall’s foot, #27, between
floor2each room’s 9#51, the floor under the wall
3 to 10, and the arches’ 6 and 7each room’s 9, and 10 … 70#49, the plain floor, or #50, the same with a few pebbles, in any cells you like; #51 under each arch, on row 6
decoration121, 29, 43, 47the banner, #30, either side of the foyer’s door and the theatre’s sign
  1. For each room of the table below, select Gallery, add a Node with its name at its Position, and under it a Sprite, <room>_boards: Texture art/planks.png, Atlas Region deck, Draw Mode Tiled, Size 144, 144, Tile Size 16, 16, Sort Layer -2.
  2. Copy knight from crypt.ron, his camera under him, and paste him under Gallery at the foyer’s start, 392, 120. His lantern comes with him: select it and delete it. The gallery has no lights, and one would make it a lit scene, dark but for the circle round him.
  3. Make leave.rgs with the script below: in Assets, click Assets in the path bar, then Create → New script, type leave and press Enter. Every script this chapter makes is made so, at the project’s top beside the others. Select Gallery, press Add component and choose Leave.
Room (node)PositionHoldsIts sign says
radio_room88, 104radioRadio
listening_room248, 104listening_zone; table at -64, -48 and stool at -48, -40, against the radio room’s wallThrough the wall
foyer408, 104jukebox_door; the knight’s startJukebox, left of the door
treasury568, 104chestFanfare
theatre728, 104stage, performer, daisTheatre
haunted_room888, 104ghostWhisper
machine_room1048, 104machineMachine
belfry1208, 104bellFar bell
rgs leave.rgs
/// Escape, which the input map calls pause, leaves the gallery for the title.
/// It sits on the root of each of the gallery's two scenes.
component Leave {
    fn loop() {
        if pressed("pause") {
            change_scene("title");
        }
    }
}

So a visitor can tell the rooms apart, each has a sign in its north wall, <room>_sign, 80 above the room’s middle; the foyer’s is 32 west of it, left of the door.

  1. Select a room, click + Add node and choose Shape. Rename it <room>_sign and set its Position to 0, -80. Set its Kind to Rectangle, its Size to the sign’s width by 12, its Color to the pack’s navy, 38, 43, 68, its Outline to 1 in the pack’s dark outline, 63, 38, 49, and its Sort Layer to 0.
  2. On the same node, press Add component and choose WorldTextComponent: Text the room’s sign, Scale 0.25, Color the pack’s beige, 236, 227, 206, Offset 0, 0, Pixel Size unticked, Sort Layer 1, Outline Width 0.
  3. The width is the words’ and 4 either side: 30 for Radio, 78 for Through the wall, 42 for the rest.

A World Text draws in the project’s font, Kenney Mini, here at 32 px; at Scale 0.25 its letters sit on the art’s own pixel grid. Pixel Size off makes the sign part of the wall, its size the room’s. table, stool and dais are Sprites of their regions with no Collider: they are to be seen and walked past. Every Sprite this chapter puts in a room, table and stool here, and the radio, the chest, the performer, the machine, the bell, the foyer’s door and the jukebox’s room’s own, goes on Sort Layer 1, over the boards; the ghost on 2, as the knight is, and the dais on -1, under the performer.

The gallery has a music asset of its own, music/gallery.data, made as the crypt’s was: a fanfare that plays once, and calm. It opens on the fanfare, and nothing follows it: the gallery is quiet, so each case is heard clean. Only the chest plays the fanfare again, and then calm.

  1. In Assets, click the music folder, so the path bar reads Assets / music. Choose Create → New data asset → Music, type gallery over the name and press Enter: music/gallery.data, made as chapter 10 made crypt.data, and open in the Inspector.
  2. Its Tracks: fanfare, Clip jingles_STEEL05.ogg, Looping unticked; and calm, Clip crypt-calm.wav, Looping ticked.
  3. Its Rules: (any) to fanfare, Immediate; and fanfare to calm, AtEnd. Leave the Default Transition as it comes, a CrossFade of 1 second, and the Playlist empty. Press Save.
  4. In the Levels tab, on the Gallery row, drop gallery.data on Music and pick fanfare in Track.
The Inspector drawing gallery.data, MusicGraph: Tracks, 2 items; 1 fanfare, Clip jingles_STEEL05.ogg, Intro (none), Layers no items, Looping unticked; 2 calm, Clip crypt-calm.wav, Intro (none), Looping ticked; Rules, 2 items; 1, From any, To fanfare, How Immediate; 2, From fanfare, To calm, How AtEnd; Default Transition CrossFade, Seconds 1.00 s; Playlist with no clips, Shuffle unticked, Seed 0, Position 0
The gallery’s music: a fanfare once, and calm.
The Levels panel: Levels, 3 in order; 1 Title, startup; 2 The Crypt; 3 Gallery, scenes/gallery.ron, selected, with its buttons, Music: gallery.data and Track: fanfare; and Then open: (none)
Three levels now: the Gallery’s Music and Track. The jukebox’s room adds the fourth.

The gallery has a mix of its own, mix, under its root, with the safety on Master the crypt has, and three slots on Sfx, each unticked, for two of the cases: a HighPass and a BandPass for the radio, a Distortion for the whisper. Music has no slots.

  1. Select Gallery, click + Add node and choose Audio Mix. Rename it mix, give it the slots of the table below, each set as chapter 6’s and chapter 7’s were, and the two snapshots after it, each made as chapter 7’s were: + beside Snapshots, its Name, a press of + beside Master’s Effects and three beside Sfx’s, and then the switches ticked as it says. Press Ctrl+S.
BusSlotEffectValuesEnabled
Master1CompressorThreshold -1 dB, Ratio 20, Attack 0, Release 0.1 sticked
Sfx1HighPassCutoff 400 Hz, Resonance 0.707unticked
2BandPassCutoff 1200 Hz, Resonance 1.0unticked
3DistortionDrive 12, Mix 0.7unticked
The Inspector narrowed to audio, on the gallery’s mix: Effects; Master with one slot, Compressor; Music with no slots; Sfx with three slots open, 1 HighPass, Cutoff 400 Hz, Resonance 0.707, Enabled unticked; 2 BandPass, Cutoff 1200 Hz, Resonance 1.00, Enabled unticked; 3 Distortion, Drive 12.0, Mix 0.700, Enabled unticked; Snapshots, 2 items, through_wall and haunted; Ducking and Sends with no items
The gallery’s mix: Sfx’s three slots, each unticked.
A BandPass’s Cutoff
The middle of the band it lets through, in hertz: here 1200. Below it and above it, the sound falls away.
A BandPass’s Resonance
How narrow the band is: higher is narrower, at the same level in its middle. 1 here.
A Distortion’s Drive
How hard the sound is pushed into the clipper that flattens its peaks: higher is rougher. A quiet sound comes out louder as well as rougher, as the whisper does below.
A Distortion’s Mix
How much of what comes out is clipped rather than the sound as it came, from 0, none, to 1, all of it: here 0.7.

Two snapshots, each with every Volume 1 and no Send Amounts: through_wall, Master on, Sfx on, on, off; and haunted, Master on, Sfx off, off, on.

A radio through the wall

A song plays on a radio in the radio room. Next door, through the wall, it sounds thin, a radio’s band; in its own room, whole.

  1. Under radio_room, add a Sprite, radio, at 0, -48 (the world’s 88, 56), of the region radio, with a Collider 14 by 12, Offset 0, 2.
  2. Press Add component and choose AudioSourceComponent: Clip heavy_boss_battle_1_bpm200_0.ogg, Bus Sfx, Volume 0.8, Looping, Autoplay and Positional ticked; Max Distance 256, Rolloff Linear, Min Distance 16.
  3. Under listening_room, click + Add node and choose Audio Zone. Rename it listening_zone; set its Area’s Size to 144, 144, the room’s floor, and its Snapshot to through_wall. Leave Fade 0.5 and Priority 0, as they come.
The Inspector narrowed to audio, on radio: AudioSourceComponent with Clip heavy_boss_battle_1_bpm200_0.ogg, Bus Sfx, Volume 0.800, Pitch 1.00, Looping and Autoplay ticked, Spatial with Positional ticked, Max Distance 256.00, Blend 1.000, Rolloff Linear, Min Distance 16.00, Pan 0.000, Max Voices 0 and Triggers with no items
The radio: a song in the room, on Sfx, gone at 256.
The Inspector narrowed to audio, on listening_zone: AudioZoneComponent with Snapshot through_wall, Fade 0.50 s and Priority 0
The listening room’s zone.
The gallery’s mix with Effects shut and the snapshot 1 through_wall open: Name through_wall; Master, Volume 1.000, Effects 1 Compressor ticked; Music, Volume 1.000, no effects; Sfx, Volume 1.000, Effects 1 HighPass ticked, 2 BandPass ticked, 3 Distortion unticked; Send Amounts no items; 2 haunted shut
through_wall: the HighPass and the BandPass on.
FieldValueWhy
Clipheavy_boss_battle_1_bpm200_0.ogga song in the next room
BusSfxa sound in the room, as the music box is; and the chain the snapshot ticks is Sfx’s
Volume0.8with the BandPass’s Resonance at 1, it keeps the thinned song audible through the wall
Max Distance, Rolloff, Min Distance256, Linear, 16gone at a known distance, short of the foyer
From the foyer he walks west into the listening room, stands, and walks on through the arch into the radio room. Listen for the gallery’s short fanfare as it opens, then nothing of the radio in the foyer; in the listening room, the song coming through the wall thin and small, a radio’s band with no bass, and his steps thinned too; in the radio room, the song whole and loud.
What it sounds like

A short bright steel-drum fanfare and a faint bell’s toll; footsteps on wooden boards; a thin, tinny rock song with no bass, quiet, as if from a small speaker next door; more footsteps, and the song is suddenly full and loud, drums and bass and all.

The game in the listening room: the knight on the boards, a small table and a stool against the west wall, the sign Through the wall above, and through the arch on the left the radio room, its radio on the north wall
The listening room, the radio beyond the wall.
The editor two seconds into Play with the knight in the listening room; the Sound tab: Music, No music, Track fanfare, not sounding; Mix held by the zone the listener is in, "through_wall", Now On "through_wall"; Voices (3): bell at -28.0 dB, machine silent, radio at -11.1 dB; the Inspector shows listening_zone’s Audio Zone
In the listening room: the zone holds the mix at through_wall.

A ghost’s whisper

A ghost haunts the room east of the theatre. Walked into, it whispers, and while it whispers the whole of Sfx turns rough: a script’s mix.

  1. Under haunted_room, add a Sprite, ghost, at 0, -48, of the region ghost, its Color alpha 0.8. Add an AreaComponent, Size 144, 144, Offset 0, 48: the room’s floor.
  2. Add an AudioSourceComponent: no Clip, Bus Sfx, Volume 1, Positional ticked, Max Distance 160, Rolloff Quadratic, Min Distance 32; and a trigger whisper, its Clip whisper.wav.
  3. Make haunt.rgs with the script below, and add Haunt to ghost. Leave its Haunting at 3 s.
rgs haunt.rgs
/// The ghost in the haunted room. As the knight comes in, it whispers, and
/// while it whispers the gallery's mix is haunted: that snapshot's Distortion
/// roughens everything on Sfx, the whisper, his steps and the bell far off.
/// Then it lets the mix go, back to the room's own.
component Haunt : Area {
    /// How long the mix stays haunted: the whisper's 2.6 s and a little more.
    #[suffix("s")]
    haunting: f32 = 3.0,

    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            // The mix holds haunted, whatever zone he is in, until the
            // script lets it go.
            set_mix("haunted", 0.25);
            play_sound("whisper");
            await wait(haunting);
            clear_mix(1.0);
        }
    }
}
The Inspector narrowed to audio, on the gallery’s ghost: AudioSourceComponent with Clip (none), Bus Sfx, Volume 1.000, Positional ticked, Max Distance 160.00, Blend 1.000, Rolloff Quadratic, Min Distance 32.00, Pan 0.000, Max Voices 0; Triggers, 1 item, 1 whisper open: Name whisper, Clip whisper.wav, Clips no items, Mode Shuffle, Pitch and Volume each Min 1.00 and Max 1.00
The ghost’s Audio Source: no sound of its own, and whisper.
The gallery’s mix with Effects shut and the snapshot 2 haunted open: Name haunted; Master, Volume 1.000, Compressor ticked; Music, Volume 1.000, no effects; Sfx, Volume 1.000, Effects 1 HighPass unticked, 2 BandPass unticked, 3 Distortion ticked; Send Amounts no items
haunted: the Distortion on.
This clip is loud, much louder than the crypt’s: turn your volume down before you play it. In the haunted room from the gallery’s opening, the short fanfare playing as the room opens. Listen for the whisper rough and loud, and the bell’s ring roughened under it; three seconds in the ghost lets the mix go, and a second later the ring is clean again.
What it sounds like

A short steel-drum fanfare; a harsh, buzzing, breathy whisper over a bell’s ring; then the ring rings on clean.

The same from a copy whose haunted leaves the Distortion unticked: listen for the whisper soft and clean, the difference the Distortion makes.
What it sounds like

The same short fanfare; a soft, breathy whisper over a bell’s ring; the ring rings on.

The game in the haunted room: the pale ghost under the sign Whisper on the north wall, the knight below it on the boards
The haunted room.
The editor a second into Play in the haunted room; the Sound tab: Master and Sfx meters loud, Music silent; Music, No music, Track fanfare, not sounding; Mix held by A script’s set_mix, "haunted", Now On "haunted"; Voices (4): bell at -13.6 dB, ghost whisper.wav at -5.0 dB, machine and radio silent; the Inspector shows the ghost’s Audio Source
While it whispers: the mix is the script’s, haunted.

A machine that winds up and down

A machine hums, winding up and down for ever: louder and faster, then quieter and slower. Its hum is the gate’s grind, chapter 4’s, set low and slow; a script pulses its Pitch and Volume while it plays.

  1. Under machine_room, add a Sprite, machine, at 0, -48, of the region machine, with a Collider 14 by 12, Offset 0, 2.
  2. Add an AudioSourceComponent: Clip gate-grind.wav, Bus Sfx, Volume 0.2, Pitch 0.6, Looping, Autoplay and Positional ticked; Max Distance 160, Rolloff Quadratic, Min Distance 32.
  3. Make machine.rgs with the script below, and add Machine to machine, leaving its fields as they come.
rgs machine.rgs
/// The machine in the machine room. Its hum is its Audio Source's own loop,
/// set low and slow; this winds it up and down for ever, its Pitch up to
/// wound and back and its Volume up to roar and back, each over winding
/// seconds, so it speeds up as it grows louder.
component Machine {
    /// How fast it runs wound up, as a Pitch.
    wound: f32 = 1.6,
    /// How loud it is wound up, as a Volume.
    roar: f32 = 0.6,
    /// How long it takes to wind up, and again to wind down.
    #[suffix("s")]
    winding: f32 = 3.0,

    fn on_create() {
        pulse_number("AudioSourceComponent", "pitch", wound, winding, .InOutSine);
        pulse_number("AudioSourceComponent", "volume", roar, winding, .InOutSine);
    }
}
The Inspector on machine, from its AudioSourceComponent, Clip gate-grind.wav, Bus Sfx, Volume 0.200, Pitch 0.60, Looping and Autoplay ticked, Positional ticked, Max Distance 160.00, Blend 1.000, Rolloff Quadratic, Min Distance 32.00, through its ColliderComponent, to its Machine component: Wound 1.60, Roar 0.60, Winding 3.00 s
The machine’s hum, set low and slow, and Machine’s three fields.
pulse_number
Anneals a number field of a component on the script’s own node to a value and back, over its seconds each way, on its curve, for ever. Two of them run side by side here, the Audio Source’s pitch to Wound and its volume to Roar, each over Winding seconds on an InOutSine curve, so the hum speeds up as it grows louder. A playing sound hears its Pitch and Volume change as they change; chapter 4’s gate wound its Pitch once, with anneal_number.
Wound, Roar and Winding, the machine’s
How high the Pitch winds, 1.6; how loud the Volume grows, 0.6; and the seconds it takes each way, 3.
By the machine, from the gallery’s opening, twelve seconds. Listen for its hum speeding up and growing louder over three seconds, then slowing and quietening over three, and again; the bell in the next room tolls every six.
What it sounds like

A short fanfare and a bell’s toll; a low mechanical hum rises in pitch and loudness, falls back, rises and falls again, while the bell tolls and rings away.

The game in the machine room: the machine on the north wall under the sign Machine, the knight in front of it on the boards
The machine room.

A fanfare handed over

A chest in the treasury plays the gallery’s fanfare as he walks up to it, and calm takes over at the fanfare’s end, with no gap: the asset’s AtEnd, heard.

  1. Under treasury, add a Sprite, chest, at 0, -48, of the region chest, with a Collider 14 by 10, Offset 0, 3, and an AreaComponent 32 by 32, Offset 0, 24: the floor in front of it.
  2. Make chest.rgs with the script below, and add Chest to chest.
rgs chest.rgs
/// The chest in the treasury. Walked up to, it plays the gallery's fanfare,
/// once, and calm takes over as the fanfare ends, with no gap between them.
/// Walking away stops the music.
component Chest : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            // A track of the gallery's music asset, its Looping unticked: it
            // plays once. The rule to it from any track is Immediate.
            play_music("fanfare");
            // Asked at once, calm waits: the rule from the fanfare to calm is
            // At End, so calm comes in as the fanfare's one pass ends.
            play_music("calm");
        }
    }

    fn on_exit(other: NodeId) {
        if in_group(other, "knight") {
            stop_music();
        }
    }
}
The game in the treasury: the knight in front of the chest on the north wall under the sign Fanfare
At the chest.
The gallery opens on its fanfare; he walks east, his steps on the boards, and two seconds in, up to the chest. Listen for the fanfare again, once, and, as its last note rings, calm coming in with no gap between them.
What it sounds like

A short bright steel-drum fanfare; footsteps on boards; the fanfare again, and straight out of its last note a gentle music-box melody over a soft pad.

The editor in Play as the knight reaches the chest; the Sound tab: Music: Track fanfare; Next calm, when this pass ends; fanfare playing, gain 1.00; calm waiting to take over, gain 1.00; Mix held by the room’s default; Voices (5), among them music jingles_STEEL05.ogg at 0.0 dB and music crypt-calm.wav, starts in 0.3 s
The fanfare playing, and calm waiting for its end.

A short cutscene with audio cues

A show in the theatre: walked into, it plays its music, a performer appears, bows to a fanfare, and goes, and the music stops. Its cues are a cutscene’s, made in the Cutscene tab as Animation and Cutscenes teaches it.

  1. Under theatre, add dais, a Sprite of the region dais at 0, -42 on Sort Layer -1, and performer, a Sprite of the region performer at 0, -48, with Visible unticked.
  2. Select theatre, click + Add node and choose Cutscene. Rename it stage and set its Position to 0, -56.
  3. With stage selected, open the Cutscene tab and press New cutscene: it writes scenes/stage.timeline, beside the scene, named after the node, and points Timeline at it.
  4. Type 4.5 into the length box beside its name, in the tab’s bar: the show is 4.5 seconds long.
  5. Add an AudioSourceComponent: Bus Sfx, Volume 1, Positional unticked; a trigger theme, its Clip abandoned_castle_music_-_starninjas_6.ogg, and a trigger bow, its Clip jingles_STEEL05.ogg.
  6. Add an AreaComponent, Size 144, 144, Offset 0, 56: the theatre’s floor. Make show.rgs with the script below and add Show.
  7. In the Cutscene tab, on stage, add an Audio track on stage with three cues, and an Activation track on performer, as the table below. Press the tab’s Save.
TrackAtCue
Audio, on stage0.5 sPlay music theme
3.0 sPlay sound bow
4.0 sStop music
Activation, on performer1.0 s to 3.5 sshown
rgs show.rgs
/// The theatre's show, its cutscene: the knight walking into the theatre
/// starts it. Its Audio track plays the show's music, the performer's bow and,
/// at the end, stops the music. Walked into again while it plays, it plays on;
/// once it is over, the next visit plays it again.
component Show : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            await play_cutscene();
        }
    }
}
The Inspector narrowed to audio, on stage: AudioSourceComponent with Clip (none), Bus Sfx, Volume 1.000, Pitch 1.00, Looping and Autoplay unticked, Positional unticked, Max Distance 512.00 dimmed, Pan 0.000, Max Voices 0; Triggers, 2 items, 1 theme and 2 bow
The stage’s Audio Source: theme and bow.
The Cutscene tab on stage: stage, 4.50 s, On stage; the playhead at 2.00 s of 4.50; the stage Audio track with three cues, Music: theme at 0.5, bow at 3.0 and Stop music at 4.0; the performer Activation track with a green bar from 1.0 to 3.5
The show’s timeline: three audio cues, and the performer shown.
A Play music cue
Asks the level’s music asset for a track of the cue’s name first, by its rules; only if the asset has none, it plays the node’s trigger of that name as the music, on the music channel. The gallery’s asset has no track theme, so the stage’s trigger plays, the title’s music, one music at a time.
A Play sound cue
Plays the node’s trigger of that name as a sound, through the node’s Audio Source, on its Bus: the bow, on Sfx, over the music.
A Stop music cue
Stops the music, whoever asked for it, as stop_music() does.
From the foyer he walks east through the treasury into the theatre, his steps on the boards. Listen for the show starting as he walks in: half a second later the title’s music as the show’s theme; three seconds in, the fanfare of the performer’s bow over it; and at four seconds the music stops.
What it sounds like

Footsteps on boards; a gentle castle melody begins; a bright steel-drum fanfare plays over it; then the melody stops, and only a far-off bell is left.

The game in the theatre two seconds after he walked in: the performer, a figure in purple, on the stone bench under the sign Theatre and its two banners, the knight below on the boards
Two seconds into the show: the performer on the dais.

A sound that carries far

A bell in the belfry, at the gallery’s east end, tolls every six seconds and is heard far down the gallery: a Custom rolloff holds it up across the rooms, where a Quadratic would let it go, and its Blend keeps a tenth of it even past its reach.

  1. Under belfry, add a Sprite, bell, at 40, -48 (the world’s 1248, 56), of art/bell.png, with a Collider 12 by 8, Offset 0, 3.
  2. Add an AudioSourceComponent: Clip bell.wav, Bus Sfx, Volume 0.4, Looping, Autoplay and Positional ticked; Max Distance 576, Min Distance 32, Blend 0.9, and Rolloff Custom.
  3. Open the Curve’s fold under Rolloff: its canvas, from 0 at Min Distance to 1 at Max Distance. Double-click the line to add a key, drag it, or select it and type its numbers in the fields under the canvas. Make the four keys of the table below.
  4. Select each key that leaves on a curve or a step, open Shape under the canvas, and choose its segment under Segment leaving this key. Press Ctrl+S.
xyinoutSegment leaving this key
0.01.000Constant
0.150.60-0.2Cubic
0.80.35-0.80Linear
1.00.000Linear
The Inspector narrowed to audio, on bell: AudioSourceComponent with Clip bell.wav, Bus Sfx, Volume 0.400, Looping and Autoplay ticked, Positional ticked, Max Distance 576.00, Blend 0.900, Rolloff Custom, its Curve open: a canvas with four orange keys, flat at the top from the left edge, a step down to the second key, selected and white with its out arm, an easing line to the third and a straight fall to the right edge at the bottom; under it Shape, and the fields x 0.15, y 0.60 and out -0.20; Min Distance 32.00, Pan 0.000, Max Voices 0
The bell’s Custom curve, its second key selected: x 0.15, y 0.6, out -0.2.
The same curve with its Shape menu open under the canvas: Start from, Linear, Ease in, Ease out and Constant 1; and Segment leaving this key, Constant, Linear and Cubic, Cubic lit
The Shape menu: the segment leaving the second key is Cubic.
A curve key’s x
Where the key sits along the canvas, left to right: for a rolloff, 0 at Min Distance and 1 at Max Distance.
A curve key’s y
What the curve reads at the key, bottom to top: for a rolloff, the share of the sound heard there, 1 all of it.
A curve key’s in and out
The slopes the curve arrives at the key on and leaves it on. Each is shown, as an arm on the canvas and a field under it, only where a Cubic segment reads it: out on a key whose own segment is Cubic, in on the key after one. Drag an arm, or type the slope; hold Shift while dragging an arm to break it from the other.
Segment leaving this key, in the Shape menu
How the curve is filled in from the selected key to the next. Constant holds the key’s value to the next key and steps there; Linear runs straight; Cubic bends by the two keys’ slopes. The menu’s Start from seeds the whole curve from a shape.

Flat to 114 away, where the wall into the machine room is; a step down there, standing in for the wall, which itself stops no sound; an ease, and a slow fall to nothing at 576. The gain is the Volume times the curve, blended by Blend: at 0.9, a tenth of the Volume, 0.04, still sounds past 576, where a Blend of 1 is silent. In the theatre, 520 away, the toll is more than twice what a Quadratic gives there: that is what Custom is for.

In the foyer, where he starts, five rooms from the bell and far past its Max Distance, after the gallery’s opening fanfare. Listen for the bell’s toll, faint, at six and twelve seconds: the tenth that Blend keeps. At a Blend of 1 there would be nothing here.
What it sounds like

A short fanfare; then silence but for a faint, low bell tolling at six and twelve seconds, ringing away each time.

The game in the belfry: the knight on the boards against the north wall beside the sign Far bell, the golden bell a little to his east
In the belfry, by the bell.

Steps on boards

The gallery’s floors are boards, and his steps on them are five takes of a step on wood. The pasted knight still plays the crypt’s steps on stone; his trigger changes.

  1. Select the gallery’s knight. In his Audio Source’s trigger step, drop footstep_wood_000.ogg on its Clip, and the other four on the four takes of its Clips, each at Weight 1.
  2. Set its Mode to Shuffle, and its Pitch and Volume ranges each to 1 to 1, as a trigger comes. Press Ctrl+S.
The Inspector narrowed to audio, on the gallery’s knight: AudioListenerComponent, Enabled ticked; AudioSourceComponent with Clip (none), Bus Sfx, Volume 0.500, Positional ticked, Max Voices 1; Triggers, 1 item, 1 step open: Name step, Clip footstep_wood_000.ogg, Clips 4 items, Mode Shuffle, Pitch Min 1.00 and Max 1.00, Volume Min 1.00 and Max 1.00
His steps on boards: five takes, Shuffle.

Shuffle, a trigger’s Mode as it comes, plays every take once in each round of five, and never one twice running, not even across a round’s end. Weight has nothing to say here: the five takes are alike. His walk’s step track, chapter 3’s, fires it: the radio’s, the chest’s and the show’s clips above have his steps in them.

The jukebox’s room

A door in the foyer’s north wall leads to the jukebox’s room, a scene and a level of its own. The jukebox plays four short songs, shuffled, never one twice running, leaning to its side of the room; when the innkeeper speaks, it makes room for him.

  1. Under foyer, add a Sprite, jukebox_door, at 8, -80 (the world’s 416, 24), of the region door_open, with an AreaComponent 32 by 16, Offset 0, 16. Make doorway.rgs with the script below, add Doorway, and set its To to jukebox.
  2. In the Levels tab, add a level Jukebox and press Create scene: scenes/jukebox.ron. Build its room as the two tables below: one room, 11 by 9 cells, from x 16 to 192 and y 32 to 176.
  3. Its stone is made as the gallery’s: a Tilemap on Sort Layer -3, and New tilemap… from art/tilemap_packed.png. This time the editor writes art/tilemap_packed-2.tilemap, as the status line says: the gallery’s file kept the first name’s id, so that name is not free. Rename it jukebox.tilemap, give it the same three layers, and paint it as the first table below. Press the tab’s Save.
  4. In Assets, click music and make jukebox.data in it the same way: Create → New data asset → Music, jukebox, Enter. Leave its Tracks and Rules empty. Press + beside its Playlist’s Clips: a first item at its default. Drop jingles_NES00.ogg on it; press + three times more and drop jingles_PIZZI07.ogg, jingles_SAX07.ogg and jingles_STEEL07.ogg on the three. Tick Shuffle, set Seed to 12, and leave Position at 0. Press Save.
  5. On the Jukebox row in Levels, drop jukebox.data on Music. Its Track list reads (no tracks).
rgs doorway.rgs
/// A door to a room that is a scene of its own: walked into, it opens that
/// scene. The jukebox's room is one, since its music is its own level's.
component Doorway : Area {
    /// The scene the door leads to, by its name.
    to: String = "",

    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            change_scene(to);
        }
    }
}
LayerRowsColumnsTiles, by the picker’s number
walls00; 1 to 11; 12the wall’s corner, #2; its top, #3; the other corner, #4
10; 1 to 11; 12the wall’s west side, #14; its face, #41; its east side, #16
2 to 100 and 12#14 in column 0 and #16 in column 12: the two sides
110; 1 to 11; 12the foot’s corner, #26; the wall’s foot, #27; the other corner, #28
floor21 to 11#51, the floor under the wall
3 to 101 to 11#49, or #50 in any cells you like
decoration11 and 11the banner, #30, at each end of the north wall
NodeComponentValue
Jukebox, the rootLeaveleave.rgs
confinerCamera Confinerat 104, 96, Bounds 208, 192
stoneTilemapat 0, 0: art/jukebox.tilemap, Sort Layer -3, painted as the table above
boardsSpriteat 104, 104: planks.png’s deck, Tiled, Size 176, 144, Tile Size 16, 16, Sort Layer -2, as the gallery’s
jukebox_signShape, WorldTextat 64, 24: a gallery room’s sign, 42 wide, Jukebox
jukeboxSprite, Colliderat 32, 80: the region jukebox; a Collider 14 by 28
innkeeperSprite, Colliderat 176, 88: the region innkeeper; a Collider 12 by 8, Offset 0, 4
Area48 by 48, Offset -8, 0
Audio Sourceno Clip, Sfx, Volume 1, Positional unticked; trigger line = voice.wav
Speakerspeaker.rgs
exitSprite, Area, Doorwayat 112, 24: door_open, an Area as the door’s; To gallery
mixAudio MixMusic slot 1: Panner, Pan -0.5, Width 1, ticked; a Ducking row as it comes
knightat 112, 120: the crypt’s knight, with no Audio Source, no Audio Listener and no lantern
rgs speaker.rgs
/// The innkeeper, by the jukebox. As the knight comes up to him he says his
/// line, and the jukebox makes room for it: the mix's Ducking row holds the
/// Music bus down while anything on Sfx is over its Threshold, as his words
/// are. In the two breaths between them his voice falls silent and the
/// jukebox lifts a little; the Release keeps it from coming all the way back.
component Speaker : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "knight") {
            play_sound("line");
        }
    }
}
The Inspector drawing jukebox.data, MusicGraph: Tracks no items; Rules no items; Default Transition CrossFade, Seconds 1.00 s; Playlist with Clips, 4 items, jingles_NES00.ogg, jingles_PIZZI07.ogg, jingles_SAX07.ogg and jingles_STEEL07.ogg; Shuffle ticked; Seed 12; Position 0
The jukebox’s music: no tracks, and a Playlist of four.
The Levels panel: 4 in order; 4 Jukebox, scenes/jukebox.ron, selected, with its buttons, Music: jukebox.data and Track: (no tracks)
The Jukebox’s level: its Music an asset with no tracks.
The music asset’s Playlist
Clips played one after another, each once a pass, round and round, under the level’s tracks from the level’s opening, or alone in an asset with no tracks, as here. Its songs are the game’s music, on the Music bus, from nowhere.
The playlist’s Clips
The songs, in the order they were added; each + adds a slot, and a clip is dropped on it.
The playlist’s Shuffle
Ticked, it plays the clips in a new order each pass, each clip once in a pass and never one twice running, not even across a pass’s end. Unticked, in the order they were added.
Seed
Where the shuffle is drawn from. The same seed is the same order, so the room plays the same songs in the same order every time it opens.
Position
How far through its pass the playlist stands, as it was saved: 0, the start. The game keeps its own place as it plays and never writes it back to the asset.
The Inspector narrowed to audio, on the jukebox room’s mix: Effects; Master with no slots; Music with one slot open, 1 Panner, Effect Panner, Pan -0.500, Width 1.000, Enabled ticked; Sfx with no slots; Snapshots no items; Ducking, 1 item, 1 Sfx>Music open: Trigger Sfx, Target Music, Threshold -30.0 dB, Amount 8.0 dB, Attack 0.05 s, Release 0.40 s; Sends no items
The room’s mix: a Panner on Music, and a Ducking row as it comes.

The Panner is the one you can hear: the songs are music, with no place of their own, so the Music bus’s Panner at Pan -0.5 leans them to the jukebox’s west side, the left at full and the right at half; Width 1 changes nothing on these jingles, whose two channels are the same. The Ducking row is the row as it comes: while Sfx is over -30 dB, Music comes down 8 dB.

The jukebox’s room as it opens, standing. Listen for one short song after another: four different ones, each once, before any comes round again, and never the same song twice running; and every one from your left, the right ear at half.
What it sounds like

Short jingles one after another, louder in the left ear: pizzicato strings, an eight-bit tune, steel drums and a saxophone, then the strings, the eight-bit tune and the saxophone again.

Two seconds after the room opens he walks up to the innkeeper. Listen for the jukebox dropping under his line, staying down while he speaks and lifting a little in his breaths, then coming back up within about a second of his last word.
What it sounds like

Jingles playing; a man’s wordless voice speaks a line of seven syllables, and the music sinks under it; as the voice stops, the music rises back.

The game in the jukebox’s room as it opens: a boarded room, the jukebox against the west wall, the innkeeper by the east wall, the knight in the middle, the exit door and the sign Jukebox in the north wall with a banner at each end
The jukebox’s room.

Who decides what you hear

The gallery, case by case

NodeComponentFieldValue
title_menu › galleryText, ButtonText, ActionGallery, gallery
FocusUp, Down, Next, Previousoptions, play, play, options
title_frameRectOffset Max y541
title_menuTitleMenutitle_menu.rgs, rewritten
Gallery, in Levelsthe levelScene, Music, Trackscenes/gallery.ron, music/gallery.data, fanfare
Jukebox, in Levelsthe levelScene, Musicscenes/jukebox.ron, music/jukebox.data
music/gallery.dataMusicTracks, Rulesfanfare (jingles_STEEL05.ogg, Looping unticked), calm; any → fanfare Immediate, fanfare → calm AtEnd
music/jukebox.dataMusicPlaylistfour jingles, Shuffle ticked, Seed 12, Position 0
Gallery › mixAudio MixSfx slotsHighPass 400/0.707, BandPass 1200/1.0, Distortion 12/0.7, each unticked
Snapshotsthrough_wall (Sfx on, on, off), haunted (Sfx off, off, on)
radioAudio SourceClip, Bus, Volumeheavy_boss_battle_1_bpm200_0.ogg, Sfx, 0.8
Max Distance, Rolloff, Min Distance256, Linear, 16
listening_zoneAudio ZoneSnapshot, Fade, Prioritythrough_wall, 0.5, 0
ghostAudio Sourcetrigger whisperwhisper.wav; Max Distance 160, Quadratic, Min Distance 32
HauntHaunting3 s
machineAudio SourceClip, Volume, Pitchgate-grind.wav, 0.2, 0.6
MachineWound, Roar, Winding1.6, 0.6, 3 s
chestArea, Chest32 by 32, Offset 0, 24; chest.rgs
stageTimelineTimelinescenes/stage.timeline: Play music theme at 0.5, Play sound bow at 3, Stop music at 4; performer shown 1 to 3.5
Audio Sourcetriggerstheme, bow; Positional unticked
bellAudio SourceVolume, Max Distance, Min Distance0.4, 576, 32
Blend, Rolloff0.9, Custom: four keys, Constant, Cubic, Linear, Linear
knight (gallery)Audio Sourcetrigger stepfive steps on wood, Shuffle
innkeeperAudio Source, Speakertrigger linevoice.wav; speaker.rgs
Jukebox › mixAudio MixMusic slot 1Panner, Pan -0.5, Width 1
DuckingSfx over Music, -30 dB, 8 dB, 0.05 s, 0.4 s

Check it works