diff --git a/README.md b/README.md index 653fbd0..3d33ba1 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,11 @@ Play options: -t, --track= set track number -f, --frequency= set audio frequency in Hz (default 44100) + --psg-mix= + empiric mixes the three PSG channels as measured + on Atari ST hardware; linear sums the channels to + produce a cleaner sound (default linear) + Disassembly options: --disassemble disassemble SNDH file and exit; may be combined diff --git a/doc/psgplay.1 b/doc/psgplay.1 index a61fc69..4c68cd3 100644 --- a/doc/psgplay.1 +++ b/doc/psgplay.1 @@ -75,6 +75,11 @@ Set track number. .BR \-f ", " \-\-frequency "=<" \fIfrequency\fR ">" Set audio frequency in Hz (default 44100). +.TP +.BR \-\-psg-mix "=<" \fIempiric\fR "|" \fIlinear\fR ">" +Empiric mixes the three PSG channels as measured on Atari ST hardware; linear +sums the channels to produce a cleaner sound (default linear). + .RE Disassembly options: diff --git a/include/system/unix/option.h b/include/system/unix/option.h index 28684eb..2add70a 100644 --- a/include/system/unix/option.h +++ b/include/system/unix/option.h @@ -9,6 +9,7 @@ #include #include "atari/trace.h" +#include "psgplay/stereo.h" #define OPTION_TIME_UNDEFINED -1 #define OPTION_STOP_NEVER -2 @@ -36,6 +37,8 @@ struct options { int track; int frequency; + const char *psg_mix; + const char *input; struct trace_mode trace; @@ -50,6 +53,8 @@ bool command_mode_option(void); bool text_mode_option(void); +psgplay_digital_to_stereo_cb psg_mix_option(void); + struct options *parse_options(int argc, char **argv); int option_verbosity(void); diff --git a/system/unix/command-mode.c b/system/unix/command-mode.c index 022d97a..171dfc9 100644 --- a/system/unix/command-mode.c +++ b/system/unix/command-mode.c @@ -101,6 +101,11 @@ void command_replay(const struct options *options, struct file file, options->track, options->frequency); ssize_t sample_count = 0; + if (!pp) + pr_fatal_error("%s: failed to init PSG play\n", progname); + + psgplay_digital_to_stereo_callback(pp, psg_mix_option(), NULL); + for (;;) { struct psgplay_stereo buffer[256]; diff --git a/system/unix/option.c b/system/unix/option.c index a11deae..41dee5f 100644 --- a/system/unix/option.c +++ b/system/unix/option.c @@ -64,6 +64,11 @@ static void help(FILE *file) " -t, --track= set track number\n" " -f, --frequency= set audio frequency in Hz (default 44100)\n" "\n" +" --psg-mix=\n" +" empiric mixes the three PSG channels as measured\n" +" on Atari ST hardware; linear sums the channels to\n" +" produce a cleaner sound (default linear)\n" +"\n" "Disassembly options:\n" "\n" " --disassemble disassemble SNDH file and exit; may be combined\n" @@ -169,6 +174,18 @@ TRACE_DEVICE(TRACE_DEVICE_OPT) return (struct trace_mode) { .m = m }; } +psgplay_digital_to_stereo_cb psg_mix_option(void) +{ + if (strcmp(option.psg_mix, "empiric") == 0) + return psgplay_digital_to_stereo_empiric; + if (strcmp(option.psg_mix, "linear") == 0) + return psgplay_digital_to_stereo_linear; + + pr_fatal_error("unknown PSG mix: %s\n", option.psg_mix); + + return NULL; +} + struct options *parse_options(int argc, char **argv) { static const struct option options[] = { @@ -188,6 +205,8 @@ struct options *parse_options(int argc, char **argv) { "track", required_argument, NULL, 0 }, { "frequency", required_argument, NULL, 0 }, + { "psg-mix", required_argument, NULL, 0 }, + { "disassemble", no_argument, NULL, 0 }, { "disassemble-header", no_argument, NULL, 0 }, { "disassemble-address", no_argument, NULL, 0 }, @@ -204,6 +223,7 @@ struct options *parse_options(int argc, char **argv) option.track = -1; option.frequency = 44100; + option.psg_mix = "linear"; for (;;) { int index = 0; @@ -242,6 +262,8 @@ struct options *parse_options(int argc, char **argv) goto opt_t; else if (OPT("frequency")) goto opt_f; + else if (OPT("psg-mix")) + option.psg_mix = optarg; else if (OPT("trace")) option.trace = trace_option(optarg); diff --git a/system/unix/text-mode.c b/system/unix/text-mode.c index 926f490..5361d98 100644 --- a/system/unix/text-mode.c +++ b/system/unix/text-mode.c @@ -47,19 +47,29 @@ struct tty_arg { struct sample_buffer *sb; }; +static struct psgplay *psgplay_init__(const void *data, + size_t size, int track, int frequency) +{ + struct psgplay *pp = psgplay_init(data, size, track, frequency); + + if (!pp) + pr_fatal_error("Failed to init PSG play\n"); + + psgplay_digital_to_stereo_callback(pp, psg_mix_option(), NULL); + + return pp; +} + static struct sample_buffer sample_buffer_init(const void *data, size_t size, const char *option_output, int track, int frequency, const struct output *output) { struct sample_buffer sb = { - .pp = psgplay_init(data, size, track, frequency), + .pp = psgplay_init__(data, size, track, frequency), .output = output, .output_arg = output->open(option_output, frequency, true), }; - if (!sb.pp) - pr_fatal_error("Failed to init PSG play\n"); - return sb; } @@ -98,9 +108,7 @@ static bool sample_buffer_play(struct sample_buffer *sb, { BUG_ON(sb->pp); - sb->pp = psgplay_init(data, size, track, frequency); - if (!sb->pp) - return false; + sb->pp = psgplay_init__(data, size, track, frequency); return true; }