summaryrefslogtreecommitdiff
path: root/chapter31/docs
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-11-12 13:16:00 -0800
committerCliff Click <cliffc@acm.org>2026-11-12 13:52:46 -0800
commit467338ee01565234762db8077c067df42c3b40a8 (patch)
tree42c44a77da87c4811b1eb7611d0952dc2c55e022 /chapter31/docs
parent0720fd8ed0aa92248622a9f3c3ebd522b002fd91 (diff)
downloadSimple-467338ee01565234762db8077c067df42c3b40a8.tar.gz
Simple-467338ee01565234762db8077c067df42c3b40a8.zip
Add audio, overhaul makefiles
Adds simple audio support to Simple Overhaul makefiles; remove common boilerplate; make them more uniform
Diffstat (limited to 'chapter31/docs')
-rw-r--r--chapter31/docs/audio.md62
-rw-r--r--chapter31/docs/drawing.md3
-rw-r--r--chapter31/docs/examples/README.md1
-rw-r--r--chapter31/docs/examples/TicTacToeGraphical.smp15
-rw-r--r--chapter31/docs/graphics.md13
5 files changed, 89 insertions, 5 deletions
diff --git a/chapter31/docs/audio.md b/chapter31/docs/audio.md
new file mode 100644
index 00000000..30817012
--- /dev/null
+++ b/chapter31/docs/audio.md
@@ -0,0 +1,62 @@
+# Optional background audio
+
+`sys.audio` uses [miniaudio](https://github.com/mackron/miniaudio) through an
+optional native C backend. Playback runs on its own thread; the game keeps
+processing input and drawing. No Python, CMake, codec packages, or sound files
+are needed. Default builds/tests never download miniaudio or open a device.
+
+From `chapter31`:
+
+```sh
+make libs CTAGS= # Once while online, or use make init.
+make audio CTAGS=
+make run-graphical-tictactoe CTAGS=
+```
+
+The last command builds both optional backends and runs the game. Accepted
+moves get a quiet 70ms sine boop. A player win gets a 480ms rising C-E-G
+celebration; a CPU win reverses the notes. Invalid input and occupied squares
+are silent. Replay stops any previous cue. Win/loss cues replace the ordinary
+move boop; draws use the ordinary boop.
+
+For direct execution in PowerShell, alongside `SIMPLE_MINIFB`:
+
+```powershell
+$env:SIMPLE_MINIAUDIO = (Resolve-Path build/release/x86_64_v2_win64/simple_miniaudio.dll).Path
+.\build\examples\x86_64_v2_win64\TicTacToeGraphical.exe
+```
+
+Linux uses `libsimple_miniaudio.so` in the corresponding release directory.
+`SIMPLE_MINIAUDIO` must name the full backend path. Unset it or set it to `off`
+for silent play. An unavailable audio device returns `ERROR` and the game
+continues. Audio and graphics can be configured independently.
+
+| Operation | Meaning |
+| --- | --- |
+| `open()` | Open output and generate built-in sounds; `OK` (0) or `ERROR` (-1). Repeated open is safe. |
+| `boop()`, `win()`, `lose()` | Play a built-in cue; same as `play(BOOP/WIN/LOSE)`. |
+| `load(samples)` | Copy `i16[~]` mono PCM at `RATE` (48000Hz); return handle or `ERROR`. |
+| `play(handle)` | Start/restart, replacing the current sound. Return `OK` or `ERROR`. |
+| `stop()` | Stop playback; safe before open/after close. |
+| `playing()` | Whether samples remain to submit; final device buffering may remain. |
+| `close()` | Join the audio thread and free device/buffers; safe to repeat. |
+
+All calls belong on the main/game thread. Load custom sounds at startup:
+there are 28 custom slots, each up to ten seconds, retained until close.
+Custom handles must be reloaded after close/reopen. Signed samples range
+from -32768 to 32767; quiet effects should use much smaller amplitudes.
+Native code copies the array and never retains a Simple heap pointer or calls
+Simple from the audio thread. Playback itself neither allocates nor waits for
+the sound duration. This first interface plays one sound at a time.
+
+`audio.mk` pins miniaudio 0.11.23, cached under `lib/miniaudio-0.11.23/` by
+`make libs` (or `init`; `lib` remains a setup alias). Only these explicit setup
+targets can download dependencies. All builds, runs, and tests use local
+copies, surviving `make clean`; missing cache entries fail promptly with setup
+instructions. Windows uses the existing MinGW-w64 compiler;
+Linux uses GCC and system pthread/math/dl libraries. No audio development
+headers need installing. The upstream header includes its public-domain and
+MIT-0 license options, copied beside the backend as `miniaudio-LICENSE`.
+`make test-audio CTAGS=` builds the backend checks from the local cache
+and runs a real audio thread with miniaudio's silent null
+device; normal tests exercise the loader and game without hardware.
diff --git a/chapter31/docs/drawing.md b/chapter31/docs/drawing.md
index d9d7e624..3fec1f12 100644
--- a/chapter31/docs/drawing.md
+++ b/chapter31/docs/drawing.md
@@ -76,6 +76,9 @@ The explicit backend path follows [the pixel-window instructions](graphics.md).
Passing any argument performs a five-poll, self-closing smoke test.
The original `make tictactoe` still builds the terminal game.
+The graphical game also uses optional [background audio](audio.md): a soft
+boop for accepted moves, rising tones for a player win, and falling tones for
+a CPU win. Bad input is silent. The run target builds/configures both backends.
`make test CLASS=DrawTest CTAGS=` checks raster pixels and complete game turns
without a display. `make tests_nographics CTAGS=` runs the ordinary suite with
the backend disabled.
diff --git a/chapter31/docs/examples/README.md b/chapter31/docs/examples/README.md
index db95487e..a1d81be2 100644
--- a/chapter31/docs/examples/README.md
+++ b/chapter31/docs/examples/README.md
@@ -8,6 +8,7 @@ The [graphical tic-tac-toe](TicTacToeGraphical.smp) uses the Simple
[drawing library](../drawing.md). Run it with
`make run-graphical-tictactoe CTAGS=`; click a cell or press 1–9, R/Space to
replay, and Q/Escape to quit. The terminal game below remains available.
+Optional [background audio](../audio.md) supplies soft move and win/loss cues.
From `chapter31`, build the tic-tac-toe executable (without starting it):
diff --git a/chapter31/docs/examples/TicTacToeGraphical.smp b/chapter31/docs/examples/TicTacToeGraphical.smp
index 7daf6710..b4f8bcf4 100644
--- a/chapter31/docs/examples/TicTacToeGraphical.smp
+++ b/chapter31/docs/examples/TicTacToeGraphical.smp
@@ -7,6 +7,7 @@ val main = { u8[~][] args ->
val board = new u8[9];
_reset(board);
if( sys.gfx.open("Simple tic-tac-toe",screen.width,screen.height) != sys.gfx.OK ) return 1;
+ sys.audio.open(); // Audio is optional; failure leaves the game silent.
_draw(screen,board,-1);
int result = sys.gfx.present(screen.pixels);
bool mouseHeld = false, keyHeld = false, replayHeld = false;
@@ -20,7 +21,7 @@ val main = { u8[~][] args ->
int square = _square(sys.gfx.mouseX(),sys.gfx.mouseY());
bool dirty = square!=hover;
hover = square;
- if( replay && !replayHeld ) { _reset(board); dirty=true; }
+ if( replay && !replayHeld ) { sys.audio.stop(); _reset(board); dirty=true; }
bool digit = false;
int choice = down && !mouseHeld ? square : -1;
for( int i=0; i<9; i++ ) {
@@ -30,7 +31,10 @@ val main = { u8[~][] args ->
if( !keyHeld ) choice=i;
}
}
- if( !(replay && !replayHeld) && _move(board,choice) ) dirty=true;
+ if( !(replay && !replayHeld) && _move(board,choice) ) {
+ sys.audio.play(_sound(board));
+ dirty=true;
+ }
mouseHeld = down;
keyHeld = digit;
replayHeld = replay;
@@ -40,10 +44,17 @@ val main = { u8[~][] args ->
}
if( args#>1 && ++frames==5 ) break;
}
+ sys.audio.close();
sys.gfx.close();
return result==sys.gfx.ERROR ? 1 : 0;
};
+// Called only for an accepted move; invalid input never requests a sound.
+val _sound = { u8[~] board ->
+ int winner = _winner(board);
+ return winner=='X' ? sys.audio.WIN : winner=='O' ? sys.audio.LOSE : sys.audio.BOOP;
+};
+
val _reset = { u8[] board ->
for( int i=0; i<9; i++ ) board[i]=' ';
};
diff --git a/chapter31/docs/graphics.md b/chapter31/docs/graphics.md
index fb3972ee..2394a401 100644
--- a/chapter31/docs/graphics.md
+++ b/chapter31/docs/graphics.md
@@ -7,12 +7,14 @@ provides a window, input, and pixel presentation. The first interface is
The [drawing library and graphical tic-tac-toe](drawing.md) build on this pixel
interface. `make run-graphical-tictactoe CTAGS=` builds the optional backend and
opens the game; `make graphical-tictactoe CTAGS=` only builds its executable.
+The game run target also builds optional [background audio](audio.md).
## Default: no graphics dependency
From `chapter31`, the usual `make release`, `make tests`, and `make tictactoe`
need no MiniFB, graphics headers, OpenGL, CMake, or running display. Nothing
-downloads MiniFB unless you explicitly request `make graphics`.
+downloads dependencies unless you explicitly request `make libs` or `make init`
+(`make lib` remains a setup alias). Build and run targets never use the network.
`make tests_nographics CTAGS=` runs the entire ordinary suite with
`SIMPLE_MINIFB=off`. This includes the missing-backend tests, which never open
@@ -29,12 +31,14 @@ the process. Non-graphics programs ignore even a broken graphics configuration.
From `chapter31`:
```sh
+make libs CTAGS= # Once while online; fills the persistent lib/ cache.
make graphics graphics-example CTAGS=
make run-graphics CTAGS=
```
-`graphics` downloads the revision pinned in [graphics.mk](../graphics.mk) into
-ignored `build/deps/minifb` and builds only its C framebuffer backend. Windows
+`libs` downloads the revision pinned in [graphics.mk](../graphics.mk) into
+ignored `lib/minifb-<revision>.tar.gz` and extracts it under `lib/`.
+`graphics` builds only its C framebuffer backend from these local sources. Windows
uses the MinGW-w64 GCC compiler (`x86_64-w64-mingw32-gcc`) and GDI; the rest of
Simple still uses the existing Cygwin GCC. Linux uses GCC and X11 (`libx11-dev`
on Ubuntu), including XWayland on a Wayland desktop. OpenGL, the C++ callback
@@ -50,6 +54,9 @@ Outputs:
`MiniFB-LICENSE` is copied alongside the backend; include it when distributing
the library. MiniFB sources remain outside the tracked Simple sources.
+The cache survives `make clean`. Editing a makefile or rebuilding a backend
+does not fetch or check GitHub. Missing dependencies fail promptly with
+instructions to run `make libs` while online.
`graphics-example` alone builds the executable without requiring MiniFB. It
also demonstrates the diagnostic and exit status 1 when graphics is absent.