diff options
| author | Cliff Click <cliffc@acm.org> | 2026-11-12 13:16:00 -0800 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-11-12 13:52:46 -0800 |
| commit | 467338ee01565234762db8077c067df42c3b40a8 (patch) | |
| tree | 42c44a77da87c4811b1eb7611d0952dc2c55e022 /chapter31/docs | |
| parent | 0720fd8ed0aa92248622a9f3c3ebd522b002fd91 (diff) | |
| download | Simple-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.md | 62 | ||||
| -rw-r--r-- | chapter31/docs/drawing.md | 3 | ||||
| -rw-r--r-- | chapter31/docs/examples/README.md | 1 | ||||
| -rw-r--r-- | chapter31/docs/examples/TicTacToeGraphical.smp | 15 | ||||
| -rw-r--r-- | chapter31/docs/graphics.md | 13 |
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. |
