# HG changeset patch # User Michael Pavone # Date 1553482781 25200 # Node ID 5278b6e44fc1998a6236553a814591b824c6d3aa # Parent 5ff8f0d281881e535d025b944cda70901ebc195d Optionally emulate the offset around zero in the imperfect DAC of a discrete YM2612 diff -r 5ff8f0d28188 -r 5278b6e44fc1 genesis.c --- a/genesis.c Sun Mar 24 13:31:22 2019 -0700 +++ b/genesis.c Sun Mar 24 19:59:41 2019 -0700 @@ -1334,20 +1334,23 @@ 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 @@ 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 -r 5ff8f0d28188 -r 5278b6e44fc1 nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Sun Mar 24 13:31:22 2019 -0700 +++ b/nuklear_ui/blastem_nuklear.c Sun Mar 24 19:59:41 2019 -0700 @@ -1668,13 +1668,24 @@ "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 @@ 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 -r 5ff8f0d28188 -r 5278b6e44fc1 ym2612.c --- a/ym2612.c Sun Mar 24 13:31:22 2019 -0700 +++ b/ym2612.c Sun Mar 24 19:59:41 2019 -0700 @@ -256,6 +256,7 @@ } } ym_reset(context); + ym_enable_zero_offset(context, 1); } void ym_free(ym2612_context *context) @@ -267,8 +268,18 @@ 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 @@ 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 @@ 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 -r 5ff8f0d28188 -r 5278b6e44fc1 ym2612.h --- a/ym2612.h Sun Mar 24 13:31:22 2019 -0700 +++ b/ym2612.h Sun Mar 24 19:59:41 2019 -0700 @@ -70,9 +70,11 @@ //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 @@ 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);