From: kub Date: Thu, 23 Nov 2023 19:50:25 +0000 (+0100) Subject: sound, faster resampler for SMS FM X-Git-Tag: v2.00~162 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43ef4071dac81b19cdb8fbfa5866806ccedf882c;p=picodrive.git sound, faster resampler for SMS FM --- diff --git a/pico/pico_int.h b/pico/pico_int.h index b8e788e4..e74a4ac2 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -346,6 +346,7 @@ struct PicoMisc #define PMS_HW_LCD 0x2 // GG LCD #define PMS_HW_JAP 0x4 // japanese system #define PMS_HW_FM 0x8 // FM sound +#define PMS_HW_FMUSED 0x10 // FM sound accessed #define PMS_MAP_AUTO 0 #define PMS_MAP_SEGA 1 diff --git a/pico/sms.c b/pico/sms.c index 52a36b3d..398a4da3 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -221,6 +221,7 @@ static void z80_sms_out(unsigned short a, unsigned char d) { case 0xf0: // FM reg port + Pico.m.hardware |= PMS_HW_FMUSED; YM2413_regWrite(d); break; case 0xf1: diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 9c7a9289..c31c2cf4 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -27,8 +27,11 @@ s16 cdda_out_buffer[2*1152]; // sn76496 extern int *sn76496_regs; +// FM resampling polyphase FIR +static resampler_t *fmresampler; +static int (*PsndFMUpdate)(s32 *buffer, int length, int stereo, int is_buf_empty); + // ym2413 -#define YM2413_CLK 3579545 static OPLL *opll = NULL; static OPLL old_opll; static struct { @@ -36,6 +39,14 @@ static struct { uint8_t reg[sizeof(opll->reg)]; } opll_buf; + +void YM2413_regWrite(unsigned data){ + OPLL_writeIO(opll,0,data); +} +void YM2413_dataWrite(unsigned data){ + OPLL_writeIO(opll,1,data); +} + PICO_INTERNAL void *YM2413GetRegs(void) { memcpy(opll_buf.reg, opll->reg, sizeof(opll->reg)); @@ -54,12 +65,9 @@ PICO_INTERNAL void YM2413UnpackState(void) opll->adr = opll_buf.adr; } -static resampler_t *fmresampler; -static int (*PsndFMUpdate)(s32 *buffer, int length, int stereo, int is_buf_empty); - PICO_INTERNAL void PsndInit(void) { - opll = OPLL_new(YM2413_CLK, PicoIn.sndRate); + opll = OPLL_new(OSC_NTSC/15, OSC_NTSC/15/72); OPLL_setChipType(opll,0); OPLL_reset(opll); } @@ -95,7 +103,25 @@ static int YM2612UpdateFIR(s32 *buffer, int length, int stereo, int is_buf_empty return ymchans; } -static void YM2612_setup_FIR(int inrate, int outrate, int stereo) +// resample SMS FM from its native 49716Hz/49262Hz with polyphase FIR filter +static void YM2413Update(s32 *buffer, int length, int stereo) +{ + while (length-- > 0) { + int16_t getdata = OPLL_calc(opll) * 3; + *buffer++ = getdata; + buffer += stereo; // only left for stereo, to be mixed to right later + } +} + +static int YM2413UpdateFIR(s32 *buffer, int length, int stereo, int is_buf_empty) +{ + if (!is_buf_empty) memset(buffer, 0, (length << stereo) * sizeof(*buffer)); + resampler_update(fmresampler, buffer, length, YM2413Update); + return 0; +} + +// FIR setup, looks for a close enough rational number matching the ratio +static void YMFM_setup_FIR(int inrate, int outrate, int stereo) { int mindiff = 999; int diff, mul, div; @@ -132,21 +158,31 @@ void PsndRerate(int preserve_state) void *state = NULL; int target_fps = Pico.m.pal ? 50 : 60; int target_lines = Pico.m.pal ? 313 : 262; + int sms_clock = Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15; int ym2612_clock = Pico.m.pal ? OSC_PAL/7 : OSC_NTSC/7; int ym2612_rate = YM2612_NATIVE_RATE(); + int ym2413_rate = (sms_clock + 36) / 72; if (preserve_state) { state = malloc(0x204); if (state == NULL) return; ym2612_pack_state(); memcpy(state, YM2612GetRegs(), 0x204); + + if (opll != NULL) + memcpy(&old_opll, opll, sizeof(OPLL)); // remember old state } - if ((PicoIn.opt & POPT_EN_FM_FILTER) && ym2612_rate != PicoIn.sndRate) { + if (PicoIn.AHW & PAHW_SMS) { + OPLL_setRate(opll, ym2413_rate); + OPLL_reset(opll); + YMFM_setup_FIR(ym2413_rate, PicoIn.sndRate, 0); + PsndFMUpdate = YM2413UpdateFIR; + } else if ((PicoIn.opt & POPT_EN_FM_FILTER) && ym2612_rate != PicoIn.sndRate) { // polyphase FIR resampler, resampling directly from native to output rate YM2612Init(ym2612_clock, ym2612_rate, ((PicoIn.opt&POPT_DIS_FM_SSGEG) ? 0 : ST_SSG) | ((PicoIn.opt&POPT_EN_FM_DAC) ? ST_DAC : 0)); - YM2612_setup_FIR(ym2612_rate, PicoIn.sndRate, PicoIn.opt & POPT_EN_STEREO); + YMFM_setup_FIR(ym2612_rate, PicoIn.sndRate, PicoIn.opt & POPT_EN_STEREO); PsndFMUpdate = YM2612UpdateFIR; } else { YM2612Init(ym2612_clock, PicoIn.sndRate, @@ -158,20 +194,17 @@ void PsndRerate(int preserve_state) // feed it back it's own registers, just like after loading state memcpy(YM2612GetRegs(), state, 0x204); ym2612_unpack_state(); + + if (opll != NULL) { + memcpy(&opll->adr, &old_opll.adr, sizeof(OPLL)-20); // restore old state + OPLL_forceRefresh(opll); + } } if (preserve_state) memcpy(state, sn76496_regs, 28*4); // remember old state SN76496_init(Pico.m.pal ? OSC_PAL/15 : OSC_NTSC/15, PicoIn.sndRate); if (preserve_state) memcpy(sn76496_regs, state, 28*4); // restore old state - if(opll != NULL){ - if (preserve_state) memcpy(&old_opll, opll, sizeof(OPLL)); // remember old state - OPLL_setRate(opll, PicoIn.sndRate); - OPLL_reset(opll); - if (preserve_state) memcpy(&opll->adr, &old_opll.adr, sizeof(OPLL)-20); // restore old state - OPLL_forceRefresh(opll); - } - if (state) free(state); @@ -284,12 +317,12 @@ PICO_INTERNAL void PsndDoPSG(int cyc_to) SN76496Update(PicoIn.sndOut + pos, len, stereo); } -#if 0 -PICO_INTERNAL void PsndDoYM2413(int cyc_to) +PICO_INTERNAL void PsndDoSMSFM(int cyc_to) { int pos, len; int stereo = 0; - s16 *buf; + s32 *buf32 = PsndBuffer; + s16 *buf = PicoIn.sndOut; // nothing to do if sound is off if (!PicoIn.sndOut) return; @@ -312,22 +345,15 @@ PICO_INTERNAL void PsndDoYM2413(int cyc_to) pos <<= 1; } - buf = PicoIn.sndOut + pos; - while (len-- > 0) { - int16_t getdata = OPLL_calc(opll) * 3; - *buf++ += getdata; - buf += stereo; // only left for stereo, to be mixed to right later + if (Pico.m.hardware & PMS_HW_FMUSED) { + buf += pos; + PsndFMUpdate(buf32, len, 0, 0); + while (len--) { + *buf++ += *buf32++; + buf += stereo; + } } } -#endif - -void YM2413_regWrite(unsigned data){ - OPLL_writeIO(opll,0,data); -} -void YM2413_dataWrite(unsigned data){ - OPLL_writeIO(opll,1,data); -} - PICO_INTERNAL void PsndDoFM(int cyc_to) { @@ -515,6 +541,7 @@ PICO_INTERNAL void PsndGetSamples(int y) static int PsndRenderMS(int offset, int length) { + s32 *buf32 = PsndBuffer; int stereo = (PicoIn.opt & 8) >> 3; int psglen = ((Pico.snd.psg_pos+0x80000) >> 20); int ym2413len = ((Pico.snd.ym2413_pos+0x80000) >> 20); @@ -536,11 +563,11 @@ static int PsndRenderMS(int offset, int length) s16 *ym2413buf = PicoIn.sndOut + (ym2413len << stereo); Pico.snd.ym2413_pos += (length-ym2413len) << 20; int len = (length-ym2413len); - if (PicoIn.opt & POPT_EN_YM2413){ - while (len-- > 0) { - int16_t getdata = OPLL_calc(opll) * 3; - *ym2413buf += getdata; - ym2413buf += 1<