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