diff --git a/README.md b/README.md index 8801270..2b16ff8 100644 --- a/README.md +++ b/README.md @@ -410,7 +410,9 @@ Plus six more the original already carried: a leading `0` selects base 8, so `PR * `USING`, `VERIFY`, `VOL`, `WAIT`, `WIDTH`, `WINDOW` * The I/O-channel variants (`GETIO`, `INPUTIO`, `OPENIO`, `PRINTIO`, `RECORDIO`) -None of those is blocked on a missing `libakgl` capability any more. Four were — text measurement, immediate-mode drawing, audio, and a non-blocking keystroke read — and rather than work around them here they were filed in [`deps/libakgl/TODO.md`](deps/libakgl/TODO.md) under "API gaps blocking akbasic". All four have since landed upstream (`akgl_text_measure`, the `akgl_draw_*` family, `akgl_audio_*`, and `akgl_controller_poll_key`), so what is left is akbasic-side work. +One of those is still blocked on a missing `libakgl` capability, and it is only one. Four were — text measurement, immediate-mode drawing, audio, and a non-blocking keystroke read — and rather than work around them here they were filed in [`deps/libakgl/TODO.md`](deps/libakgl/TODO.md) under "API gaps blocking akbasic". All four have since landed upstream (`akgl_text_measure`, the `akgl_draw_*` family, `akgl_audio_*`, and `akgl_controller_poll_key`), so what is left is akbasic-side work. + +The exception is `FILTER`, which sets the SID's filter cutoff, band switches and resonance. `akgl_audio_*` synthesises raw waveforms and mixes them; there is no filter stage to configure, and SDL3 supplies no primitive to build one from. Until an `akgl_audio_filter()` exists, `FILTER` parses and then refuses at execution rather than being silently ignored — a program that asks for a low-pass and gets an unfiltered square wave has been lied to. ## Deliberately out of scope @@ -422,7 +424,7 @@ None of those is blocked on a missing `libakgl` capability any more. Four were * [libakerror](https://source.starfort.tech/andrew/libakerror) 1.0.0 — TRY/CATCH-style error contexts. Every function that can fail returns one. * [libakstdlib](https://source.starfort.tech/andrew/libakstdlib) 0.1.0 — libc wrappers that report through `libakerror`. -* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.1.0 — **optional**, only for `-DAKBASIC_WITH_AKGL=ON`. Pulls in SDL3. +* [libakgl](https://source.starfort.tech/andrew/libakgl) 0.1.0 at commit `42b60f7` or later — **optional**, only for `-DAKBASIC_WITH_AKGL=ON`. Pulls in SDL3. The requirement is pinned by submodule commit rather than by version on purpose: 42b60f7 added 22 public symbols and left the version and the `libakgl.so.0.1` soname alone, so `AKGL_VERSION_AT_LEAST(0, 1, 0)` cannot tell the two trees apart. Filed upstream; `TODO.md` section 8 has the detail. * [basicinterpret](https://source.starfort.tech/andrew/basicinterpret) — the Go original, vendored as the behavioural spec and the acceptance corpus. Not linked, not built. Everything is a submodule; `git submodule update --init --recursive` gets all of it. There is nothing to install first. diff --git a/TODO.md b/TODO.md index 6058358..b432164 100644 --- a/TODO.md +++ b/TODO.md @@ -424,13 +424,18 @@ Order by what unblocks the most, and by what does not need `libakgl` to grow fir | B. Housekeeping | `NEW`, `CLR`, `CONT`, `RESTORE`, `RENUMBER`, `SWAP`, `TRON`, `TROFF`, `HELP` | nothing | | C. Errors | `TRAP`, `RESUME`, `ER`, `ERR` | needs a BASIC-visible error object | | D. Strings/format | `USING`, `PUDEF`, `WIDTH`, `CHAR` | nothing | -| E. Console | `GET`, `GETKEY`, `SCNCLR`, `LOCATE`, `WINDOW`, `KEY`, `SLEEP`, `WAIT`, `TI` | sink + `libakgl` input | +| E. Console | `GET`, `GETKEY`, `SCNCLR`, `WINDOW`, `KEY`, `SLEEP`, `WAIT`, `TI` | `GET`/`GETKEY`/`SCNCLR` nothing; the rest want the sink or a clock | | F. Disk | `DOPEN`, `DCLOSE`, `APPEND`, `RECORD`, `HEADER`, `COLLECT`, `BACKUP`, `COPY`, `CONCAT`, `RENAME`, `SCRATCH`, `DIRECTORY`, `CATALOG`, `DCLEAR`, `DVERIFY`, `SAVE`, `LOAD`, `VERIFY`, `BLOAD`, `BSAVE`, `BOOT` | `aksl_f*` only; no new akgl | -| G. Graphics | `GRAPHIC`, `DRAW`, `BOX`, `CIRCLE`, `PAINT`, `COLOR`, `SCALE`, `SSHAPE`, `GSHAPE`, `LOCATE` | **`libakgl` immediate-mode draw API — file it** | +| G. Graphics | `GRAPHIC`, `DRAW`, `BOX`, `CIRCLE`, `PAINT`, `COLOR`, `SCALE`, `SSHAPE`, `GSHAPE`, `LOCATE` | nothing — `akgl_draw_*` landed at 42b60f7 | | H. Sprites | `SPRITE`, `MOVSPR`, `SPRCOLOR`, `SPRDEF`, `SPRSAV`, `COLLISION` | `libakgl` sprite/actor API — check before filing | -| I. Audio | `PLAY`, `SOUND`, `ENVELOPE`, `FILTER`, `VOL`, `TEMPO` | **`libakgl` has no mixer-backed audio API — file it** | +| I. Audio | `PLAY`, `SOUND`, `ENVELOPE`, `VOL`, `TEMPO` | nothing — `akgl_audio_*` landed at 42b60f7 | +| I′. Audio, still gapped | `FILTER`, `SOUND`'s sweep arguments | `libakgl` has neither; see §7 | | J. Machine | `SYS`, `FETCH`, `STASH`, `POKE`/`PEEK` variants | nothing | +`LOCATE` used to appear in both E and G. It belongs to G alone: in BASIC 7.0 `LOCATE` moves the +*graphics* pixel cursor that `DRAW` starts from, and the text cursor verb is `CHAR`, which is +already in group D. + **Out of scope, and staying that way** — the reference marks these as incompatible with a modern PC and that reasoning stands: `BANK` (no bank switching), `FAST` (irrelevant CPU speed control), `MONITOR` (no machine-language monitor). @@ -627,8 +632,21 @@ Building against any of it needs `-DAKBASIC_WITH_AKGL=ON`, which pulls in `libak submodules (SDL and friends). Those are not initialized in a default clone; `git submodule update --init --recursive` gets them. -No gaps are currently outstanding. When the next one turns up, file it there rather than -working around it here. +**One gap is outstanding, and upstream named it itself.** The commit that added the audio API +says plainly what it does not cover: *"Still missing for a complete BASIC sound vocabulary: +`FILTER` (SDL3 has no filter primitive; this would need writing), `TEMPO` and the `PLAY` +note-string parser, both of which belong in the interpreter rather than here."* + +- **`TEMPO` and the `PLAY` parser are ours**, not a gap. They are group I work in this + repository and nothing upstream is waiting on. +- **`FILTER` is a real gap.** BASIC 7.0's `FILTER freq, lp, bp, hp, res` sets the SID's + filter cutoff, the three band-pass switches and the resonance. `akgl_audio_*` synthesises + raw waveforms and mixes them; there is no filter stage to configure and SDL3 supplies no + primitive to build one from. Until an `akgl_audio_filter()` exists, `FILTER` is accepted by + the parser and refused at execution with `AKBASIC_ERR_DEVICE` rather than silently ignored — + a program that asks for a low-pass and gets an unfiltered square wave has been lied to. + +When the next gap turns up, file it there rather than working around it here. --- @@ -659,7 +677,23 @@ Dependency baseline: |---|---|---| | `deps/libakerror` | 1.0.0 | Private ownership-enforced status registry. akbasic reserves 512–767 in `akbasic_error_register()`. Does not namespace its `coverage` target when embedded — worked around in our `CMakeLists.txt`. | | `deps/libakstdlib` | 0.1.0 | soname `libakstdlib.so.0.1`. `AKSL_VERSION_CHECK()` asserted in `tests/version_check.c`. Its `aksl_ato*` family is banned here — see §1.9. | -| `deps/libakgl` | 0.1.0 | Migrated to the 1.0.0 registry and owns 256–260. Not yet linked: `AKBASIC_WITH_AKGL` defaults OFF and `src/sink_akgl.c` does not exist. | +| `deps/libakgl` | 0.1.0, **pinned at commit 42b60f7** | Migrated to the 1.0.0 registry and owns 256–260. Not yet linked: `AKBASIC_WITH_AKGL` defaults OFF and `src/sink_akgl.c` does not exist. The version number cannot carry this requirement — see below. | + +**The `libakgl` requirement is pinned by commit, not by version, and that is a defect +upstream.** 42b60f7 added 22 public symbols across four headers — `akgl_draw_*` (8), +`akgl_audio_*` (10), `akgl_controller_poll_key`/`_flush_keys`, and `akgl_text_measure`/ +`_measure_wrapped` — and left `project(akgl VERSION 0.1.0)` and the `libakgl.so.0.1` soname +unchanged. By that repository's own stated rule, *"0.1 and 0.2 are different ABIs"*, this +should have been 0.2.0. Two consequences land here: + +- A binary compiled against the new headers links happily against an installed + `libakgl.so.0.1` built from the old tree, and fails at symbol resolution rather than at + configure time. +- `AKGL_VERSION_AT_LEAST(0, 1, 0)` is true for both trees, so nothing here can feature-test + for the new API. The submodule pointer is the only thing that expresses the requirement. + +Filed in `deps/libakgl/TODO.md`. When it is fixed, add the floor to the `find_package` call +and say so here. CI is split in two. `.gitea/workflows/ci.yaml` runs on push -- the suite, ASan+UBSan, coverage and a two-file mutation run -- and `.gitea/workflows/release.yaml` is manual