A 48K Spectrum has one bit of sound hardware, bit 4 of port $FE, and Pentagram makes every sound by setting and clearing it with the processor counting in between, the border kept black. While a sound plays nothing else happens, which is why the game stands still for a tune. There are two players. The tunes go through PLAY_NOTE, a note at a time; everything else is a burst of waves from CLICK, which turns the speaker on for B turns of a 13 T-state loop and off for as long, and BEEP, which repeats it C times.

The tune player and its note table are Knight Lore's (see Knight Lore's sounds). A tune is a string of note bytes ended by $FF: the low six bits index NOTES, five octaves of semitones from G#1 to G6 with 0 a rest, and the top two bits are the length less one, one to four units of about 0.155 s. Checked at this build against Knight Lore's snapshot: of the 88 bytes of PLAY_NOTE, the 4 that differ from Knight Lore's play_note ($B2DA) are exactly the two addresses in it, the CALL to ADD_HL_A and the LD of NOTES; and the 183 bytes of NOTES are Knight Lore's note table ($B332) exactly. The six tunes themselves are Pentagram's own: none of them is in Knight Lore.

The effects are Pentagram's. Most in-game sounds are a single burst -- a jump, a bolt, a footstep, a puff. Two are sequences, played a note a turn by EFFECT_NOTE from the end of the main loop's turn (OBJECT_DONE): SOUND_COUNT holds how many notes are left and which of the four effects in EFFECTS, and each turn one note of twelve waves is played, from the last byte of the effect's notes back. Only effects 0 (entering a room) and 1 (picking up or putting down) are ever started; 2 and 3 have their notes and their addresses, and nothing sets them. About a hundred bytes of other sound code and pitch tables, from BLIP_BY_TURN to MORE_PITCHES_D and at BEEP_BY_GRAPHIC, are never reached at all.

Every recording here is the game's own code running in SkoolKit's simulator, each change of the speaker bit logged to the T-state and rendered at 44100 Hz; nothing is synthesised. Each says how it was recorded and how it was checked against what the code implies: the number of waves, and every half-wave's length in T-states from the instructions of the loop that timed it. The simulator has no memory contention, so all of this runs a touch faster, and a touch higher, than on a real Spectrum, where the ULA holds up the OUTs. A quiet turn (room 30, nothing moving) lasts 160,637 T-states, 46 ms; the calls that stand for an effect played over several turns are spaced by that.

Tunes

The start of a game

Played in full by START once 0 has been pressed at the menu, before the quest is set out and the first room is built.

Recorded: PLAY_TUNE called with DE = TUNE_START.

