The player speaks indices, which is the shape a file has to be
Order lists hold one-byte sequence indices and 0x80 holds a one-byte patch index. Two tables, PatchTable and SequenceTable, are the only places an address lives. THAT IS WHAT MAKES A TUNE LOADABLE WITHOUT WALKING IT. Nothing inside a sequence or an order list is an address, so putting one in memory means adding the load address to two arrays and nothing else. The alternative is a loader that parses every sequence looking for addresses to correct, which is a loader a malformed file can walk off a cliff. Doing it now, while the tune is still assembled in, means the file form and the assembled form are the same shape - so reading a tune from a file will change no engine code at all. The whole point of the rung. The patch each voice starts on moved from four calls in a row into VoiceStart, four declared bytes, and loadStartPatches reads them. A starting instrument is state and belongs where state goes: the user's ruling is that a voice with undefined state is an error, prompted by noticing that a program run a second time starts with the memory the first run left, because loading is what initialises and running is not. Order lists also halved in size, which was not the reason but is welcome. Hand-writing the two tables is exactly the tedium the compiler exists to remove - every sequence counted into its place, and moving one means renumbering. Better to feel that here than after a tool has baked the shape in. Verified by rendering: bar for bar the same piece. break.sh confirms the scaling, since an index is doubled to reach a two-byte entry and halving that step lands on the wrong sequence and fails four checks. 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
8029063bdc
commit
5d9b39514b
@@ -90,8 +90,13 @@ start:
|
||||
; ---- An instrument for each voice ----
|
||||
;
|
||||
; Four patches, designed in soundThing and converted by SoundPatch, which is the only thing
|
||||
; here that understands what a patch means. This reads a count and that many parameter and
|
||||
; value pairs and knows nothing else about them.
|
||||
; here that understands what a patch means. The player reads a count and that many parameter
|
||||
; and value pairs and knows nothing else about them.
|
||||
;
|
||||
; WHICH PATCH EACH VOICE STARTS ON IS DECLARED, in VoiceStart below, rather than being four
|
||||
; calls in a row here. That is the shape a tune read from a file will have - a starting
|
||||
; instrument is state and belongs in a header - and saying it once means the two forms do
|
||||
; not drift.
|
||||
;
|
||||
; A PATCH BELONGS TO ITS CHANNEL, which is why four of them can be up at once. It did not
|
||||
; used to: the LFOs belonged to the whole device, so whichever patch was loaded last owned
|
||||
@@ -99,18 +104,7 @@ start:
|
||||
; under the old device this piece would have played with the arpeggio's setting on all four
|
||||
; parts - which is exactly the fault that made Lunar Porter's low fuel warning stop
|
||||
; trilling after the first landing of a run.
|
||||
SETD.0 OboePatch
|
||||
RSTA
|
||||
CALL loadPatch ; The melody sings, so it is the one with a voice.
|
||||
SETD.0 StringsPatch
|
||||
INIA 0d1
|
||||
CALL loadPatch ; A pad underneath it.
|
||||
SETD.0 SquarePatch
|
||||
INIA 0d2
|
||||
CALL loadPatch ; And a square wave for the bass, which is where one belongs.
|
||||
SETD.0 KalimbaPatch
|
||||
INIA 0d3
|
||||
CALL loadPatch ; Plucked, for the arpeggio.
|
||||
CALL loadStartPatches
|
||||
|
||||
INIA 0x60 ; Room over the top for four voices at once.
|
||||
OUTA 0x46
|
||||
@@ -208,13 +202,32 @@ tick:
|
||||
; order list, and it is worth noticing how little it cost: a table of labels the assembler
|
||||
; fills in, and ten instructions in stepVoice.
|
||||
Order0:
|
||||
Mel1 Mel2 Mel3 Mel4 0xFF 0xFF
|
||||
0d0 0d1 0d2 0d3 0xFF
|
||||
Order1:
|
||||
Har1 Har2 Har3 Har4 0xFF 0xFF
|
||||
0d4 0d5 0d6 0d7 0xFF
|
||||
Order2:
|
||||
BassC BassF BassG BassC 0xFF 0xFF
|
||||
0d8 0d9 0d10 0d8 0xFF ; BassC twice, written once.
|
||||
Order3:
|
||||
ArpC ArpF ArpG Silent 0xFF 0xFF
|
||||
0d11 0d12 0d13 0d14 0xFF
|
||||
|
||||
; ---- The tables, which are the only places an address lives ----
|
||||
;
|
||||
; Writing these out by hand is exactly the tedium a compiler exists to remove: every sequence
|
||||
; has to be counted into its place above, and moving one means renumbering. That it is
|
||||
; unpleasant is the point of noticing it here rather than after a tool has baked the shape in.
|
||||
PatchTable:
|
||||
OboePatch StringsPatch SquarePatch KalimbaPatch
|
||||
|
||||
SequenceTable:
|
||||
Mel1 Mel2 Mel3 Mel4 ; 0 to 3
|
||||
Har1 Har2 Har3 Har4 ; 4 to 7
|
||||
BassC BassF BassG ; 8 to 10
|
||||
ArpC ArpF ArpG Silent ; 11 to 14
|
||||
|
||||
; The patch each voice starts on. Not assumed, and not four calls in a row: a starting
|
||||
; instrument is state, and state belongs somewhere it can be read.
|
||||
VoiceStart:
|
||||
0d0 0d1 0d2 0d3
|
||||
|
||||
; ---- Four bars of C, F, G, C ----
|
||||
;
|
||||
@@ -239,7 +252,7 @@ Mel3:
|
||||
0d71 0d8 ; B
|
||||
0xFF
|
||||
Mel4:
|
||||
0x80 StringsPatch ; The last bar is a swell rather than a reed.
|
||||
0x80 0d1 ; Patch one is Strings: the last bar is a swell, not a reed.
|
||||
0d72 0d16 ; and home
|
||||
0xFF
|
||||
|
||||
|
||||
Reference in New Issue
Block a user