sound, add native rate mode, change resampling

This commit is contained in:
kub 2022-03-06 20:40:50 +00:00
parent d26d4c2965
commit 882f697ad4
11 changed files with 90 additions and 167 deletions

View file

@ -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);

View file

@ -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];

View file

@ -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<<EG_SH)) break;
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
c2 = op_calc(ct->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<<EG_SH)) break;
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
c2 = op_calc(ct->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<<EG_SH)) break;
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
c2 += op_calc(ct->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<<EG_SH)) break;
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
c2 += op_calc(ct->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<<EG_SH)) break;
c1 = ct->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<<EG_SH)) break;
if( eg_out < ENV_QUIET ) { /* SLOT 3 */
smp = op_calc(ct->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<<EG_SH)) break;
c1 = ct->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<<EG_SH)) break;
smp = ct->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<<EG_SH && !(ct->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_SH) {
ct->eg_timer -= 1<<EG_SH;
@ -1168,62 +1146,56 @@ static void chan_render_loop(chan_rend_context *ct, s32 *buffer, int length)
update_eg_phase_channel(ct);
}
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->eg_timer < (2<<EG_SH) || (ct->pack&0xf000)) {
if (ct->pack & 4) goto disabled; /* output disabled */
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;
}
/* 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( eg_out < ENV_QUIET ) /* SLOT 1 */
{
int out = 0;
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->eg_timer < (2<<EG_SH)) {
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]);
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;
}
}
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 & 4) goto disabled; /* output disabled */
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;
}
/* 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( eg_out < ENV_QUIET ) /* SLOT 1 */
{
int out = 0;
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; */
}
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]);
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;
/* mix sample to output buffer */
if (smp) {
smp = clip(smp); /* saturate to 14 bit */
@ -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<<EG_SH) * freqbase;
ym2612.OPN.ST.freqbase = 1.0; // freqbase
ym2612.OPN.ST.freqbase = freqbase;
/* make time tables */
init_timetables( dt_tab );

View file

@ -327,9 +327,6 @@
@ r0-r2=scratch, r3=sin_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
.macro upd_algo0_m
cmp r8, #(1<<EG_SH)
bge 1f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -370,9 +367,6 @@
.macro upd_algo1_m
cmp r8, #(1<<EG_SH)
bge 1f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -413,9 +407,6 @@
.macro upd_algo2_m
cmp r8, #(1<<EG_SH)
bge 1f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -457,9 +448,6 @@
.macro upd_algo3_m
cmp r8, #(1<<EG_SH)
bge 1f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -501,9 +489,6 @@
.macro upd_algo4_m
cmp r8, #(1<<EG_SH)
bge 2f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -541,9 +526,6 @@
.macro upd_algo5_m
cmp r8, #(1<<EG_SH)
bge 2f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -584,9 +566,6 @@
.macro upd_algo6_m
cmp r8, #(1<<EG_SH)
bge 2f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -622,9 +601,6 @@
.macro upd_algo7_m
cmp r8, #(1<<EG_SH)
bge 2f
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
@ -709,53 +685,15 @@ crl_loop:
mov r0, #0
add r8, r8, r9
subs r8, r8, #(1<<EG_SH)
blt crl_smp_loop_end
blt eg_loop_done
cmp r8, #(2<<EG_SH) @ calculate only for operator memory, sample,
tstge r12, #0xf000 @ ...feedback
bne crl_smp_loop
@ -- LFO+PHASE UPDATE, FF --
mov r0, r8, lsr #EG_SH
sub r0, r0, #1
tst r12, #8 @ lfo?
beq lfo_done_ff
ldr r2, [lr, #0x34] @ lfo_inc
ldr r1, [lr, #0x30] @ lfo_cnt
mul r2, r0, r2
add r2, r2, r1
str r2, [lr, #0x30]
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt
advance_lfo_m
lfo_done_ff:
add lr, lr, #0x10
ldmia lr, {r1-r3,r5-r7}
mul r6, r0, r6
mul r7, r0, r7
add r1, r1, r6
add r2, r2, r7
ldr r6, [lr, #0x18]
ldr r7, [lr, #0x1c]
mul r6, r0, r6
mul r7, r0, r7
add r3, r3, r6
add r5, r5, r7
stmia lr, {r1-r3,r5}
sub lr, lr, #0x10
crl_smp_loop:
crl_eg_loop:
ldr r5, [lr, #0x40] @ CH
#if defined(SSG_EG)
tst r12, #0x02 @ ssg_enabled?
beq ssg_done
@ -- SSG --
ssg_loop:
mov r6, #4
ssg_upd_loop:
@ use lr as a pointer to the slot phases stored in the context
@ -808,9 +746,11 @@ eg_upd_loop:
sub r5, r5, #SLOT_STRUCT_SIZE*3
eg_done:
cmp r8, #(2<<EG_SH) @ calculate only for operator memory, sample,
tstge r12, #0xf000 @ ...feedback
beq crl_ff
subs r8, r8, #(1<<EG_SH)
bge crl_eg_loop
eg_loop_done:
add r8, r8, #(1<<EG_SH)
@ -- disabled? --
mov r0, #0
@ -847,9 +787,6 @@ lfo_done:
upd_slot1_m
@ -- SLOT2+ --
cmp r8, #(2<<EG_SH) @ op mem or sample?
bge crl_algo_done
and r0, r4, #7
PIC_XB(,r0, lsl #2)
nop
@ -915,13 +852,7 @@ crl_algo_done:
stmia lr, {r1-r3,r5}
sub lr, lr, #0x10
crl_ff:
subs r8, r8, #(1<<EG_SH)
bge crl_smp_loop
crl_smp_loop_end:
add r8, r8, #(1<<EG_SH)
@ -- WRITE SAMPLE --
tst r0, r0
beq ctl_sample_skip

View file

@ -275,7 +275,7 @@ static int custom_read(menu_entry *me, const char *var, const char *val)
case MA_OPT_SOUND_QUALITY:
if (strcasecmp(var, "Sound Quality") != 0) return 0;
PicoIn.sndRate = strtoul(val, &tmp, 10);
if (PicoIn.sndRate < 8000 || PicoIn.sndRate > 44100)
if (PicoIn.sndRate < 8000 || PicoIn.sndRate > 53267)
PicoIn.sndRate = 22050;
if (*tmp == 'H' || *tmp == 'h') tmp++;
if (*tmp == 'Z' || *tmp == 'z') tmp++;

View file

@ -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;

View file

@ -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;

View file

@ -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)
{

View file

@ -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);

View file

@ -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"

View file

@ -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);