thecodingidiot.com

Who Wants to Be a Game Developer? AcousticThe Audio Design

The Audio Design

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:

TierQuestionsWAV fileFeel
11–5music/tier1.wavCalm; low stakes, early game
26–10music/tier2.wavTense; past the first safe level
311–15music/tier3.wavDramatic; 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);
 
#endif

The 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.