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
@@ -34,6 +34,9 @@ void printHelp(const char *programName) {
|
||||
printf(" keyboard rather than a terminal. Which means the console does\n");
|
||||
printf(" its own line editing, the way it must when a window is open\n");
|
||||
printf(" and there is no terminal behind it to do it.\n");
|
||||
printf(" -N, --sound FILE Save every sample the machine made, as raw signed 16 bit\n");
|
||||
printf(" at 48kHz. What --screen is for a picture: the only way to\n");
|
||||
printf(" check a sound on a machine with no speaker.\n");
|
||||
printf(" -h, --help Display this help message.\n");
|
||||
}
|
||||
|
||||
@@ -47,6 +50,7 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
{"disk-cycles", required_argument, 0, 'L'},
|
||||
{"screen", required_argument, 0, 'S'},
|
||||
{"keyboard", required_argument, 0, 'K'},
|
||||
{"sound", required_argument, 0, 'N'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
@@ -61,9 +65,10 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
options->diskCycles = 0;
|
||||
options->screen = NULL;
|
||||
options->keyboard = NULL;
|
||||
options->sound = NULL;
|
||||
|
||||
// Parse options
|
||||
while ((opt = getopt_long(argc, argv, "dc:fhD:WL:S:K:", long_options, &option_index)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "dc:fhD:WL:S:K:N:", long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
options->debug = 1;
|
||||
@@ -99,6 +104,9 @@ uint8_t parseOptions(int argc, char *argv[], EmulatorOptions *options) {
|
||||
case 'K':
|
||||
options->keyboard = optarg;
|
||||
break;
|
||||
case 'N':
|
||||
options->sound = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
printHelp(argv[0]);
|
||||
return OPTIONS_HELP;
|
||||
|
||||
Reference in New Issue
Block a user