sound, add ym2612 channel clipping, ladder effect

This commit is contained in:
kub 2021-11-17 22:27:02 +01:00
parent 55615f9c97
commit 8794ba5c8d
7 changed files with 39 additions and 9 deletions

View file

@ -75,6 +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 PAHW_MCD (1<<0) #define PAHW_MCD (1<<0)
#define PAHW_32X (1<<1) #define PAHW_32X (1<<1)

View file

@ -67,7 +67,9 @@ void PsndRerate(int preserve_state)
ym2612_pack_state(); ym2612_pack_state();
memcpy(state, YM2612GetRegs(), 0x204); 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) { 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

@ -918,6 +918,14 @@ typedef struct
#if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612) #if !defined(_ASM_YM2612_C) || defined(EXTERNAL_YM2612)
#include <limits.h>
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) static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)
{ {
int scounter; /* sample counter */ 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 */ /* mix sample to output buffer */
if (smp) { if (smp) {
smp = clip(smp); /* saturate to 14 bit */
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;
@ -1256,12 +1265,21 @@ static void chan_render_prep(void)
crct.lfo_inc = ym2612.OPN.lfo_inc; 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_cnt = crct.eg_cnt;
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)
@ -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)); 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; if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, flags|((pan&0xc00)>>6)|(!!ym2612.dacen<<2)) << 5;
#undef BIT_IF #undef BIT_IF
chan_render_finish(); chan_render_finish(buffer, length, active_chs);
return active_chs; // 1 if buffer updated return active_chs; // 1 if buffer updated
} }
/* initialize YM2612 emulator */ /* initialize YM2612 emulator */
void YM2612Init_(int clock, int rate, int ssg) void YM2612Init_(int clock, int rate, int flags)
{ {
memset(&ym2612, 0, sizeof(ym2612)); memset(&ym2612, 0, sizeof(ym2612));
init_tables(); init_tables();
ym2612.OPN.ST.clock = clock; ym2612.OPN.ST.clock = clock;
ym2612.OPN.ST.rate = rate; ym2612.OPN.ST.rate = rate;
ym2612.OPN.ST.flags = (ssg ? 1:0); ym2612.OPN.ST.flags = flags;
OPNSetPres( 6*24 ); OPNSetPres( 6*24 );

View file

@ -108,6 +108,9 @@ typedef struct
INT32 dt_tab[8][32];/* DeTune table */ INT32 dt_tab[8][32];/* DeTune table */
} FM_ST; } FM_ST;
#define ST_SSG 1
#define ST_LADDER 2
/***********************************************************/ /***********************************************************/
/* OPN unit */ /* OPN unit */
/***********************************************************/ /***********************************************************/
@ -162,7 +165,7 @@ typedef struct
extern YM2612 ym2612; extern YM2612 ym2612;
#endif #endif
void YM2612Init_(int baseclock, int rate, int ssg); void YM2612Init_(int baseclock, int rate, int flags);
void YM2612ResetChip_(void); void YM2612ResetChip_(void);
int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty); int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty);
@ -184,9 +187,9 @@ int YM2612PicoStateLoad2(int *tat, int *tbt);
#else #else
/* GP2X specific */ /* GP2X specific */
#include <platform/gp2x/940ctl.h> #include <platform/gp2x/940ctl.h>
#define YM2612Init(baseclock,rate,ssg) do { \ #define YM2612Init(baseclock,rate,flags) do { \
if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate, ssg); \ if (PicoIn.opt&POPT_EXT_FM) YM2612Init_940(baseclock, rate, flags); \
else YM2612Init_(baseclock, rate, ssg); \ else YM2612Init_(baseclock, rate, flags); \
} while (0) } while (0)
#define YM2612ResetChip() do { \ #define YM2612ResetChip() do { \
if (PicoIn.opt&POPT_EXT_FM) YM2612ResetChip_940(); \ if (PicoIn.opt&POPT_EXT_FM) YM2612ResetChip_940(); \

View file

@ -924,6 +924,10 @@ crl_algo_done:
tst r0, r0 tst r0, r0
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
adds r2, r1, r0, asr #13
subne r0, r1, #0x80000001
asrne r0, r0, #18
tst r12, #1 tst r12, #1
beq ctl_sample_mono beq ctl_sample_mono

View file

@ -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 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 ("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,6 +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_SN76496, MA_OPT2_ENABLE_SN76496,
MA_OPT2_ENABLE_YM2413, MA_OPT2_ENABLE_YM2413,
MA_OPT2_ENABLE_GGLCD, MA_OPT2_ENABLE_GGLCD,