Before writing a line of implementation, define what the music module must do and what interface it exposes.
What plays when
The game has 15 questions and two safe levels. The dramatic arc of the WWTBAM score maps to three tiers:
| Tier | Questions | WAV file | Feel |
|---|---|---|---|
| 1 | 1–5 | music/tier1.wav | Calm; low stakes, early game |
| 2 | 6–10 | music/tier2.wav | Tense; past the first safe level |
| 3 | 11–15 | music/tier3.wav | Dramatic; the final five questions |
The current question index is level in game_loop. Tier 1 starts
when the game starts. Tier 2 starts when level reaches 5 (the
player answered Q5 correctly and is now on Q6). Tier 3 starts when
level reaches 10.
The music stops when the game ends — win, loss, or walk-away.
The music lifecycle
The important invariant: at any moment during a game, exactly one
child process is running aplay. When the tier changes, the old
child is stopped before the new one is started.
The API
The music module exposes two functions. Design the signatures by reading the lifecycle diagram.
start_music needs a file path (which WAV to play) and must return
something the caller can use to stop it later. aplay runs as a child
process; the caller needs its PID to send it a signal. So
start_music returns pid_t.
stop_music needs the PID returned by start_music. It returns
nothing — stopping music is a fire-and-forget operation from the
game's perspective.
music.h — replace the stub with the real header:
#ifndef MUSIC_H
# define MUSIC_H
# include <sys/types.h>
# include <sys/wait.h>
# include <signal.h>
# include <unistd.h>
pid_t start_music(const char *path);
void stop_music(pid_t pid);
#endifThe system headers belong in music.h rather than music.c because
game.c includes music.h (via game.h) and calls both functions —
it needs the pid_t type in scope.
What the caller stores
game_loop in game.c will hold the current child PID in a local
variable:
pid_t music_pid;Every call to stop_music and start_music goes through this
variable. When the game ends, stop_music(music_pid) is the last call
before cleanup. The game does not need a struct for this — a single
local variable is enough.
The next two pages implement the two functions.