sound, fix ym2612 ladder effect, add option

This commit is contained in:
kub 2021-11-19 21:01:50 +01:00
parent b55e4e1b2f
commit 23cd73bc8f
9 changed files with 46 additions and 22 deletions

View file

@ -75,7 +75,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
#define POPT_EN_PWM (1<<21) #define POPT_EN_PWM (1<<21)
#define POPT_PWM_IRQ_OPT (1<<22) #define POPT_PWM_IRQ_OPT (1<<22)
#define POPT_DIS_FM_SSGEG (1<<23) #define POPT_DIS_FM_SSGEG (1<<23)
#define POPT_EN_FM_LADDER (1<<24) //x00 0000 #define POPT_EN_FM_DAC (1<<24) //x00 0000
#define PAHW_MCD (1<<0) #define PAHW_MCD (1<<0)
#define PAHW_32X (1<<1) #define PAHW_32X (1<<1)

View file

@ -69,7 +69,7 @@ void PsndRerate(int preserve_state)
} }
YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate, YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate,
((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) | ((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) |
((PicoIn.opt&POPT_EN_FM_LADDER) ? ST_LADDER : 0)); ((PicoIn.opt&POPT_EN_FM_DAC) ? ST_DAC : 0));
if (preserve_state) { if (preserve_state) {
// feed it back it's own registers, just like after loading state // feed it back it's own registers, just like after loading state
memcpy(YM2612GetRegs(), state, 0x204); memcpy(YM2612GetRegs(), state, 0x204);

View file

@ -922,7 +922,8 @@ typedef struct
static int clip(int n) static int clip(int n)
{ {
unsigned b = 14, s = n < 0; unsigned b = 14, s = n < 0;
if (s + (n>>(b-1))) n = (int)(s + INT_MAX) >> (8*sizeof(int)-b); int m = s + INT_MAX;
if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);
return n; return n;
} }
@ -1234,7 +1235,11 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
/* mix sample to output buffer */ /* mix sample to output buffer */
if (smp) { if (smp) {
smp = clip(smp); /* saturate to 14 bit */ smp = clip(smp); /* saturate to 14 bit */
if (ct->algo & 0x80) {
smp &= ~0x1f; /* drop bits (DAC has 9 bits) */
smp -= (smp < 0 ? 7:0) << 5; /* discontinuity */
}
if (ct->pack & 1) { /* stereo */ if (ct->pack & 1) { /* stereo */
if (ct->pack & 0x20) /* L */ /* TODO: check correctness */ if (ct->pack & 0x20) /* L */ /* TODO: check correctness */
buffer[scounter*2] += smp; buffer[scounter*2] += smp;
@ -1271,15 +1276,6 @@ static void chan_render_finish(int *buffer, unsigned short length, int active_ch
ym2612.OPN.eg_timer = crct.eg_timer; ym2612.OPN.eg_timer = crct.eg_timer;
g_lfo_ampm = crct.pack >> 16; // need_save g_lfo_ampm = crct.pack >> 16; // need_save
ym2612.OPN.lfo_cnt = crct.lfo_cnt; ym2612.OPN.lfo_cnt = crct.lfo_cnt;
/* apply ladder effect. NB only works if buffer was empty beforehand! */
if (active_chans && (ym2612.OPN.ST.flags & ST_LADDER)) {
length <<= crct.pack & 1;
while (length--) {
*buffer -= (*buffer < 0)*4 << 5;
buffer++;
}
}
} }
static UINT32 update_lfo_phase(FM_SLOT *SLOT, UINT32 block_fnum) static UINT32 update_lfo_phase(FM_SLOT *SLOT, UINT32 block_fnum)
@ -1339,6 +1335,8 @@ static int chan_render(int *buffer, int length, int c, UINT32 flags) // flags: s
crct.op1_out = crct.CH->op1_out; crct.op1_out = crct.CH->op1_out;
crct.algo = crct.CH->ALGO & 7; crct.algo = crct.CH->ALGO & 7;
if (ym2612.OPN.ST.flags & ST_DAC)
crct.algo |= 0x80;
if(crct.CH->pms && (ym2612.OPN.ST.mode & 0xC0) && c == 2) { if(crct.CH->pms && (ym2612.OPN.ST.mode & 0xC0) && c == 2) {
/* 3 slot mode */ /* 3 slot mode */

View file

@ -109,7 +109,7 @@ typedef struct
} FM_ST; } FM_ST;
#define ST_SSG 1 #define ST_SSG 1
#define ST_LADDER 2 #define ST_DAC 2
/***********************************************************/ /***********************************************************/
/* OPN unit */ /* OPN unit */

View file

@ -677,7 +677,7 @@
@ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]) @ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[3],ssg_update,was_update,algo[3], r5=tl_tab/slot, @ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|dac,unused[2],ssg_update,was_update,algo[3], r5=tl_tab/slot,
@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer @ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
.global chan_render_loop @ chan_rend_context *ct, int *buffer, int length .global chan_render_loop @ chan_rend_context *ct, int *buffer, int length
@ -688,8 +688,8 @@ chan_render_loop:
ldr r12, [lr, #0x4c] ldr r12, [lr, #0x4c]
ldr r0, [lr, #0x50] ldr r0, [lr, #0x50]
mov r11, r1 mov r11, r1
and r0, r0, #7 and r0, r0, #0x87
orr r4, r4, r0 @ (length<<8)|algo orr r4, r4, r0 @ (length<<8)|dac,unused[4],algo[3]
ldr r8, [lr, #0x44] @ eg_timer ldr r8, [lr, #0x44] @ eg_timer
ldr r9, [lr, #0x48] @ eg_timer_add ldr r9, [lr, #0x48] @ eg_timer_add
ldr r10, [lr, #0x54] @ op1_out ldr r10, [lr, #0x54] @ op1_out
@ -925,9 +925,12 @@ crl_algo_done:
beq ctl_sample_skip beq ctl_sample_skip
orr r4, r4, #8 @ have_output orr r4, r4, #8 @ have_output
lsr r1, r0, #31 @ clip (saturate) sample to 14 bit lsr r1, r0, #31 @ clip (saturate) sample to 14 bit
adds r2, r1, r0, asr #13 cmn r1, r0, asr #13
subne r0, r1, #0x80000001 subne r0, r1, #0x80000001
asrne r0, r0, #18 asrne r0, r0, #18
tst r4, r1, lsl #7 @ (sample < 0) && dac?
bicne r0, r0, #0x1f
subne r0, r0, #7<<5
tst r12, #1 tst r12, #1
beq ctl_sample_mono beq ctl_sample_mono

View file

@ -561,7 +561,7 @@ static menu_entry e_menu_adv_options[] =
mee_onoff ("Emulate Z80", MA_OPT2_ENABLE_Z80, PicoIn.opt, POPT_EN_Z80), mee_onoff ("Emulate Z80", MA_OPT2_ENABLE_Z80, PicoIn.opt, POPT_EN_Z80),
mee_onoff ("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM), mee_onoff ("Emulate YM2612 (FM)", MA_OPT2_ENABLE_YM2612, PicoIn.opt, POPT_EN_FM),
mee_onoff ("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG), mee_onoff ("Disable YM2612 SSG-EG", MA_OPT2_DISABLE_YM_SSG,PicoIn.opt, POPT_DIS_FM_SSGEG),
mee_onoff ("Enable YM2612 ladder effect",MA_OPT2_DISABLE_YM_LAD,PicoIn.opt, POPT_EN_FM_LADDER), mee_onoff ("Enable YM2612 DAC noise", MA_OPT2_ENABLE_YM_DAC, PicoIn.opt, POPT_EN_FM_DAC),
mee_onoff ("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG), mee_onoff ("Emulate SN76496 (PSG)", MA_OPT2_ENABLE_SN76496,PicoIn.opt, POPT_EN_PSG),
mee_onoff ("Emulate Game Gear LCD", MA_OPT2_ENABLE_GGLCD ,PicoIn.opt, POPT_EN_GG_LCD), mee_onoff ("Emulate Game Gear LCD", MA_OPT2_ENABLE_GGLCD ,PicoIn.opt, POPT_EN_GG_LCD),
mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET), mee_onoff ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET),

View file

@ -50,7 +50,7 @@ typedef enum
MA_OPT2_ENABLE_Z80, MA_OPT2_ENABLE_Z80,
MA_OPT2_ENABLE_YM2612, MA_OPT2_ENABLE_YM2612,
MA_OPT2_DISABLE_YM_SSG, MA_OPT2_DISABLE_YM_SSG,
MA_OPT2_DISABLE_YM_LAD, MA_OPT2_ENABLE_YM_DAC,
MA_OPT2_ENABLE_SN76496, MA_OPT2_ENABLE_SN76496,
MA_OPT2_ENABLE_YM2413, MA_OPT2_ENABLE_YM2413,
MA_OPT2_ENABLE_GGLCD, MA_OPT2_ENABLE_GGLCD,

View file

@ -1594,6 +1594,15 @@ static void update_variables(bool first_run)
PicoIn.opt &= ~POPT_EN_DRC; PicoIn.opt &= ~POPT_EN_DRC;
#endif #endif
var.value = NULL;
var.key = "picodrive_dacnoise";
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
if (strcmp(var.value, "enabled") == 0)
PicoIn.opt |= POPT_EN_FM_DAC;
else
PicoIn.opt &= ~POPT_EN_FM_DAC;
}
old_snd_filter = PicoIn.opt & POPT_EN_SNDFILTER; old_snd_filter = PicoIn.opt & POPT_EN_SNDFILTER;
var.value = NULL; var.value = NULL;
var.key = "picodrive_audio_filter"; var.key = "picodrive_audio_filter";

View file

@ -64,7 +64,7 @@ struct retro_core_option_v2_category option_cats_us[] = {
{ {
"audio", "audio",
"Audio", "Audio",
"Configure sample rate / emulated audio devices / low pass filter." "Configure sample rate / emulated audio devices / low pass filter / DAC noise."
}, },
{ {
"input", "input",
@ -231,11 +231,25 @@ struct retro_core_option_v2_definition option_defs_us[] = {
}, },
"off" "off"
}, },
{
"picodrive_dacnoise",
"Mega Drive FM DAC noise",
NULL,
"Enable emulation of YM2612 DAC noise. This option generates a distortion which existed on most Model 1 Mega Drive/Genesis, but not on newer models.",
NULL,
"audio",
{
{ "off", "disabled" },
{ "on", "enabled" },
{ NULL, NULL },
},
"off"
},
{ {
"picodrive_audio_filter", "picodrive_audio_filter",
"Audio Filter", "Audio Filter",
NULL, NULL,
"Enable a low pass audio filter to better simulate the characteristic sound of a Model 1 Genesis. This option is ignored when running Master System and PICO titles. Only the Genesis and its add-on hardware (Sega CD, 32X) employed a physical low pass filter.", "Enable a low pass audio filter to better simulate the characteristic sound of a Model 1 Mega Drive/Genesis. Note that although only the Genesis and its add-on hardware (Sega CD, 32X) employed a physical low pass filter, the filter setting is not restricted to that.",
NULL, NULL,
"audio", "audio",
{ {