Skip to content

Commit

Permalink
Added per-sound channel individual volume core options (libretro#223)
Browse files Browse the repository at this point in the history
fixed PSG Noise channel volume scaling

reworked PSG volume scaling formula, cleanups (libretro#223)

reworked MD volume scaling formula

added preproc tests for libretro (libretro#223)

added first implementation of SMS FM (YM2413) channel volume scaling (libretro#223)

added core option Show Advanced Audio Volume Settings

use USE_PER_SOUND_CHANNELS_CONFIG CFLAG for the new core options

changed volumes array types to avoid casting (libretro#223)

minor fixes
  • Loading branch information
eadmaster authored and eadmaster committed Dec 13, 2020
1 parent 0359e04 commit c5efcd6
Show file tree
Hide file tree
Showing 7 changed files with 482 additions and 53 deletions.
3 changes: 2 additions & 1 deletion Makefile.libretro
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,8 @@ LIBRETRO_CFLAGS += $(BPP_DEFINES) \
-DM68K_OVERCLOCK_SHIFT=20 \
-DZ80_OVERCLOCK_SHIFT=20 \
-DHAVE_YM3438_CORE \
-DHAVE_OPLL_CORE
-DHAVE_OPLL_CORE \
-DUSE_PER_SOUND_CHANNELS_CONFIG

ifneq (,$(findstring msvc,$(platform)))
LIBRETRO_CFLAGS += -DINLINE="static _inline"
Expand Down
21 changes: 9 additions & 12 deletions core/sound/psg.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ static struct
int chanDelta[4][2];
int chanOut[4][2];
int chanAmp[4][2];
int chanUserVolume[4];
} psg;

static void psg_update(unsigned int clocks);
Expand Down Expand Up @@ -379,14 +378,6 @@ void psg_write(unsigned int clocks, unsigned int data)
psg.regs[index] = data;
}

void psg_set_user_channel_volume(unsigned int channel, unsigned int volume)
{
if(channel > 3 || volume > 100) return; // invalid args
// else

psg.chanUserVolume[channel] = volume;
}

void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
{
int i;
Expand All @@ -405,10 +396,16 @@ void psg_config(unsigned int clocks, unsigned int preamp, unsigned int panning)
{
/* channel internal volume */
int volume = psg.regs[i*2+1];

/* update channel stereo amplification */
psg.chanAmp[i][0] = preamp * (psg.chanUserVolume[i]/100) * ((panning >> (i + 4)) & 1);
psg.chanAmp[i][1] = preamp * (psg.chanUserVolume[i]/100) * ((panning >> (i + 0)) & 1);
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
psg.chanAmp[i][0] = preamp * ((panning >> (i + 4)) & 1);
psg.chanAmp[i][1] = preamp * ((panning >> (i + 0)) & 1);
#else
/* also apply user-set volume scaling */
psg.chanAmp[i][0] = ((preamp * config.psg_ch_volumes[i]) / 100) * ((panning >> (i + 4)) & 1);
psg.chanAmp[i][1] = ((preamp * config.psg_ch_volumes[i]) / 100) * ((panning >> (i + 0)) & 1);
#endif

/* tone channels */
if (i < 3)
Expand Down
68 changes: 52 additions & 16 deletions core/sound/ym2413.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign
#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask))

/* calculate output */
INLINE void chan_calc( YM2413_OPLL_CH *CH )
INLINE void chan_calc( YM2413_OPLL_CH *CH, unsigned int chan )
{
YM2413_OPLL_SLOT *SLOT;
unsigned int env;
Expand Down Expand Up @@ -799,7 +799,13 @@ INLINE void chan_calc( YM2413_OPLL_CH *CH )
env = volume_calc(SLOT);
if( env < ENV_QUIET )
{
output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable);
output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[chan]/100;
#endif
}
}

Expand Down Expand Up @@ -877,7 +883,13 @@ INLINE void rhythm_calc( YM2413_OPLL_CH *CH, unsigned int noise )
SLOT++;
env = volume_calc(SLOT);
if( env < ENV_QUIET )
output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable);
output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[6]/100;
#endif


/* Phase generation is based on: */
Expand Down Expand Up @@ -945,7 +957,13 @@ INLINE void rhythm_calc( YM2413_OPLL_CH *CH, unsigned int noise )
phase = 0xd0>>2;
}

output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[7].SLOT[SLOT1].wavetable);
output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[7].SLOT[SLOT1].wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[7]/100;
#endif
}

