M1: the tune keeps a beat it sets, instead of one it borrowed
tune.asm counted the screen's frames, because until 6b51d63 the frame
was the only regular beat on the machine. It is now driven by the timer.
THE DURATIONS ARE NOT A CONVERSION OF THE OLD ONES. A frame is 16,667
cycles, so a sixteenth note at 120 beats a minute is seven and a half of
them and could not be asked for at all: the arpeggio was written as
seven whole frames, which is six and a half per cent fast, and the rest
of the piece was written to a tempo picked so its subdivisions landed on
whole frames. The tick is now 125,000 cycles, which IS that sixteenth
note, and the durations are what the music wanted in the first place -
an eighth is two ticks, a quarter four, the arpeggio one each.
The player's loop did not change shape: a note table, a wait on each
beat, the gate dropped at the end. Only what it waits on. The handler
stays a bare RETI, because taking the interrupt is what brings the line
down - a program that POLLED the timer would have to read 0x50, and the
comment now says so, since that is the trap.
Three checks in sound.sh, on a program that is the player's loop rather
than the tune: eight ticks last eight periods to within a tenth of a per
cent, and the seventh and eighth notes are measured where the ticks put
them. The middle one is the one that fails on the old timing - at seven
whole frames the boundary slides under the window and it reads 384 Hz,
which is neither note and is what a crossing counter says when given
two. Verified with break.sh by moving the timer's period a byte.
tune.sbx grew 306 -> 318 bytes, which is why ten cosmos recordings moved:
they quote a directory listing. Nothing else in them changed.
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
35c6708e46
commit
1b251fb290
@@ -31,7 +31,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -21,7 +21,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -38,7 +38,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -28,7 +28,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -28,7 +28,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -114,7 +114,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -33,7 +33,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -21,7 +21,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -19,7 +19,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -28,7 +28,7 @@ Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
tune.sbx 318
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
|
||||
@@ -578,6 +578,72 @@ EOT
|
||||
&& result ok "and its own channel's patch does take it away" "$FIRST became $THIRD, which is the note itself" \
|
||||
|| result no "and its own channel's patch does take it away" "$FIRST then $THIRD"
|
||||
|
||||
# ---- A tune keeps the timer's beat, not the screen's ----
|
||||
#
|
||||
# M1 of the music player. The sound device knows how to make a note and nothing about when;
|
||||
# the timer is the other half. What is checked here is that a note's LENGTH is the period that
|
||||
# was asked for - which is the one claim a program timing music on frames cannot make.
|
||||
#
|
||||
# 125,000 cycles is a sixteenth note at 120 beats a minute, and a frame is 16,667: seven and a
|
||||
# half of them. It could not be asked for at all until the timer existed, and Examples/tune.asm
|
||||
# spent years writing its arpeggio as seven whole frames instead, six and a half per cent fast.
|
||||
#
|
||||
# THE PROGRAM IS THE PLAYER'S LOOP, deliberately: a note table walked by a pointer, a wait on
|
||||
# each tick, the gate dropped at the end. Eight notes of one tick each, seven of them middle C
|
||||
# and the last an octave up, so where the boundary between them falls can be MEASURED rather
|
||||
# than assumed.
|
||||
{ printf '#Program\nstart:\n'
|
||||
port 0x41 0x00
|
||||
param 0x00 0x02 # Saw, which has edges enough to count
|
||||
param 0x01 0xFF # at full gain
|
||||
param 0x05 0x01 # and switched on.
|
||||
param 0x20 0x00 # No attack, no decay, held at full: a note lasts its whole tick
|
||||
param 0x21 0x00 # and stops when the gate drops, rather than fading on its own -
|
||||
param 0x22 0xFF # which is what makes the boundary a thing a counter can find.
|
||||
param 0x23 0x05
|
||||
port 0x46 0xC0
|
||||
port 0x52 0x01
|
||||
port 0x53 0xE8
|
||||
port 0x54 0x48 # 0x01E848, which is 125,000 cycles: 6,000 samples.
|
||||
port 0x51 0x07 # Run, repeat, interrupt.
|
||||
printf ' SIF\n'
|
||||
printf ' SETD.0 Notes\nnextNote:\n LDA.0\n BRA done\n OUTA 0x44\n INCD.0\n'
|
||||
printf ' LDB.0\n INCD.0\nhold:\n WAIT\n DECB\n BNB hold\n'
|
||||
printf ' RSTA\n OUTA 0x45\n BRI nextNote\ndone:\n CIF\n RSTA\n OUTA 0x51\n HALT\n'
|
||||
printf 'tick:\n RETI\n'
|
||||
printf '#Data\nNotes:\n'
|
||||
printf ' 0d60 0d1\n 0d60 0d1\n 0d60 0d1\n 0d60 0d1\n'
|
||||
printf ' 0d60 0d1\n 0d60 0d1\n 0d60 0d1\n 0d72 0d1\n 0x00\n'
|
||||
printf '#Vectors\n Boot start\n Device 0x50 tick\n'; } \
|
||||
| run timedNotes 1200000 || exit 1
|
||||
|
||||
# Eight ticks of 125,000 cycles is 1,000,000, and the machine halts when the table runs out
|
||||
# rather than when the cycle limit does. So the length of what came out is the beat, counted.
|
||||
# A TENTH OF A PER CENT, which is forty eight samples. That is not fussiness: the machine
|
||||
# halts within a few hundred cycles of the last tick, so anything wider than this stops
|
||||
# measuring the timer and starts measuring nothing in particular.
|
||||
COUNT="$(measure timedNotes count)"
|
||||
near "$COUNT" 48000 0.1 \
|
||||
&& result ok "eight ticks last eight periods" "$COUNT samples, and 8 x 125,000 cycles is 48,000" \
|
||||
|| result no "eight ticks last eight periods" "$COUNT samples, wanted about 48,000"
|
||||
|
||||
# ---- And the notes change where the ticks do ----
|
||||
#
|
||||
# The seventh note occupies samples 36,000 to 42,000 and the eighth 42,000 to 48,000, so a
|
||||
# window inside each should hear one note and not a blend of two.
|
||||
#
|
||||
# THIS IS THE ONE THAT FAILS ON THE OLD TIMING. At seven whole frames a tick is 5,600 samples,
|
||||
# the eighth note starts at 39,200, and the seventh window straddles the boundary: measured, it
|
||||
# reads 384 Hz, which is neither note and is what a crossing counter says when it is given two.
|
||||
SEVENTH="$(measure timedNotes pitch 37000 41000)"
|
||||
EIGHTH="$(measure timedNotes pitch 43000 47000)"
|
||||
near "$SEVENTH" 261.6 2 \
|
||||
&& result ok "a note begins where a tick begins" "the seventh note reads $SEVENTH hertz, and middle C is 261.6" \
|
||||
|| result no "a note begins where a tick begins" "the seventh window reads $SEVENTH hertz, which is not middle C alone"
|
||||
near "$EIGHTH" 523.3 2 \
|
||||
&& result ok "and the one after it is the next note" "$EIGHTH hertz, an octave up as written" \
|
||||
|| result no "and the one after it is the next note" "$EIGHTH hertz, wanted 523.3"
|
||||
|
||||
echo
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "All $PASS sound checks passed."
|
||||
|
||||
Reference in New Issue
Block a user