Give the machine a sound device
Four channels on ports 0x40 to 0x4F, each one a whole soundThing voice:
two oscillators, two envelopes, a filter and the routing between them. A
channel keeps its patch between notes, so a program sets an instrument up
once and then plays it.
Six ports rather than forty, because a voice has around forty settings and
four of them would spend more than half the port space on one device.
There is a selector and a value instead: say which channel, say which
setting, write it. That is three writes to change a setting and two to
play a note, which is the right way round - patches are loaded, notes are
played in an inner loop.
Samples come from the machine's clock and not the host's: 48,000 a second
of emulated time, worked out in whole numbers so it never drifts. A
million cycles is exactly 48,000 samples on any host at any speed, which
is what makes a sound something a test can compare. --sound writes them
out, the way --screen writes a picture, for the same reason: the suite has
no speaker.
Tests/sound.sh is 22 checks and found three real defects the first time it
ran, all the same shape - a synthesizer written for a patch editor, wired
up as hardware and inheriting the editor's assumptions:
- Only one voice had an oscillator switched on, so three of the four
channels could not make a sound whatever was written to them.
- That voice's oscillator arrived at full gain and every other one
arrived at nothing, an asymmetry with no reason behind it.
- A note with no sustain is silent but not over, so the obvious way to
wait for a sound to finish waits for ever.
The first two are fixed by the device defining its own power-on state
rather than inheriting synthInit's: every channel arrives able to make a
sound, so writing a note number is the whole of playing a note. The third
was already written into the manual as advice, an hour before the check
existed. The check disagreed with the documentation and the check was
right; the manual now says the one rule, which is that a note sounds until
the gate is dropped.
Programs/Examples/tune.asm plays eight notes, taking its tempo from the
screen's frame interrupt because that is the only regular beat this
machine has. It spends 99.8% of its cycles asleep in WAIT.
Voyager has no speaker yet - this is the device and its tests. Playing the
samples out of the window is the next commit.
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
b0d06aa6e5
commit
d388cd3122
+23
-3
@@ -9,7 +9,7 @@ believe them.
|
||||
|
||||
## What The Suite Claims:
|
||||
|
||||
The suite is not one thing. It is ten scripts making five different kinds of claim, and
|
||||
The suite is not one thing. It is eleven scripts making five different kinds of claim, and
|
||||
knowing which claim you are relying on is the whole point of this document. A recorded
|
||||
transcript and a byte-for-byte comparison against a second implementation both print
|
||||
`[ok ]`, and they are worth wildly different amounts.
|
||||
@@ -58,6 +58,7 @@ Individual scripts can be run on their own, from anywhere:
|
||||
./Tests/disk.sh The disk tool against the format.
|
||||
./Tests/cycles.sh What the memory controller charges.
|
||||
./Tests/video.sh What the video device draws.
|
||||
./Tests/sound.sh What the sound device makes.
|
||||
./Tests/terminal.sh The things a recorded file cannot see.
|
||||
./Tests/native.sh The two assemblers against each other.
|
||||
./Tests/agree.sh The two filesystems against each other.
|
||||
@@ -78,7 +79,7 @@ from `make`, not from here.
|
||||
### 1. Recorded output
|
||||
|
||||
`Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares
|
||||
everything it printed against a file in `Tests/expected`. 169 tests, of which 107 run, 35
|
||||
everything it printed against a file in `Tests/expected`. 170 tests, of which 108 run, 35
|
||||
only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image
|
||||
given at all.
|
||||
|
||||
@@ -158,7 +159,26 @@ the palette is what colours it, that the attribute nibble adds sixteen, that scr
|
||||
which row is on top, that the map wraps, and that an impossible mode is refused without
|
||||
stopping the machine.
|
||||
|
||||
**Half of it is about the console rather than the device.** Those programs ask the video
|
||||
`Tests/sound.sh` is the same argument again, one device along: the suite has no speaker, and
|
||||
a sound nothing can hear is a sound nothing checks. Its samples come from the machine's clock
|
||||
rather than the host's, so `--sound` writes a file that is a pure function of the program and
|
||||
the cycle count - a million cycles is exactly forty-eight thousand samples, on any host, at
|
||||
any speed. The checks read that file back and measure it: that a note is the note that was
|
||||
asked for, that twelve of them is an octave, that gain is a level and volume is over the top
|
||||
of it, and that two runs are identical byte for byte.
|
||||
|
||||
**It found three real defects the first time it ran**, all of them the same shape - a
|
||||
synthesizer written for a patch editor, wired up as hardware and inheriting the editor's
|
||||
assumptions. Only one voice had an oscillator switched on, so three of the four channels could
|
||||
not make a sound whatever was written to them. That voice's oscillator arrived at full gain
|
||||
while every other one arrived at nothing. And a note with no sustain is silent but not over,
|
||||
so the obvious way to wait for a sound to end waits for ever.
|
||||
|
||||
The last of those had already caught the person writing the device, an hour before the check
|
||||
existed, and had been written into the manual as advice. That is the argument for a suite in
|
||||
one sentence: **the check disagreed with the documentation, and the check was right.**
|
||||
|
||||
**Half of `video.sh` is about the console rather than the device.** Those programs ask the video
|
||||
device for nothing at all: they write bytes to port 0x00, the way every SplitBit program
|
||||
always has, and the picture is what is checked. A character lands at the cursor and the
|
||||
cursor moves along, a newline starts the next row, backspace rubs out, the line wraps at the
|
||||
|
||||
Reference in New Issue
Block a user