/* Snare Drum (verified on real YM3812) */
Expand All @@ -966,13 +984,25 @@ INLINE void rhythm_calc( YM2413_OPLL_CH *CH, unsigned int noise )
if (noise)
phase ^= 0x100;

output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[7].SLOT[SLOT2].wavetable);
output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[7].SLOT[SLOT2].wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[7]/100;
#endif
}

/* Tom Tom (verified on real YM3812) */
env = volume_calc(&CH[8].SLOT[SLOT1]);
if( env < ENV_QUIET )
output[1] += op_calc(CH[8].SLOT[SLOT1].phase, env, 0, CH[8].SLOT[SLOT1].wavetable);
output[1] += op_calc(CH[8].SLOT[SLOT1].phase, env, 0, CH[8].SLOT[SLOT1].wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[8]/100;
#endif

/* Top Cymbal (verified on real YM2413) */
env = volume_calc(&CH[8].SLOT[SLOT2]);
Expand All @@ -999,7 +1029,13 @@ INLINE void rhythm_calc( YM2413_OPLL_CH *CH, unsigned int noise )
if (res2)
phase = 0x300;

output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[8].SLOT[SLOT2].wavetable);
output[1] += op_calc(phase<<FREQ_SH, env, 0, CH[8].SLOT[SLOT2].wavetable)
#ifndef USE_PER_SOUND_CHANNELS_CONFIG
;
#else
/* apply user-set volume scaling */
* config.sms_fm_ch_volumes[8]/100;
#endif
}
}

Expand Down Expand Up @@ -1681,18 +1717,18 @@ void YM2413Update(int *buffer, int length)
advance_lfo();

/* FM part */
chan_calc(&ym2413.P_CH[0]);
chan_calc(&ym2413.P_CH[1]);
chan_calc(&ym2413.P_CH[2]);
chan_calc(&ym2413.P_CH[3]);
chan_calc(&ym2413.P_CH[4]);
chan_calc(&ym2413.P_CH[5]);
chan_calc(&ym2413.P_CH[0], 0);
chan_calc(&ym2413.P_CH[1], 1);
chan_calc(&ym2413.P_CH[2], 2);
chan_calc(&ym2413.P_CH[3], 3);
chan_calc(&ym2413.P_CH[4], 4);
chan_calc(&ym2413.P_CH[5], 5);

if(!(ym2413.rhythm&0x20))
{
chan_calc(&ym2413.P_CH[6]);
chan_calc(&ym2413.P_CH[7]);
chan_calc(&ym2413.P_CH[8]);
chan_calc(&ym2413.P_CH[6], 6);
chan_calc(&ym2413.P_CH[7], 7);
chan_calc(&ym2413.P_CH[8], 8);
}
else /* Rhythm part */
{
Expand Down
10 changes: 10 additions & 0 deletions core/sound/ym2612.c
Original file line number Diff line number Diff line change
Expand Up @@ -2089,6 +2089,16 @@ void YM2612Update(int *buffer, int length)
else if (out_fm[4] < -8192) out_fm[4] = -8192;
if (out_fm[5] > 8191) out_fm[5] = 8191;
else if (out_fm[5] < -8192) out_fm[5] = -8192;

#ifdef USE_PER_SOUND_CHANNELS_CONFIG
/* apply user volume scaling */
if (config.md_ch_volumes[0] < 100) out_fm[0] = (out_fm[0] * config.md_ch_volumes[0]) / 100;
if (config.md_ch_volumes[1] < 100) out_fm[1] = (out_fm[1] * config.md_ch_volumes[1]) / 100;
if (config.md_ch_volumes[2] < 100) out_fm[2] = (out_fm[2] * config.md_ch_volumes[2]) / 100;
if (config.md_ch_volumes[3] < 100) out_fm[3] = (out_fm[3] * config.md_ch_volumes[3]) / 100;
if (config.md_ch_volumes[4] < 100) out_fm[4] = (out_fm[4] * config.md_ch_volumes[4]) / 100;
if (config.md_ch_volumes[5] < 100) out_fm[5] = (out_fm[5] * config.md_ch_volumes[5]) / 100;
#endif

/* stereo DAC output panning & mixing */
lt = ((out_fm[0]) & ym2612.OPN.pan[0]);
Expand Down
111 changes: 91 additions & 20 deletions libretro/libretro.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ static bool retro_audio_buff_underrun = false;
static unsigned audio_latency = 0;
static bool update_audio_latency = false;

static bool show_advanced_av_settings = true;

static void retro_audio_buff_status_cb(
bool active, unsigned occupancy, bool underrun_likely)
{
Expand Down Expand Up @@ -938,6 +940,9 @@ static void config_default(void)
config.ym2612 = YM2612_DISCRETE;
config.ym2413 = 2; /* AUTO */
config.mono = 0; /* STEREO output */
for (i = 0; i < 4; i++) config.psg_ch_volumes[i] = 100; /* individual channel volumes */
for (i = 0; i < 6; i++) config.md_ch_volumes[i] = 100; /* individual channel volumes */
for (i = 0; i < 9; i++) config.sms_fm_ch_volumes[i] = 100; /* individual channel volumes */
#ifdef HAVE_YM3438_CORE
config.ym3438 = 0;
#endif
Expand Down Expand Up @@ -1540,26 +1545,6 @@ static void check_variables(bool first_run)
}
}