Checked: 19 notes, 32 units, no rests, from row 37 (G#4, 415 Hz) to row 49 (G#5, 824 Hz). The table's wave counts make that 2,955 waves, so 5,909 edges (the first OUT turns off a speaker already off); the recording has 5,909 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

5.06 s, 5,909 edges, 415 to 824 Hz (G#4 to G#5).

The menu

Played by PLAY_TUNE_ONCE under the menu (MENU), the first time the menu is shown after the game is loaded or a game ends; any key stops it between two notes, and it does not play again until the next game is over (TUNE_HEARD).

Recorded: PLAY_TUNE_ONCE called with DE = TUNE_MENU, TUNE_HEARD clear and no key down, so it plays to the end, as it does for a player who waits.

Checked: 84 notes, 129 units, no rests, from row 32 (D#4, 313 Hz) to row 44 (D#5, 619 Hz). The table's wave counts make that 10,401 waves, so 20,801 edges (the first OUT turns off a speaker already off); the recording has 20,801 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

20.28 s, 20,801 edges, 313 to 619 Hz (D#4 to D#5).

A quest item done

Played in full by BUCKET when the bucket has flown over a quest item: the game stands still while it plays, and then the bucket turns into a puff and the item into its finished form (QUEST_ITEM).

Recorded: PLAY_TUNE called with DE = TUNE_QUEST.

Checked: 11 notes, 15 units, no rests, from row 32 (D#4, 313 Hz) to row 44 (D#5, 619 Hz). The table's wave counts make that 969 waves, so 1,937 edges (the first OUT turns off a speaker already off); the recording has 1,937 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

2.35 s, 1,937 edges, 313 to 619 Hz (D#4 to D#5).

The quest complete

Played in full by WON under the congratulations, when the fifth collectable reaches its place on the pentagram.

Recorded: PLAY_TUNE called with DE = TUNE_WON.

Checked: 31 notes, 48 units, no rests, from row 32 (D#4, 313 Hz) to row 46 (F5, 696 Hz). The table's wave counts make that 3,887 waves, so 7,773 edges (the first OUT turns off a speaker already off); the recording has 7,773 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

7.55 s, 7,773 edges, 313 to 696 Hz (D#4 to F5).

Game over

Played in full by GAME_OVER (in WON) under the percentage, after the last life is lost and after the win; then about four seconds' wait, and the menu.

Recorded: PLAY_TUNE called with DE = TUNE_OVER.

Checked: 27 notes, 48 units, no rests, from row 30 (C#4, 279 Hz) to row 44 (D#5, 619 Hz). The table's wave counts make that 3,117 waves, so 6,233 edges (the first OUT turns off a speaker already off); the recording has 6,233 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

7.53 s, 6,233 edges, 279 to 619 Hz (C#4 to D#5).

The notes the tunes use, worked out from NOTES and PLAY_NOTE's timing: B and C time each half-wave, and a unit is that many waves. The table has 61 rows; these are the ones any of the six tunes plays.

RowNoteBCWaves a unitPitchA unitPlayed in
23F#3203329186.7 Hz0.155 sA tune nothing plays
25G#3125333209.3 Hz0.158 sA tune nothing plays
27A#356337234.5 Hz0.158 sA tune nothing plays
30C#4221244279.2 Hz0.158 sA tune nothing plays, Game over
32D#4169249312.9 Hz0.157 sA quest item done, Game over, The menu, The quest complete
34F4123255350.4 Hz0.157 sA quest item done, Game over
35F#4102258370.6 Hz0.156 sA tune nothing plays
36G481262393.4 Hz0.158 sA quest item done, Game over, The quest complete
37G#463265415.2 Hz0.157 sA quest item done, Game over, The menu, The quest complete, The start of a game
38A445269439.6 Hz0.157 sA quest item done
39A#428273465.5 Hz0.157 sA tune nothing plays, Game over, The menu, The quest complete, The start of a game
40B412278492.7 Hz0.158 sThe start of a game
41C5253182523.1 Hz0.157 sA quest item done, Game over, The menu, The quest complete
42C#5239187553.2 Hz0.157 sA tune nothing plays, Game over, The menu, The quest complete, The start of a game
44D#5213198619.4 Hz0.158 sA quest item done, Game over, The menu, The quest complete, The start of a game
45E52011104655.6 Hz0.159 sThe start of a game
46F51891110696.2 Hz0.158 sThe quest complete
47F#51791117734.2 Hz0.159 sThe start of a game
49G#51591131824.1 Hz0.159 sThe start of a game

Effects in play

Entering a room

Effect 0: on the first turn in a room OBJECT_DONE sets SOUND_COUNT to four notes of effect 0, and EFFECT_NOTE plays one a turn, twelve waves each, from the last byte of the effect's notes back (EFFECTS). Every room, whether he came through a doorway or started a life there.

Recorded: the game running: a life started in room 30, which has nothing in it that makes a sound, and five turns from the room's first.

Checked: 48 waves, 96 edges (the code implies 48 and 96); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64; one note a turn.

495 ms, 96 edges, 5 turns, 1169 to 2005 Hz.

Walking

FOOTSTEP, called by HANDLE_FORWARD for every step of his legs: STEP_SOUND counts them, and every fourth plays two waves, at a half-wave count of 64 and 96 by turns -- a step of the legs is a turn, so a tick every four turns, the pitch alternating.

Recorded: the game running in room 30: walk held for 16 turns.

Checked: 8 waves, 16 edges (the code implies 8 and 16); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64, the step counter going from 1 to 17.

789 ms, 16 edges, 16 turns, 1358 to 2005 Hz.

A bolt and its puff

FIRE_SOUND as the bolt is fired, and then, when it bumps into the wall and turns into a puff, PUFF_SOUND on each of the puff's turns (PUFF): four single waves at pitches read from the ROM, from an address made of the random number and the byte after it, so no two puffs sound alike. Every puff makes it: a bolt's, the player's own when he dies, the bucket's, a thing shot down.

Recorded: the game running in room 30, fire pressed for a turn with him facing the wall at U 150, until the puff has gone.

Checked: 32 waves fired, 64 edges (the code implies 32 and 64); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 76; then 7 bursts of 4 waves, one a turn, every off half-wave inside a burst 13B + 133 for its B (PUFF_SOUND's loop round BEEP), and each burst's four pitches four bytes in a row of the ROM's first 512, less their top bits, as PUFF_SOUND reads them.

851 ms, 120 edges, 18 turns, noise.

Pausing, and going on

PAUSE_BEEP, played by PAUSE as SPACE (or CAPS SHIFT) alone pauses the game and again as it lets it go on: twelve waves at 64 plus SOUND_COUNT's first byte, after adding one to it. So each beep is a little lower than the last, and the two added to the count make EFFECT_NOTE play the last effect's last two notes again on the turns after.

Recorded: the game running in room 30, nothing under way (SOUND_COUNT 0, effect 0): SPACE held 0.3 s, let go 0.5 s, held 0.3 s, let go; recorded on to three turns later. The silence in the middle is the pause, as long as it was held.

Checked: 48 waves, 96 edges (the code implies 48 and 96); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64.

1.37 s, 96 edges, 1169 to 2005 Hz.

Picking up and putting down

Effect 1: every press of the pick-up key that TAKE_OR_LEAVE acts on sets SOUND_COUNT to five notes of effect 1, which EFFECT_NOTE plays one a turn, falling -- whether he picks something up, puts something down, or only moves what he carries along a place.

Recorded: the game running in room 30: collectable record 4 (graphic 148) moved into the room 15 units in front of him, and 1 pressed for a turn; recorded from that turn for seven. He picked it up: its quest record's graphic went to 0, as TAKE_OR_LEAVE marks a thing carried.

Checked: 60 waves, 120 edges (the code implies 60 and 120); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64; one note a turn.

360 ms, 120 edges, 7 turns, 1169 to 2005 Hz.

A jump

JUMP_SOUND, from HANDLE_JUMP as he leaves the ground: sixteen single waves at a half-wave count of (C XOR $A5) + C for C = 16 down to 1, so the pitch jumps about rather than sweeping -- Knight Lore's werewolf warble with $A5 in place of $55.

Recorded: one call; it sets its own pitches.

Checked: 16 waves, 32 edges (the code implies 16 and 32); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 83.

22 ms, 32 edges, 670 to 797 Hz.

A bolt fired

FIRE_SOUND, from FIRE when a bolt sets off: 32 single waves, each half-wave count the step count less the one before. FIRE comes straight from an LDIR that leaves B at 0, so the counts go 32, 255, 31, 254 ... a high note and a low one interleaved, both falling.

Recorded: one call with B = 0, as the LDIR leaves it.

Checked: 32 waves, 64 edges (the code implies 32 and 64); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 76.

33 ms, 64 edges, 521 to 6530 Hz.

Never heard in the game

Code and data that the game has but never plays, recorded by calling it to hear what it would have made.

Effect 2, never started

The notes EFFECT_NOTE would play for effect 2, whose address is in EFFECTS and whose notes are there after effect 1's; but the only code that starts an effect sets 0 (OBJECT_DONE) or 1 (TAKE_OR_LEAVE). How many notes it has is not written anywhere; 7 is what fits before effect 3's address, as each effect's address is the last note of the one before.

Recorded: 7 calls of EFFECT_NOTE with SOUND_COUNT set to 7, 6 ... 1 and effect 2, as the game would leave it turn by turn, a quiet turn apart (160,637 T-states, measured below).

Checked: 84 waves, 168 edges (the code implies 84 and 168); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64.

342 ms, 168 edges, 1026 to 2632 Hz.

Effect 3, never started

The notes EFFECT_NOTE would play for effect 3, whose address is in EFFECTS and whose notes are there after effect 1's; but the only code that starts an effect sets 0 (OBJECT_DONE) or 1 (TAKE_OR_LEAVE). How many notes it has is not written anywhere; 3 is what fits before the code at FIRE_SOUND, as each effect's address is the last note of the one before.

Recorded: 3 calls of EFFECT_NOTE with SOUND_COUNT set to 3, 2 ... 1 and effect 3, as the game would leave it turn by turn, a quiet turn apart (160,637 T-states, measured below).

Checked: 36 waves, 72 edges (the code implies 36 and 72); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64.

114 ms, 72 edges, 1358 to 2632 Hz.

A blip, never reached

BLIP_BY_TURN: twelve waves at one of sixteen pitches from BLIP_PITCHES, picked by the turn counter, if bit 1 of the object's flags was set. No code or table holds its address; it is Knight Lore's movable-block buzz, gated on a flag, left behind.

Recorded: 16 calls with IX on a record whose flags have bit 1 set and the turn counter 0 to 15, a quiet turn apart: what one object calling it every turn would make.

Checked: 192 waves, 384 edges (the code implies 192 and 384); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64.

765 ms, 384 edges, 1619 to 3829 Hz.

Two beeps, never reached

The code at BEEP_BY_GRAPHIC, which nothing reaches (the listing keeps it as data): six waves pitched by the low three bits of the object's graphic (its complement, moved to the top three bits), and, entered after its data byte, eight waves pitched by the complement of that byte, which is 0 on the tape and written by nothing.

Recorded: the first part called with IX on a record of graphic 0, 1 ... 7 -- the eight pitches it can make -- then the second part once, a quiet turn apart.

Checked: 56 waves, 112 edges (the code implies 56 and 112); every on half-wave was 13B + 18 T-states for the B the code gives it, and every off half-wave between two waves of a burst was 13B + 64.

435 ms, 112 edges, 519 to 3829 Hz.

A tune nothing plays

At TUNE_UNUSED, in the tunes' format among the others, and no code or table refers to its address: never played in the game. Recorded by handing it to the tune player all the same.

Recorded: PLAY_TUNE called with DE = TUNE_UNUSED.

Checked: 14 notes, 29 units, no rests, from row 23 (F#3, 187 Hz) to row 42 (C#5, 553 Hz). The table's wave counts make that 1,611 waves, so 3,221 edges (the first OUT turns off a speaker already off); the recording has 3,221 -- the same. Every off half-wave was D + 39 T-states and every on half-wave inside a note was D + 62, D being 13B + 3339C - 3333 for the note's B and C, as PLAY_NOTE's loops imply.

4.55 s, 3,221 edges, 187 to 553 Hz (F#3 to C#5).