diff --git a/.gitignore b/.gitignore
index 3e97566..129c0a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,10 @@
/Voyager
/SoundPatch
/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
/claudeResume.sh
/codexResume.sh
diff --git a/Programs/Tunes/splash.tune.txt b/Programs/Tunes/splash.score
similarity index 100%
rename from Programs/Tunes/splash.tune.txt
rename to Programs/Tunes/splash.score
diff --git a/Programs/Tunes/two.tune.txt b/Programs/Tunes/two.score
similarity index 98%
rename from Programs/Tunes/two.tune.txt
rename to Programs/Tunes/two.score
index f966407..79b2185 100644
--- a/Programs/Tunes/two.tune.txt
+++ b/Programs/Tunes/two.score
@@ -1,4 +1,4 @@
-; two.tune.txt
+; two.score
; The smallest thing that is a tune: one voice, two sequences, and an instrument change.
; Written by Anachronaut
;
diff --git a/README.md b/README.md
index 1a3fcbe..633ceee 100644
--- a/README.md
+++ b/README.md
@@ -310,7 +310,7 @@ Without `-o` the output takes the source file's name, in the directory you calle
## Writing A Tune: TuneC
```
-./TuneC [-I
]
+./TuneC [-I ]
```
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.
-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.
diff --git a/Source/Tune/TuneC.c b/Source/Tune/TuneC.c
index bf82390..84c7e84 100644
--- a/Source/Tune/TuneC.c
+++ b/Source/Tune/TuneC.c
@@ -17,6 +17,10 @@
// 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.
//
+// 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.
// #Tick 0d125000 ; cycles a tick: a sixteenth note at 120 beats a minute
// #Patch Oboe oboe.patch
@@ -440,7 +444,7 @@ int main(int argc, char **argv) {
}
if (argc < 3) {
fprintf(stderr,
- "Usage: %s [-I ] \n\n"
+ "Usage: %s [-I ] \n\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"
"Patches come from SoundPatch --blob, which is the only thing that knows what a\n"
diff --git a/SplitBit Tune Manual.md b/SplitBit Tune Manual.md
index e5609eb..468aee7 100644
--- a/SplitBit Tune Manual.md
+++ b/SplitBit Tune Manual.md
@@ -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
-./TuneC [-I ] theme.tune.txt theme.tune
+./TuneC [-I ] theme.score 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.
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.
diff --git a/Tests/makedisks.sh b/Tests/makedisks.sh
index 6edce52..9ac5087 100755
--- a/Tests/makedisks.sh
+++ b/Tests/makedisks.sh
@@ -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
# there, the way it treats /lander.state.
"$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
# 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[2], "wb").write(blob(129))
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
# 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.
-sed 's/#Tick 0d125000/#Tick 0d250000/' "$ROOT/Programs/Tunes/two.tune.txt" > "$WORK/slow.tune.txt"
-"$ROOT/TuneC" -I "$WORK" "$WORK/slow.tune.txt" "$WORK/slow.tune" >/dev/null
+sed 's/#Tick 0d125000/#Tick 0d250000/' "$ROOT/Programs/Tunes/two.score" > "$WORK/slow.score"
+"$ROOT/TuneC" -I "$WORK" "$WORK/slow.score" "$WORK/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" \
-I "$ROOT/Programs/CosmOS/Source" \
diff --git a/Tests/sound.sh b/Tests/sound.sh
index 740cf8f..fd08289 100755
--- a/Tests/sound.sh
+++ b/Tests/sound.sh
@@ -865,9 +865,9 @@ PY2
refuses() {
# refuses ...
local want="$1"; shift
- printf '%s\n' "$@" > "$BUILD/bad.tune.txt"
+ printf '%s\n' "$@" > "$BUILD/bad.score"
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)"
if [ -f "$BUILD/bad.tune" ]; then rm -f "$BUILD/bad.tune"; fi
case "$said" in
@@ -893,8 +893,8 @@ PY2
printf '%s\n' "#Tick 0d125000" "#Patch A nosuch.patch" \
"#Voice 0d0 A" "#Voice 0d1 A" "#Voice 0d2 A" \
"#Sequence S" "0d60 0d4" \
- "#Order 0d0" "S" "#Order 0d1" "S" "#Order 0d2" "S" > "$BUILD/cascade.tune.txt"
- SAID="$("$ROOT/TuneC" "$BUILD/cascade.tune.txt" "$BUILD/cascade.tune" 2>&1 \
+ "#Order 0d0" "S" "#Order 0d1" "S" "#Order 0d2" "S" > "$BUILD/cascade.score"
+ SAID="$("$ROOT/TuneC" "$BUILD/cascade.score" "$BUILD/cascade.tune" 2>&1 \
| grep -c "cannot find\|no patch of that name\|no instrument")"
[ "$SAID" = "1" ] \
&& result ok "TuneC says a missing patch once" "one message, not one for every use of it" \
diff --git a/makefile b/makefile
index ab309be..5adfec1 100644
--- a/makefile
+++ b/makefile
@@ -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
# read the way the shell would.
ASM_RUN = ./$(ASM_TARGET)
+PATCH_RUN = ./$(PATCH_TARGET)
+TUNE_RUN = ./$(TUNE_TARGET)
EMU_RUN = ./$(EMU_TARGET)
VOY_RUN = ./$(VOY_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)
# 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): $(APPS) $(NATIVE_ASM) $(COSMOS) $(STAGE2) \
$(PROG_DIR)/testPrograms/stringKeyword.asm \
$(wildcard $(PROG_DIR)/CosmOS/Apps/*.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)
rm -f $@
@# 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 \
$(DISKTOOL) put $@ $$app /Apps/`basename $$app` >/dev/null || exit 1; done
$(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 ----
@#
@# MIRRORED RATHER THAN LISTED. A list in a makefile goes stale the moment somebody