char sound_channel_volume_base_str[] = "genesis_plus_gx_psg_channel_0_volume";
var.key = sound_channel_volume_base_str;
for (unsigned c = 0; c < 4; c++) {
sound_channel_volume_base_str[28] = c+'0';
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
psg_set_user_channel_volume(c, atoi(var.value));
// need to recall config to have the settings applied
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
psg_config(0, config.psg_preamp, 0xff);
}
else
{
psg_config(0, config.psg_preamp, io_reg[6]);
}
}
}


var.key = "genesis_plus_gx_fm_preamp";
environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var);
{
Expand Down Expand Up @@ -1835,6 +1820,92 @@ static void check_variables(bool first_run)
config.no_sprite_limit = 1;
}

char psg_channel_volume_base_str[] = "genesis_plus_gx_psg_channel_0_volume";
var.key = psg_channel_volume_base_str;
for (unsigned c = 0; c < 4; c++) {
psg_channel_volume_base_str[28] = c+'0';
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
config.psg_ch_volumes[c] = atoi(var.value);
// need to recall config to have the settings applied
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
psg_config(0, config.psg_preamp, 0xff);
}
else
{
psg_config(0, config.psg_preamp, io_reg[6]);
}
}
}

char md_fm_channel_volume_base_str[] = "genesis_plus_gx_md_channel_0_volume";
var.key = md_fm_channel_volume_base_str;
for (unsigned c = 0; c < 6; c++) {
md_fm_channel_volume_base_str[27] = c+'0';
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
config.md_ch_volumes[c] = atoi(var.value);
}
}

char sms_fm_channel_volume_base_str[] = "genesis_plus_gx_sms_fm_channel_0_volume";
var.key = sms_fm_channel_volume_base_str;
for (unsigned c = 0; c < 9; c++) {
sms_fm_channel_volume_base_str[31] = c+'0';
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
{
config.sms_fm_ch_volumes[c] = atoi(var.value);
}
}

var.key = "genesis_plus_gx_show_advanced_audio_settings";
var.value = NULL;

if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
bool show_advanced_av_settings_prev = show_advanced_av_settings;

show_advanced_av_settings = true;
if (strcmp(var.value, "disabled") == 0)
show_advanced_av_settings = false;

if (show_advanced_av_settings != show_advanced_av_settings_prev)
{
size_t i;
struct retro_core_option_display option_display;
char av_keys[19][40] = {
"genesis_plus_gx_psg_channel_0_volume",
"genesis_plus_gx_psg_channel_1_volume",
"genesis_plus_gx_psg_channel_2_volume",
"genesis_plus_gx_psg_channel_3_volume",
"genesis_plus_gx_md_channel_0_volume",
"genesis_plus_gx_md_channel_1_volume",
"genesis_plus_gx_md_channel_2_volume",
"genesis_plus_gx_md_channel_3_volume",
"genesis_plus_gx_md_channel_4_volume",
"genesis_plus_gx_md_channel_5_volume",
"genesis_plus_gx_sms_fm_channel_0_volume",
"genesis_plus_gx_sms_fm_channel_1_volume",
"genesis_plus_gx_sms_fm_channel_2_volume",
"genesis_plus_gx_sms_fm_channel_3_volume",
"genesis_plus_gx_sms_fm_channel_4_volume",
"genesis_plus_gx_sms_fm_channel_5_volume",
"genesis_plus_gx_sms_fm_channel_6_volume",
"genesis_plus_gx_sms_fm_channel_7_volume",
"genesis_plus_gx_sms_fm_channel_8_volume"
};

option_display.visible = show_advanced_av_settings;

for (i = 0; i < 19; i++)
{
option_display.key = av_keys[i];
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
}
}
}

if (reinit)
{
#ifdef HAVE_OVERCLOCK
Expand Down
Loading

0 comments on commit c5efcd6

Please sign in to comment.