From 882f697ad4fce9005b5bd25a01bfc8497f4d533c Mon Sep 17 00:00:00 2001 From: kub Date: Sun, 6 Mar 2022 20:40:50 +0000 Subject: [PATCH] sound, add native rate mode, change resampling --- pico/pico_int.h | 2 + pico/sound/sound.c | 2 +- pico/sound/ym2612.c | 108 ++++++++-------------- pico/sound/ym2612_arm.S | 83 ++--------------- platform/common/config_file.c | 2 +- platform/common/emu.c | 5 +- platform/common/menu_pico.c | 20 ++-- platform/gp2x/emu.c | 2 +- platform/libretro/libretro.c | 10 +- platform/libretro/libretro_core_options.h | 3 +- platform/psp/emu.c | 2 + 11 files changed, 81 insertions(+), 158 deletions(-) diff --git a/pico/pico_int.h b/pico/pico_int.h index 85df6c5b..e95060b0 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -853,6 +853,8 @@ extern short cdda_out_buffer[2*1152]; void cdda_start_play(int lba_base, int lba_offset, int lb_len); +#define YM2612_NATIVE_RATE() (((Pico.m.pal?OSC_PAL:OSC_NTSC)/7 + 3*24) / (6*24)) + void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new); void ym2612_pack_state(void); void ym2612_unpack_state(void); diff --git a/pico/sound/sound.c b/pico/sound/sound.c index 06d3625a..591a0299 100644 --- a/pico/sound/sound.c +++ b/pico/sound/sound.c @@ -18,7 +18,7 @@ void (*PsndMix_32_to_16l)(s16 *dest, s32 *src, int count) = mix_32_to_16l_stereo // master int buffer to mix to // +1 for a fill triggered by an instruction overhanging into the next scanline -static s32 PsndBuffer[2*(44100+100)/50+2]; +static s32 PsndBuffer[2*(53267+100)/50+2]; // cdda output buffer s16 cdda_out_buffer[2*1152]; diff --git a/pico/sound/ym2612.c b/pico/sound/ym2612.c index 95dca6a9..e7e3a8a8 100644 --- a/pico/sound/ym2612.c +++ b/pico/sound/ym2612.c @@ -974,7 +974,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig ct->mem = op_calc(ct->phase2, eg_out2, c1); } else ct->mem = 0; - if (ct->eg_timer >= (1<phase3, eg_out, m2); @@ -993,7 +992,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */ ct->mem+= op_calc(ct->phase2, eg_out2, 0); } - if (ct->eg_timer >= (1<phase3, eg_out, m2); @@ -1013,7 +1011,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig ct->mem = op_calc(ct->phase2, eg_out2, 0); } else ct->mem = 0; - if (ct->eg_timer >= (1<phase3, eg_out, m2); @@ -1033,7 +1030,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig ct->mem = op_calc(ct->phase2, eg_out2, c1); } else ct->mem = 0; - if (ct->eg_timer >= (1<phase3, eg_out, 0); @@ -1048,7 +1044,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig /* M1---C1-+-OUT */ /* M2---C2-+ */ /* MEM: not used */ - if (ct->eg_timer >= (1<op1_out>>16; if( eg_out < ENV_QUIET ) { /* SLOT 3 */ @@ -1069,7 +1064,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig /* +----C2----+ */ m2 = ct->mem; ct->mem = c1 = c2 = ct->op1_out>>16; - if (ct->eg_timer >= (1<phase3, eg_out, m2); @@ -1088,7 +1082,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig /* M2-+-OUT */ /* C2-+ */ /* MEM: not used */ - if (ct->eg_timer >= (1<op1_out>>16; if( eg_out < ENV_QUIET ) { /* SLOT 3 */ @@ -1109,7 +1102,6 @@ static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsig /* M2-+ */ /* C2-+ */ /* MEM: not used*/ - if (ct->eg_timer >= (1<op1_out>>16; if( eg_out < ENV_QUIET ) { /* SLOT 3 */ @@ -1139,20 +1131,6 @@ static void chan_render_loop(chan_rend_context *ct, s32 *buffer, int length) ct->eg_timer += ct->eg_timer_add; - if (ct->eg_timer >= 3<pack&0xf000)) { - int cnt = (ct->eg_timer>>EG_SH)-2; - if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */ - int inc = cnt*ct->lfo_inc; - ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + inc) << 16); - ct->lfo_cnt += inc; - } - - ct->phase1 += cnt*ct->incr1; - ct->phase2 += cnt*ct->incr2; - ct->phase3 += cnt*ct->incr3; - ct->phase4 += cnt*ct->incr4; - } - while (ct->eg_timer >= 1<eg_timer -= 1<vol_out1 = ct->CH->SLOT[SLOT1].vol_out; - ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_out; - ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_out; - ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_out; - - if (ct->eg_timer < (2<pack&0xf000)) { - if (ct->pack & 4) goto disabled; /* output disabled */ + ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_out; + ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_out; + ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_out; + ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_out; - if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */ - ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16); - ct->lfo_cnt += ct->lfo_inc; - } + if (ct->pack & 4) goto disabled; /* output disabled */ - /* calculate channel sample */ - eg_out = ct->vol_out1; - if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) ) - eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24); + if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */ + ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16); + ct->lfo_cnt += ct->lfo_inc; + } - if( eg_out < ENV_QUIET ) /* SLOT 1 */ - { - int out = 0; + /* calculate channel sample */ + eg_out = ct->vol_out1; + if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) ) + eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24); - if (ct->pack&0xf000) out = ((ct->op1_out + (ct->op1_out<<16))>>16) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */ - ct->op1_out <<= 16; - ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out); - } else { - ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */ - } + if( eg_out < ENV_QUIET ) /* SLOT 1 */ + { + int out = 0; - if (ct->eg_timer < (2<vol_out3; // volume_calc(&CH->SLOT[SLOT3]); - eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]); - eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]); + if (ct->pack&0xf000) out = ((ct->op1_out + (ct->op1_out<<16))>>16) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */ + ct->op1_out <<= 16; + ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out); + } else { + ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */ + } - if (ct->pack & 8) { - unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24); - if (ct->pack & (1<<(SLOT3+8))) eg_out += add; - if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add; - if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add; - } + eg_out = ct->vol_out3; // volume_calc(&CH->SLOT[SLOT3]); + eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]); + eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]); - smp = update_algo_channel(ct, eg_out, eg_out2, eg_out4); - } - /* done calculating channel sample */ + if (ct->pack & 8) { + unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24); + if (ct->pack & (1<<(SLOT3+8))) eg_out += add; + if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add; + if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add; + } + smp = update_algo_channel(ct, eg_out, eg_out2, eg_out4); + /* done calculating channel sample */ disabled: - /* update phase counters AFTER output calculations */ - ct->phase1 += ct->incr1; - ct->phase2 += ct->incr2; - ct->phase3 += ct->incr3; - ct->phase4 += ct->incr4; - } - - } + /* update phase counters AFTER output calculations */ + ct->phase1 += ct->incr1; + ct->phase2 += ct->incr2; + ct->phase3 += ct->incr3; + ct->phase4 += ct->incr4; /* mix sample to output buffer */ if (smp) { @@ -1615,7 +1587,7 @@ static void OPNSetPres(int pres) double freqbase = (ym2612.OPN.ST.rate) ? ((double)ym2612.OPN.ST.clock / ym2612.OPN.ST.rate) / pres : 0; ym2612.OPN.eg_timer_add = (1< 44100) + if (PicoIn.sndRate < 8000 || PicoIn.sndRate > 53267) PicoIn.sndRate = 22050; if (*tmp == 'H' || *tmp == 'h') tmp++; if (*tmp == 'Z' || *tmp == 'z') tmp++; diff --git a/platform/common/emu.c b/platform/common/emu.c index b233050a..63a10a38 100644 --- a/platform/common/emu.c +++ b/platform/common/emu.c @@ -57,7 +57,7 @@ int pico_inp_mode; int flip_after_sync; int engineState = PGS_Menu; -static short __attribute__((aligned(4))) sndBuffer[2*44100/50]; +static short __attribute__((aligned(4))) sndBuffer[2*53267/50]; /* tmp buff to reduce stack usage for plats with small stack */ static char static_buff[512]; @@ -1328,6 +1328,9 @@ void emu_sound_start(void) { PicoIn.sndOut = NULL; + // auto-select rate? + if (PicoIn.sndRate > 52000) + PicoIn.sndRate = YM2612_NATIVE_RATE(); if (currentConfig.EmuOpt & EOPT_EN_SOUND) { int is_stereo = (PicoIn.opt & POPT_EN_STEREO) ? 1 : 0; diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 65e08a01..fc9e769e 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -595,24 +595,24 @@ static int menu_loop_adv_options(int id, int keys) static int sndrate_prevnext(int rate, int dir) { - static const int rates[] = { 8000, 11025, 16000, 22050, 44100 }; + static const int rates[] = { 8000, 11025, 16000, 22050, 44100, 53000 }; int i; - for (i = 0; i < 5; i++) + for (i = 0; i < 6; i++) if (rates[i] == rate) break; i += dir ? 1 : -1; - if (i > 4) { + if (i > 5) { if (!(PicoIn.opt & POPT_EN_STEREO)) { PicoIn.opt |= POPT_EN_STEREO; return rates[0]; } - return rates[4]; + return rates[5]; } if (i < 0) { if (PicoIn.opt & POPT_EN_STEREO) { PicoIn.opt &= ~POPT_EN_STEREO; - return rates[4]; + return rates[5]; } return rates[0]; } @@ -630,7 +630,9 @@ static const char *mgn_opt_sound(int id, int *offs) const char *str2; *offs = -8; str2 = (PicoIn.opt & POPT_EN_STEREO) ? "stereo" : "mono"; - sprintf(static_buff, "%5iHz %s", PicoIn.sndRate, str2); + if (PicoIn.sndRate > 52000) + sprintf(static_buff, "native %s\n", str2); + else sprintf(static_buff, "%5iHz %s", PicoIn.sndRate, str2); return static_buff; } @@ -652,12 +654,14 @@ static const char *mgn_opt_alpha(int id, int *offs) return static_buff; } +static const char h_quality[] = "native is the FM sound chip rate (53267/52781 Hz),\n" + "select this for the best FM sound quality"; static const char h_lowpass[] = "Low pass filter for sound closer to real hardware"; static menu_entry e_menu_snd_options[] = { mee_onoff ("Enable sound", MA_OPT_ENABLE_SOUND, currentConfig.EmuOpt, EOPT_EN_SOUND), - mee_cust ("Sound Quality", MA_OPT_SOUND_QUALITY, mh_opt_snd, mgn_opt_sound), + mee_cust_h ("Sound Quality", MA_OPT_SOUND_QUALITY, mh_opt_snd, mgn_opt_sound, h_quality), mee_onoff_h ("Sound filter", MA_OPT_SOUND_FILTER, PicoIn.opt, POPT_EN_SNDFILTER, h_lowpass), mee_cust ("Filter strength", MA_OPT_SOUND_ALPHA, mh_opt_alpha, mgn_opt_alpha), mee_end, @@ -667,6 +671,8 @@ static int menu_loop_snd_options(int id, int keys) { static int sel = 0; + if (PicoIn.sndRate > 52000) + PicoIn.sndRate = 53000; me_loop(e_menu_snd_options, &sel); return 0; diff --git a/platform/gp2x/emu.c b/platform/gp2x/emu.c index 37ee82cf..92ea2ec6 100644 --- a/platform/gp2x/emu.c +++ b/platform/gp2x/emu.c @@ -731,7 +731,7 @@ void pemu_sound_start(void) } } -static const int sound_rates[] = { 44100, 32000, 22050, 16000, 11025, 8000 }; +static const int sound_rates[] = { 53000, 44100, 32000, 22050, 16000, 11025, 8000 }; void pemu_sound_stop(void) { diff --git a/platform/libretro/libretro.c b/platform/libretro/libretro.c index 99fc826a..00cf4da5 100644 --- a/platform/libretro/libretro.c +++ b/platform/libretro/libretro.c @@ -1316,6 +1316,8 @@ bool retro_load_game(const struct retro_game_info *info) PicoIn.writeSound = snd_write; memset(sndBuffer, 0, sizeof(sndBuffer)); PicoIn.sndOut = sndBuffer; + if (PicoIn.sndRate > 52000) + PicoIn.sndRate = YM2612_NATIVE_RATE(); PsndRerate(0); apply_renderer(); @@ -1566,7 +1568,9 @@ static void update_variables(bool first_run) { PicoDetectRegion(); PicoLoopPrepare(); - PsndRerate(1); + if (PicoIn.sndRate > 52000) + PicoIn.sndRate = YM2612_NATIVE_RATE(); + PsndRerate(!first_run); } old_vout_aspect = vout_aspect; @@ -1687,10 +1691,12 @@ static void update_variables(bool first_run) var.key = "picodrive_sound_rate"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { new_sound_rate = atoi(var.value); + if (!strcmp(var.value, "native")) + new_sound_rate = YM2612_NATIVE_RATE(); if (new_sound_rate != PicoIn.sndRate) { /* Update the sound rate */ PicoIn.sndRate = new_sound_rate; - PsndRerate(1); + PsndRerate(!first_run); struct retro_system_av_info av_info; retro_get_system_av_info(&av_info); environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); diff --git a/platform/libretro/libretro_core_options.h b/platform/libretro/libretro_core_options.h index 6e627d49..4a8a9d47 100644 --- a/platform/libretro/libretro_core_options.h +++ b/platform/libretro/libretro_core_options.h @@ -207,7 +207,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { "picodrive_sound_rate", "Audio Sample Rate (Hz)", "Sample Rate (Hz)", - "Higher values increase sound quality. Lower values may increase performance.", + "Higher values increase sound quality. Lower values may increase performance. Native is the FM sound chip rate, either 53267 Hz for NTSC or 52781 Hz for PAL. Select this if you want the most accurate audio.", NULL, "audio", { @@ -215,6 +215,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { { "22050", NULL }, { "32000", NULL }, { "44100", NULL }, + { "native", NULL }, { NULL, NULL }, }, "44100" diff --git a/platform/psp/emu.c b/platform/psp/emu.c index b6d1a346..9c86203f 100644 --- a/platform/psp/emu.c +++ b/platform/psp/emu.c @@ -487,6 +487,8 @@ void pemu_sound_start(void) } } + if (PicoIn.sndRate > 52000) + PicoIn.sndRate = YM2612_NATIVE_RATE(); ret = POPT_EN_FM|POPT_EN_PSG|POPT_EN_STEREO; if (PicoIn.sndRate != PsndRate_old || (PicoIn.opt&ret) != (PicoOpt_old&ret) || Pico.m.pal != pal_old) { PsndRerate(Pico.m.frame_count ? 1 : 0); -- 2.39.5