From 8794ba5c8d314d43aa2d5a99ba9943d1b0e2e6cb Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 17 Nov 2021 22:27:02 +0100 Subject: [PATCH] sound, add ym2612 channel clipping, ladder effect --- pico/pico.h | 1 + pico/sound/sound.c | 4 +++- pico/sound/ym2612.c | 26 ++++++++++++++++++++++---- pico/sound/ym2612.h | 11 +++++++---- pico/sound/ym2612_arm.S | 4 ++++ platform/common/menu_pico.c | 1 + platform/common/menu_pico.h | 1 + 7 files changed, 39 insertions(+), 9 deletions(-) diff --git a/pico/pico.h b/pico/pico.h index 05833ce0..f474d56f 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -75,6 +75,7 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s; #define POPT_EN_PWM (1<<21) #define POPT_PWM_IRQ_OPT (1<<22) #define POPT_DIS_FM_SSGEG (1<<23) +#define POPT_EN_FM_LADDER (1<<24) //x00 0000 #define PAHW_MCD (1<<0) #define PAHW_32X (1<<1) diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 17ac7520..ac79a84a 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -67,7 +67,9 @@ void PsndRerate(int preserve_state) ym2612_pack_state(); memcpy(state, YM2612GetRegs(), 0x204); } - YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate, !(PicoIn.opt&POPT_DIS_FM_SSGEG)); + YM2612Init(Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7, PicoIn.sndRate, + ((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) | + ((PicoIn.opt&POPT_EN_FM_LADDER) ? ST_LADDER : 0)); if (preserve_state) { // feed it back it's own registers, just like after loading state memcpy(YM2612GetRegs(), state, 0x204); diff --git a/pico/sound/ym2612.c b/pico/sound/ym2612.c index 75d33de6..502326e1 100644 --- a/pico/sound/ym2612.c +++ b/pico/sound/ym2612.c @@ -918,6 +918,14 @@ typedef struct #if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612) +#include +static int clip(int n) +{ + unsigned b = 14, s = n < 0; + if (s + (n>>(b-1))) n = (int)(s + INT_MAX) >> (8*sizeof(int)-b); + return n; +} + static void chan_render_loop(chan_rend_context *ct, int *buffer, int length) { int scounter; /* sample counter */ @@ -1226,6 +1234,7 @@ static void chan_render_loop(chan_rend_context *ct, int *buffer, int length) /* mix sample to output buffer */ if (smp) { + smp = clip(smp); /* saturate to 14 bit */ if (ct->pack & 1) { /* stereo */ if (ct->pack & 0x20) /* L */ /* TODO: check correctness */ buffer[scounter*2] += smp; @@ -1256,12 +1265,21 @@ static void chan_render_prep(void) crct.lfo_inc = ym2612.OPN.lfo_inc; } -static void chan_render_finish(void) +static void chan_render_finish(int *buffer, unsigned short length, int active_chans) { ym2612.OPN.eg_cnt = crct.eg_cnt; ym2612.OPN.eg_timer = crct.eg_timer; g_lfo_ampm = crct.pack >> 16; // need_save 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) @@ -1835,21 +1853,21 @@ int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty) BIT_IF(flags, 1, (ym2612.ssg_mask & 0xf00000) && (ym2612.OPN.ST.flags & 1)); if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, flags|((pan&0xc00)>>6)|(!!ym2612.dacen<<2)) << 5; #undef BIT_IF - chan_render_finish(); + chan_render_finish(buffer, length, active_chs); return active_chs; // 1 if buffer updated } /* initialize YM2612 emulator */ -void YM2612Init_(int clock, int rate, int ssg) +void YM2612Init_(int clock, int rate, int flags) { memset(&ym2612, 0, sizeof(ym2612)); init_tables(); ym2612.OPN.ST.clock = clock; ym2612.OPN.ST.rate = rate; - ym2612.OPN.ST.flags = (ssg ? 1:0); + ym2612.OPN.ST.flags = flags; OPNSetPres( 6*24 ); diff --git a/pico/sound/ym2612.h b/pico/sound/ym2612.h index 7d16efbf..9b7fff46 100644 --- a/pico/sound/ym2612.h +++ b/pico/sound/ym2612.h @@ -108,6 +108,9 @@ typedef struct INT32 dt_tab[8][32];/* DeTune table */ } FM_ST; +#define ST_SSG 1 +#define ST_LADDER 2 + /***********************************************************/ /* OPN unit */ /***********************************************************/ @@ -162,7 +165,7 @@ typedef struct extern YM2612 ym2612; #endif -void YM2612Init_(int baseclock, int rate, int ssg); +void YM2612Init_(int baseclock, int rate, int flags); void YM2612ResetChip_(void); int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty); @@ -184,9 +187,9 @@ int YM2612PicoStateLoad2(int *tat, int *tbt); #else /* GP2X specific */ #include -#define YM2612Init(baseclock,rate,ssg) do { \ - if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate, ssg); \ - else YM2612Init_(baseclock, rate, ssg); \ +#define YM2612Init(baseclock,rate,flags) do { \ + if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate, flags); \ + else YM2612Init_(baseclock, rate, flags); \ } while (0) #define YM2612ResetChip() do { \ if (PicoIn.opt&POPT_EXT_FM) YM2612ResetChip_940(); \ diff --git a/pico/sound/ym2612_arm.S b/pico/sound/ym2612_arm.S index b1d03265..5cb42f21 100644 --- a/pico/sound/ym2612_arm.S +++ b/pico/sound/ym2612_arm.S @@ -924,6 +924,10 @@ crl_algo_done: tst r0, r0 beq ctl_sample_skip orr r4, r4, #8 @ have_output + lsr r1, r0, #31 @ clip (saturate) sample to 14 bit + adds r2, r1, r0, asr #13 + subne r0, r1, #0x80000001 + asrne r0, r0, #18 tst r12, #1 beq ctl_sample_mono diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index e0f9da0d..b5b44533 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -561,6 +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 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 ("Enable YM2612 ladder effect",MA_OPT2_DISABLE_YM_LAD,PicoIn.opt, POPT_EN_FM_LADDER), 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 ("Disable idle loop patching",MA_OPT2_NO_IDLE_LOOPS,PicoIn.opt, POPT_DIS_IDLE_DET), diff --git a/platform/common/menu_pico.h b/platform/common/menu_pico.h index c74a96d7..5b1800d1 100644 --- a/platform/common/menu_pico.h +++ b/platform/common/menu_pico.h @@ -50,6 +50,7 @@ typedef enum MA_OPT2_ENABLE_Z80, MA_OPT2_ENABLE_YM2612, MA_OPT2_DISABLE_YM_SSG, + MA_OPT2_DISABLE_YM_LAD, MA_OPT2_ENABLE_SN76496, MA_OPT2_ENABLE_YM2413, MA_OPT2_ENABLE_GGLCD, -- 2.39.2