TuneC: a written tune becomes the bytes the player reads
The compiler, and the last thing the ladder was waiting for. A tune names
its instruments, writes sequences of notes and durations, and gives each
voice an order list of sequence names - which is where repetition comes
from, since a phrase played four times is written once and named four
times.
#Tick 0d125000
#Patch Oboe oboe.patch
#Voice 0d0 Oboe
#Sequence Verse
0d64 0d4 0d67 0d4 0d72 0d8
#Order 0d0
Verse Verse Ending
"#" is a directive and ";" is a comment, exactly as in SplitBit assembly
and in the shell's scripts, and numbers are written the way the assembler
writes them. One rule across the machine rather than a third dialect -
and the rule earned itself immediately: the first tune I wrote said
"#Voice 0" and was refused, correctly, for a bare number.
WHAT IT REFUSES IS EVERYTHING THE PLAYER CANNOT NOTICE. The machine has
no names, so it cannot say a sequence does not exist. It has no lengths,
so it cannot say the voices will come apart four bars after the mistake.
A duration of nought is counted down to 255 and held, which sounds like a
hang rather than an error. And by the time a tune is loaded, "no starting
instrument" and "instrument nought" are the same byte - so the user's
ruling, that a voice with a part and no instrument is an error, can only
be kept here.
SoundPatch gains --blob, writing the same table as raw bytes. It stays
the only thing that reads soundThing's JSON: a second program parsing
that format is a second opinion about what a patch means, and the seam
between two opinions is where the LFO bug lived for a fortnight. Patches
are found beside the tune and then on a -I path, the way an include is.
THE TEST IS THAT TWO IMPLEMENTATIONS AGREE. maketune.py lays the fixture
out by hand and TuneC compiles a written source, and the suite checks
they match byte for byte - the discipline SplitDisk and sbfs.asm are held
to, for the same reason: either alone is only self-consistent. The
fixture predates the compiler, so this is also TuneC checked against
something written before it existed. Four more checks cover the four
refusals.
Also: the SoundPatch binary was tracked, alone among the six tools, and
.gitignore lists every other one. Untracked, and TuneC added beside it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
bfc46d982e
commit
2808688fa1
@@ -37,7 +37,7 @@ Everything in between is somewhere on that line.
|
||||
make test
|
||||
```
|
||||
|
||||
Builds the five tools - and Voyager, where Raylib is installed - checks they compile under
|
||||
Builds the six tools - and Voyager, where Raylib is installed - checks they compile under
|
||||
strict ISO C, and runs the scripts in order. Takes a few seconds. Everything must pass; there are no expected failures at the
|
||||
level of the suite, only tests that record an expected failure of the assembler.
|
||||
|
||||
@@ -45,7 +45,7 @@ level of the suite, only tests that record an expected failure of the assembler.
|
||||
make sanitize
|
||||
```
|
||||
|
||||
The same suite with the five tools rebuilt under AddressSanitizer and
|
||||
The same suite with the six tools rebuilt under AddressSanitizer and
|
||||
UndefinedBehaviorSanitizer. See [The Sanitizer Run](#the-sanitizer-run).
|
||||
|
||||
Individual scripts can be run on their own, from anywhere:
|
||||
@@ -540,7 +540,7 @@ which stops the markers outliving the code they were about.
|
||||
make sanitize
|
||||
```
|
||||
|
||||
Rebuilds all five tools with `-fsanitize=address,undefined` and runs **the whole suite**
|
||||
Rebuilds all six tools with `-fsanitize=address,undefined` and runs **the whole suite**
|
||||
under them. What it reliably catches is invalid access: reads and writes off the end of an
|
||||
array, use after free, leaks, and arithmetic the standard does not define.
|
||||
|
||||
@@ -552,7 +552,7 @@ deliberate `calloc`. The machine's Program and Data memories are static arrays,
|
||||
sanitizers neither fill nor bound-check - which is the same fact, seen from a
|
||||
different side, as the overrun blind spot below.
|
||||
|
||||
It runs everything because it used to not. It built all five tools sanitized and then ran
|
||||
It runs everything because it used to not. It built all six tools sanitized and then ran
|
||||
only `run.sh` and `terminal.sh`, so SplitDisk was compiled with the sanitizers and never
|
||||
exercised, and `native.sh` - which drives the assembler and the emulator harder than
|
||||
anything else here - was skipped entirely. Those are exactly where block arithmetic on disk
|
||||
|
||||
Reference in New Issue
Block a user