A score is written and a tune is what the machine reads
The convention, at the user's asking, and it is the one this project already has everywhere else: a .asm is written and a .sbx or a .bin is what the machine loads. A .score and a .tune are the same pair one subject along. It is not only tidiness. I read the user's splash.tune as a compiled tune yesterday, dumped its header, and got a tick of seven and a half million cycles and ninety seven patches out of what was plainly a text file. Different names make that a thing nobody has to notice. AND THE SPLASH WAS SILENT ON THE DISK THAT MATTERS. The play disk mirrors every .asm and puts every app, and nothing on it put a compiled tune - so make run-cosmos and make run-voyager both booted a Lander that read /splash.tune, did not find one, and held the logo in silence. Only the test disk had it, because I had added it there and stopped. The makefile now compiles Programs/Tunes/splash.score with TuneC and puts the result on the disk, and the mirror's prerequisite list learned about .score files so that changing the music rebuilds the disk. That is the same failure the mirror was built for, in a file type the mirror did not know about yet: tune.asm went into Examples once, the image was not remade, and it was simply not there. Measured on the real disk: music from 0.9 s to 9.6 s. 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
00b31b88af
commit
dfc9d9ef7f
@@ -11,6 +11,10 @@
|
|||||||
/Voyager
|
/Voyager
|
||||||
/SoundPatch
|
/SoundPatch
|
||||||
/TuneC
|
/TuneC
|
||||||
|
|
||||||
|
# A .score is written and a .tune is what TuneC makes of it, so a .tune is a build product
|
||||||
|
# the way a .sbx is. Not anchored: they turn up wherever somebody is composing.
|
||||||
|
*.tune
|
||||||
/CLAUDE.md
|
/CLAUDE.md
|
||||||
/claudeResume.sh
|
/claudeResume.sh
|
||||||
/codexResume.sh
|
/codexResume.sh
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
; two.tune.txt
|
; two.score
|
||||||
; The smallest thing that is a tune: one voice, two sequences, and an instrument change.
|
; The smallest thing that is a tune: one voice, two sequences, and an instrument change.
|
||||||
; Written by Anachronaut
|
; Written by Anachronaut
|
||||||
;
|
;
|
||||||
@@ -310,7 +310,7 @@ Without `-o` the output takes the source file's name, in the directory you calle
|
|||||||
## Writing A Tune: TuneC
|
## Writing A Tune: TuneC
|
||||||
|
|
||||||
```
|
```
|
||||||
./TuneC [-I <dir>] <tune> <output.tune>
|
./TuneC [-I <dir>] <tune.score> <output.tune>
|
||||||
```
|
```
|
||||||
|
|
||||||
Four voices on one clock. 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.
|
Four voices on one clock. 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.
|
||||||
@@ -335,7 +335,7 @@ Four voices on one clock. A tune names its instruments, writes sequences of note
|
|||||||
|
|
||||||
`#` 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 - `0d` and `0x`, and no bare numbers. One rule across the machine rather than a third dialect.
|
`#` 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 - `0d` and `0x`, and no bare numbers. One rule across the machine rather than a third dialect.
|
||||||
|
|
||||||
Patches come from `SoundPatch --blob`, which stays the only thing that understands what a soundThing patch means, and are looked for beside the tune and then on the `-I` path the way an include is.
|
A `.score` is written and a `.tune` is what the machine reads, the same way a `.asm` is written and a `.sbx` is loaded. Patches come from `SoundPatch --blob`, which stays the only thing that understands what a soundThing patch means, and are looked for beside the tune and then on the `-I` path the way an include is.
|
||||||
|
|
||||||
**What it refuses is everything the player cannot notice for itself.** 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; and a duration of nought is counted down to 255 and held, which sounds like a hang rather than an error. A voice with a part and no instrument is refused too, because by the time a tune is loaded, "never said" and "instrument nought" are the same byte.
|
**What it refuses is everything the player cannot notice for itself.** 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; and a duration of nought is counted down to 255 and held, which sounds like a hang rather than an error. A voice with a part and no instrument is refused too, because by the time a tune is loaded, "never said" and "instrument nought" are the same byte.
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -17,6 +17,10 @@
|
|||||||
// the way the assembler writes them: 0d for decimal and 0x for hexadecimal, with no bare
|
// the way the assembler writes them: 0d for decimal and 0x for hexadecimal, with no bare
|
||||||
// numbers, so that a person reading a tune is reading something they already know.
|
// numbers, so that a person reading a tune is reading something they already know.
|
||||||
//
|
//
|
||||||
|
// A .score is what somebody writes and a .tune is what the machine reads, the same way a
|
||||||
|
// .asm is written and a .sbx is loaded. Handing a player a source is then a mistake it can
|
||||||
|
// name rather than one it has to guess at.
|
||||||
|
//
|
||||||
// ; Four bars, and the bass is the same one under two of them.
|
// ; Four bars, and the bass is the same one under two of them.
|
||||||
// #Tick 0d125000 ; cycles a tick: a sixteenth note at 120 beats a minute
|
// #Tick 0d125000 ; cycles a tick: a sixteenth note at 120 beats a minute
|
||||||
// #Patch Oboe oboe.patch
|
// #Patch Oboe oboe.patch
|
||||||
@@ -440,7 +444,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [-I <dir>] <tune> <output.tune>\n\n"
|
"Usage: %s [-I <dir>] <tune.score> <output.tune>\n\n"
|
||||||
"Turns a written tune into the bytes SplitBit's player reads: a header, a table\n"
|
"Turns a written tune into the bytes SplitBit's player reads: a header, a table\n"
|
||||||
"of patches, a table of sequences, and an order list for each of four voices.\n\n"
|
"of patches, a table of sequences, and an order list for each of four voices.\n\n"
|
||||||
"Patches come from SoundPatch --blob, which is the only thing that knows what a\n"
|
"Patches come from SoundPatch --blob, which is the only thing that knows what a\n"
|
||||||
|
|||||||
@@ -99,10 +99,12 @@ Nothing is written when anything is refused, so a failed build cannot leave a ha
|
|||||||
|
|
||||||
```
|
```
|
||||||
./SoundPatch --blob Programs/Sounds/Oboe.json Oboe oboe.patch
|
./SoundPatch --blob Programs/Sounds/Oboe.json Oboe oboe.patch
|
||||||
./TuneC [-I <dir>] theme.tune.txt theme.tune
|
./TuneC [-I <dir>] theme.score theme.tune
|
||||||
./SplitDisk put mydisk.img theme.tune
|
./SplitDisk put mydisk.img theme.tune
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**A `.score` is written and a `.tune` is what the machine reads**, the same way a `.asm` is written and a `.sbx` or a `.bin` is what it loads. One is a source and the other is bytes, and giving them different names means never wondering which a file is - or handing a player a source and being told, correctly, that it is not a tune.
|
||||||
|
|
||||||
Then `Play theme.tune` on the machine.
|
Then `Play theme.tune` on the machine.
|
||||||
|
|
||||||
Patches are looked for beside the tune first and then on the `-I` path, the way the assembler looks for an include - so a tune can name its instruments by bare name and travel with them.
|
Patches are looked for beside the tune first and then on the `-I` path, the way the assembler looks for an include - so a tune can name its instruments by bare name and travel with them.
|
||||||
|
|||||||
+4
-4
@@ -180,7 +180,7 @@ printf '#! script\nfor a in 1 2\n for b in x y\n echo $a$b\n end\nend\nset
|
|||||||
# touching the game. Lander reads it off the disk at startup and starts anyway if it is not
|
# touching the game. Lander reads it off the disk at startup and starts anyway if it is not
|
||||||
# there, the way it treats /lander.state.
|
# there, the way it treats /lander.state.
|
||||||
"$ROOT/SoundPatch" --blob "$ROOT/Programs/Sounds/Oboe.json" Oboe "$WORK/oboe.patch" >/dev/null
|
"$ROOT/SoundPatch" --blob "$ROOT/Programs/Sounds/Oboe.json" Oboe "$WORK/oboe.patch" >/dev/null
|
||||||
"$ROOT/TuneC" -I "$WORK" "$ROOT/Programs/Tunes/splash.tune.txt" "$WORK/splash.tune" >/dev/null
|
"$ROOT/TuneC" -I "$WORK" "$ROOT/Programs/Tunes/splash.score" "$WORK/splash.tune" >/dev/null
|
||||||
"$TOOL" put "$DISKS/cosmos.img" "$WORK/splash.tune" splash.tune >/dev/null
|
"$TOOL" put "$DISKS/cosmos.img" "$WORK/splash.tune" splash.tune >/dev/null
|
||||||
|
|
||||||
# tune.sbx, which used to be a boot image and is now a program like any other. It brings a
|
# tune.sbx, which used to be a boot image and is now a program like any other. It brings a
|
||||||
@@ -744,13 +744,13 @@ def blob(octave):
|
|||||||
open(sys.argv[1], "wb").write(blob(128))
|
open(sys.argv[1], "wb").write(blob(128))
|
||||||
open(sys.argv[2], "wb").write(blob(129))
|
open(sys.argv[2], "wb").write(blob(129))
|
||||||
FIXTURE
|
FIXTURE
|
||||||
"$ROOT/TuneC" -I "$WORK" "$ROOT/Programs/Tunes/two.tune.txt" "$WORK/compiled.tune" >/dev/null
|
"$ROOT/TuneC" -I "$WORK" "$ROOT/Programs/Tunes/two.score" "$WORK/compiled.tune" >/dev/null
|
||||||
|
|
||||||
# The same tune at half the speed. A TICK BELONGS TO THE TUNE, and the only reason nothing
|
# The same tune at half the speed. A TICK BELONGS TO THE TUNE, and the only reason nothing
|
||||||
# noticed that Play was ignoring it was that every fixture asked for the tick Play happened to
|
# noticed that Play was ignoring it was that every fixture asked for the tick Play happened to
|
||||||
# have written into itself. One that asks for something else is the whole check.
|
# have written into itself. One that asks for something else is the whole check.
|
||||||
sed 's/#Tick 0d125000/#Tick 0d250000/' "$ROOT/Programs/Tunes/two.tune.txt" > "$WORK/slow.tune.txt"
|
sed 's/#Tick 0d125000/#Tick 0d250000/' "$ROOT/Programs/Tunes/two.score" > "$WORK/slow.score"
|
||||||
"$ROOT/TuneC" -I "$WORK" "$WORK/slow.tune.txt" "$WORK/slow.tune" >/dev/null
|
"$ROOT/TuneC" -I "$WORK" "$WORK/slow.score" "$WORK/slow.tune" >/dev/null
|
||||||
"$TOOL" put "$DISKS/quiet.img" "$WORK/slow.tune" slow.tune >/dev/null
|
"$TOOL" put "$DISKS/quiet.img" "$WORK/slow.tune" slow.tune >/dev/null
|
||||||
"$ROOT/Assembler" -I "$ROOT/Programs/Sounds" -I "$ROOT/Programs/Libraries" \
|
"$ROOT/Assembler" -I "$ROOT/Programs/Sounds" -I "$ROOT/Programs/Libraries" \
|
||||||
-I "$ROOT/Programs/CosmOS/Source" \
|
-I "$ROOT/Programs/CosmOS/Source" \
|
||||||
|
|||||||
+4
-4
@@ -865,9 +865,9 @@ PY2
|
|||||||
refuses() {
|
refuses() {
|
||||||
# refuses <what it should say> <line>...
|
# refuses <what it should say> <line>...
|
||||||
local want="$1"; shift
|
local want="$1"; shift
|
||||||
printf '%s\n' "$@" > "$BUILD/bad.tune.txt"
|
printf '%s\n' "$@" > "$BUILD/bad.score"
|
||||||
local said
|
local said
|
||||||
said="$("$ROOT/TuneC" -I "$ROOT/Tests/build/.diskwork" "$BUILD/bad.tune.txt" \
|
said="$("$ROOT/TuneC" -I "$ROOT/Tests/build/.diskwork" "$BUILD/bad.score" \
|
||||||
"$BUILD/bad.tune" 2>&1)"
|
"$BUILD/bad.tune" 2>&1)"
|
||||||
if [ -f "$BUILD/bad.tune" ]; then rm -f "$BUILD/bad.tune"; fi
|
if [ -f "$BUILD/bad.tune" ]; then rm -f "$BUILD/bad.tune"; fi
|
||||||
case "$said" in
|
case "$said" in
|
||||||
@@ -893,8 +893,8 @@ PY2
|
|||||||
printf '%s\n' "#Tick 0d125000" "#Patch A nosuch.patch" \
|
printf '%s\n' "#Tick 0d125000" "#Patch A nosuch.patch" \
|
||||||
"#Voice 0d0 A" "#Voice 0d1 A" "#Voice 0d2 A" \
|
"#Voice 0d0 A" "#Voice 0d1 A" "#Voice 0d2 A" \
|
||||||
"#Sequence S" "0d60 0d4" \
|
"#Sequence S" "0d60 0d4" \
|
||||||
"#Order 0d0" "S" "#Order 0d1" "S" "#Order 0d2" "S" > "$BUILD/cascade.tune.txt"
|
"#Order 0d0" "S" "#Order 0d1" "S" "#Order 0d2" "S" > "$BUILD/cascade.score"
|
||||||
SAID="$("$ROOT/TuneC" "$BUILD/cascade.tune.txt" "$BUILD/cascade.tune" 2>&1 \
|
SAID="$("$ROOT/TuneC" "$BUILD/cascade.score" "$BUILD/cascade.tune" 2>&1 \
|
||||||
| grep -c "cannot find\|no patch of that name\|no instrument")"
|
| grep -c "cannot find\|no patch of that name\|no instrument")"
|
||||||
[ "$SAID" = "1" ] \
|
[ "$SAID" = "1" ] \
|
||||||
&& result ok "TuneC says a missing patch once" "one message, not one for every use of it" \
|
&& result ok "TuneC says a missing patch once" "one message, not one for every use of it" \
|
||||||
|
|||||||
@@ -149,6 +149,8 @@ PROG_BUILD = $(PROG_DIR)/build
|
|||||||
# The tools, as commands. Built by the rules above, and named here so the assembly rules
|
# The tools, as commands. Built by the rules above, and named here so the assembly rules
|
||||||
# read the way the shell would.
|
# read the way the shell would.
|
||||||
ASM_RUN = ./$(ASM_TARGET)
|
ASM_RUN = ./$(ASM_TARGET)
|
||||||
|
PATCH_RUN = ./$(PATCH_TARGET)
|
||||||
|
TUNE_RUN = ./$(TUNE_TARGET)
|
||||||
EMU_RUN = ./$(EMU_TARGET)
|
EMU_RUN = ./$(EMU_TARGET)
|
||||||
VOY_RUN = ./$(VOY_TARGET)
|
VOY_RUN = ./$(VOY_TARGET)
|
||||||
DISKTOOL = ./$(DSK_TARGET)
|
DISKTOOL = ./$(DSK_TARGET)
|
||||||
@@ -583,13 +585,14 @@ $(COSMOS_DISK): makefile
|
|||||||
#
|
#
|
||||||
# Found rather than wildcarded, because the tree the mirror walks is a tree and $(wildcard)
|
# Found rather than wildcarded, because the tree the mirror walks is a tree and $(wildcard)
|
||||||
# does not recurse. build is left out for the reason the mirror leaves it out.
|
# does not recurse. build is left out for the reason the mirror leaves it out.
|
||||||
MIRRORED := $(shell find $(PROG_DIR) -name '*.asm' -not -path '$(PROG_BUILD)/*' 2>/dev/null)
|
MIRRORED := $(shell find $(PROG_DIR) \( -name '*.asm' -o -name '*.score' \) -not -path '$(PROG_BUILD)/*' 2>/dev/null)
|
||||||
$(COSMOS_DISK): $(MIRRORED)
|
$(COSMOS_DISK): $(MIRRORED)
|
||||||
$(COSMOS_DISK): $(APPS) $(NATIVE_ASM) $(COSMOS) $(STAGE2) \
|
$(COSMOS_DISK): $(APPS) $(NATIVE_ASM) $(COSMOS) $(STAGE2) \
|
||||||
$(PROG_DIR)/testPrograms/stringKeyword.asm \
|
$(PROG_DIR)/testPrograms/stringKeyword.asm \
|
||||||
$(wildcard $(PROG_DIR)/CosmOS/Apps/*.asm) \
|
$(wildcard $(PROG_DIR)/CosmOS/Apps/*.asm) \
|
||||||
$(wildcard $(PROG_DIR)/CosmOS/Source/*.asm) \
|
$(wildcard $(PROG_DIR)/CosmOS/Source/*.asm) \
|
||||||
$(wildcard $(PROG_DIR)/CosmOS/Assembler/*.asm) | $(DSK_TARGET)
|
$(wildcard $(PROG_DIR)/CosmOS/Assembler/*.asm) \
|
||||||
|
| $(DSK_TARGET) $(PATCH_TARGET) $(TUNE_TARGET)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
rm -f $@
|
rm -f $@
|
||||||
@# A BOOT AREA, so that this is a disk the machine can start itself from rather than
|
@# A BOOT AREA, so that this is a disk the machine can start itself from rather than
|
||||||
@@ -630,6 +633,17 @@ $(COSMOS_DISK): $(APPS) $(NATIVE_ASM) $(COSMOS) $(STAGE2) \
|
|||||||
@for app in $(APPS); do \
|
@for app in $(APPS); do \
|
||||||
$(DISKTOOL) put $@ $$app /Apps/`basename $$app` >/dev/null || exit 1; done
|
$(DISKTOOL) put $@ $$app /Apps/`basename $$app` >/dev/null || exit 1; done
|
||||||
$(DISKTOOL) put $@ $(NATIVE_ASM) /Apps/Asm.sbx
|
$(DISKTOOL) put $@ $(NATIVE_ASM) /Apps/Asm.sbx
|
||||||
|
@# ---- And the music, compiled ----
|
||||||
|
@#
|
||||||
|
@# A .score is written and a .tune is what the machine reads, the same way a .asm is
|
||||||
|
@# written and a .sbx is what it loads. The patches come from SoundPatch, which stays the
|
||||||
|
@# only thing that knows what a soundThing patch means; TuneC embeds the bytes and knows
|
||||||
|
@# nothing about them.
|
||||||
|
@mkdir -p $(PROG_BUILD)/tunes
|
||||||
|
$(PATCH_RUN) --blob $(PROG_DIR)/Sounds/Oboe.json Oboe $(PROG_BUILD)/tunes/oboe.patch
|
||||||
|
$(TUNE_RUN) -I $(PROG_BUILD)/tunes $(PROG_DIR)/Tunes/splash.score \
|
||||||
|
$(PROG_BUILD)/tunes/splash.tune
|
||||||
|
$(DISKTOOL) put $@ $(PROG_BUILD)/tunes/splash.tune splash.tune
|
||||||
@# ---- What you assemble: all of it ----
|
@# ---- What you assemble: all of it ----
|
||||||
@#
|
@#
|
||||||
@# MIRRORED RATHER THAN LISTED. A list in a makefile goes stale the moment somebody
|
@# MIRRORED RATHER THAN LISTED. A list in a makefile goes stale the moment somebody
|
||||||
|
|||||||
Reference in New Issue
Block a user