summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2019-03-24 19:59:41 -0700
committerMichael Pavone <pavone@retrodev.com>2019-03-24 19:59:41 -0700
commitc1597a8f0a63adbf7018a05a35d0c77d7bccd0c3 (patch)
tree6a69339c03f4eac70575b246b9e68083190cbd15
parenta4a8b07d31dbeb9780352e332a5a4451866550c5 (diff)
Optionally emulate the offset around zero in the imperfect DAC of a discrete YM2612
-rw-r--r--genesis.c9
-rw-r--r--nuklear_ui/blastem_nuklear.c14
-rw-r--r--ym2612.c26
-rw-r--r--ym2612.h5
4 files changed, 44 insertions, 10 deletions
diff --git a/genesis.c b/genesis.c
index 5d28c5f..99dce0f 100644
--- a/genesis.c
+++ b/genesis.c
@@ -1334,20 +1334,23 @@ static void keyboard_up(system_header *system, uint8_t scancode)
io_keyboard_up(&gen->io, scancode);
}
-static void set_gain_config(genesis_context *gen)
+static void set_audio_config(genesis_context *gen)
{
char *config_gain;
config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval;
render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f);
config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval;
render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f);
+
+ char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval;
+ ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset"));
}
static void config_updated(system_header *system)
{
genesis_context *gen = (genesis_context *)system;
setup_io_devices(config, &system->info, &gen->io);
- set_gain_config(gen);
+ set_audio_config(gen);
}
genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
@@ -1402,7 +1405,7 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
gen->psg = malloc(sizeof(psg_context));
psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG);
- set_gain_config(gen);
+ set_audio_config(gen);
z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES);
#ifndef NO_Z80
diff --git a/nuklear_ui/blastem_nuklear.c b/nuklear_ui/blastem_nuklear.c
index 9bb1711..25b5a85 100644
--- a/nuklear_ui/blastem_nuklear.c
+++ b/nuklear_ui/blastem_nuklear.c
@@ -1668,13 +1668,24 @@ void view_audio_settings(struct nk_context *context)
"128",
"64"
};
+ const char *dac[] = {
+ "zero_offset",
+ "linear"
+ };
+ const char *dac_desc[] = {
+ "Zero Offset",
+ "Linear"
+ };
const uint32_t num_rates = sizeof(rates)/sizeof(*rates);
const uint32_t num_sizes = sizeof(sizes)/sizeof(*sizes);
+ const uint32_t num_dacs = sizeof(dac)/sizeof(*dac);
static int32_t selected_rate = -1;
static int32_t selected_size = -1;
- if (selected_rate < 0 || selected_size < 0) {
+ static int32_t selected_dac = -1;
+ if (selected_rate < 0 || selected_size < 0 || selected_dac < 0) {
selected_rate = find_match(rates, num_rates, "autio\0rate\0", "48000");
selected_size = find_match(sizes, num_sizes, "audio\0buffer\0", "512");
+ selected_dac = find_match(dac, num_dacs, "audio\0fm_dac\0", "zero_offset");
}
uint32_t width = render_width();
uint32_t height = render_height();
@@ -1690,6 +1701,7 @@ void view_audio_settings(struct nk_context *context)
settings_float_property(context, "Gain", "Overall", "audio\0gain\0", 0, -30.0f, 30.0f, 0.5f);
settings_float_property(context, "", "FM", "audio\0fm_gain\0", 0, -30.0f, 30.0f, 0.5f);
settings_float_property(context, "", "PSG", "audio\0psg_gain\0", 0, -30.0f, 30.0f, 0.5f);
+ selected_dac = settings_dropdown_ex(context, "FM DAC", dac, dac_desc, num_dacs, selected_dac, "audio\0fm_dac\0");
if (nk_button_label(context, "Back")) {
pop_view();
}
diff --git a/ym2612.c b/ym2612.c
index 10cb0a0..71ee0d0 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -256,6 +256,7 @@ void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div
}
}
ym_reset(context);
+ ym_enable_zero_offset(context, 1);
}
void ym_free(ym2612_context *context)
@@ -267,8 +268,18 @@ void ym_free(ym2612_context *context)
free(context);
}
-#define YM_VOLUME_MULTIPLIER 2
-#define YM_VOLUME_DIVIDER 3
+void ym_enable_zero_offset(ym2612_context *context, uint8_t enabled)
+{
+ if (enabled) {
+ context->zero_offset = 0x70;
+ context->volume_mult = 79;
+ context->volume_div = 120;
+ } else {
+ context->zero_offset = 0;
+ context->volume_mult = 2;
+ context->volume_div = 3;
+ }
+}
#define YM_MOD_SHIFT 1
#define CSM_MODE 0x80
@@ -549,7 +560,7 @@ void ym_run(ym2612_context * context, uint32_t to_cycle)
if (value & 0x2000) {
value |= 0xC000;
}
- dfprintf(debug_file, "channel %d output: %d\n", channel, (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER);
+ dfprintf(debug_file, "channel %d output: %d\n", channel, (value * context->volume_mult) / context->volume_div);
}
}
//puts("operator update done");
@@ -571,14 +582,19 @@ void ym_run(ym2612_context * context, uint32_t to_cycle)
value |= 0xC000;
}
}
+ if (value >= 0) {
+ value += context->zero_offset;
+ } else {
+ value -= context->zero_offset;
+ }
if (context->channels[i].logfile) {
fwrite(&value, sizeof(value), 1, context->channels[i].logfile);
}
if (context->channels[i].lr & 0x80) {
- left += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER;
+ left += (value * context->volume_mult) / context->volume_div;
}
if (context->channels[i].lr & 0x40) {
- right += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER;
+ right += (value * context->volume_mult) / context->volume_div;
}
}
render_put_stereo_sample(context->audio, left, right);
diff --git a/ym2612.h b/ym2612.h
index 2781c94..1f34558 100644
--- a/ym2612.h
+++ b/ym2612.h
@@ -70,9 +70,11 @@ typedef struct {
//TODO: Condense the next two fields into one
uint32_t write_cycle;
uint32_t busy_cycles;
- uint32_t lowpass_alpha;
+ int32_t volume_mult;
+ int32_t volume_div;
ym_operator operators[NUM_OPERATORS];
ym_channel channels[NUM_CHANNELS];
+ int16_t zero_offset;
uint16_t timer_a;
uint16_t timer_a_load;
uint16_t env_counter;
@@ -128,6 +130,7 @@ enum {
void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div, uint32_t options);
void ym_reset(ym2612_context *context);
void ym_free(ym2612_context *context);
+void ym_enable_zero_offset(ym2612_context *context, uint8_t enabled);
void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock);
void ym_run(ym2612_context * context, uint32_t to_cycle);
void ym_address_write_part1(ym2612_context * context, uint8_t address);