\r
void cdda_start_play(int lba_base, int lba_offset, int lb_len);\r
\r
+#define YM2612_NATIVE_RATE() (((Pico.m.pal?OSC_PAL:OSC_NTSC)/7 + 3*24) / (6*24))\r
+\r
void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new);\r
void ym2612_pack_state(void);\r
void ym2612_unpack_state(void);\r
\r
// master int buffer to mix to\r
// +1 for a fill triggered by an instruction overhanging into the next scanline\r
-static s32 PsndBuffer[2*(44100+100)/50+2];\r
+static s32 PsndBuffer[2*(53267+100)/50+2];\r
\r
// cdda output buffer\r
s16 cdda_out_buffer[2*1152];\r
ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
}\r
else ct->mem = 0;\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
c2 = op_calc(ct->phase3, eg_out, m2);\r
if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
ct->mem+= op_calc(ct->phase2, eg_out2, 0);\r
}\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
c2 = op_calc(ct->phase3, eg_out, m2);\r
ct->mem = op_calc(ct->phase2, eg_out2, 0);\r
}\r
else ct->mem = 0;\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
c2 += op_calc(ct->phase3, eg_out, m2);\r
ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
}\r
else ct->mem = 0;\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
c2 += op_calc(ct->phase3, eg_out, 0);\r
/* M1---C1-+-OUT */\r
/* M2---C2-+ */\r
/* MEM: not used */\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
c1 = ct->op1_out>>16;\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
/* +----C2----+ */\r
m2 = ct->mem;\r
ct->mem = c1 = c2 = ct->op1_out>>16;\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
smp = op_calc(ct->phase3, eg_out, m2);\r
/* M2-+-OUT */\r
/* C2-+ */\r
/* MEM: not used */\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
c1 = ct->op1_out>>16;\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
/* M2-+ */\r
/* C2-+ */\r
/* MEM: not used*/\r
- if (ct->eg_timer >= (1<<EG_SH)) break;\r
\r
smp = ct->op1_out>>16;\r
if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
\r
ct->eg_timer += ct->eg_timer_add;\r
\r
- if (ct->eg_timer >= 3<<EG_SH && !(ct->pack&0xf000)) {\r
- int cnt = (ct->eg_timer>>EG_SH)-2;\r
- if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */\r
- int inc = cnt*ct->lfo_inc;\r
- ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + inc) << 16);\r
- ct->lfo_cnt += inc;\r
- }\r
-\r
- ct->phase1 += cnt*ct->incr1;\r
- ct->phase2 += cnt*ct->incr2;\r
- ct->phase3 += cnt*ct->incr3;\r
- ct->phase4 += cnt*ct->incr4;\r
- }\r
-\r
while (ct->eg_timer >= 1<<EG_SH) {\r
ct->eg_timer -= 1<<EG_SH;\r
\r
\r
update_eg_phase_channel(ct);\r
}\r
+ }\r
\r
- ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_out;\r
- ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_out;\r
- ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_out;\r
- ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_out;\r
-\r
- if (ct->eg_timer < (2<<EG_SH) || (ct->pack&0xf000)) {\r
- if (ct->pack & 4) goto disabled; /* output disabled */\r
+ ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_out;\r
+ ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_out;\r
+ ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_out;\r
+ ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_out;\r
\r
- if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */\r
- ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16);\r
- ct->lfo_cnt += ct->lfo_inc;\r
- }\r
+ if (ct->pack & 4) goto disabled; /* output disabled */\r
\r
- /* calculate channel sample */\r
- eg_out = ct->vol_out1;\r
- if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) )\r
- eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
+ if (ct->pack & 8) { /* LFO enabled ? (test Earthworm Jim in between demo 1 and 2) */\r
+ ct->pack = (ct->pack&0xffff) | (advance_lfo(ct->pack >> 16, ct->lfo_cnt, ct->lfo_cnt + ct->lfo_inc) << 16);\r
+ ct->lfo_cnt += ct->lfo_inc;\r
+ }\r
\r
- if( eg_out < ENV_QUIET ) /* SLOT 1 */\r
- {\r
- int out = 0;\r
+ /* calculate channel sample */\r
+ eg_out = ct->vol_out1;\r
+ if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) )\r
+ eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
\r
- if (ct->pack&0xf000) out = ((ct->op1_out + (ct->op1_out<<16))>>16) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */\r
- ct->op1_out <<= 16;\r
- ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out);\r
- } else {\r
- ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */\r
- }\r
+ if( eg_out < ENV_QUIET ) /* SLOT 1 */\r
+ {\r
+ int out = 0;\r
\r
- if (ct->eg_timer < (2<<EG_SH)) {\r
- eg_out = ct->vol_out3; // volume_calc(&CH->SLOT[SLOT3]);\r
- eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]);\r
- eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]);\r
+ if (ct->pack&0xf000) out = ((ct->op1_out + (ct->op1_out<<16))>>16) << ((ct->pack&0xf000)>>12); /* op1_out0 + op1_out1 */\r
+ ct->op1_out <<= 16;\r
+ ct->op1_out |= (unsigned short)op_calc1(ct->phase1, eg_out, out);\r
+ } else {\r
+ ct->op1_out <<= 16; /* op1_out0 = op1_out1; op1_out1 = 0; */\r
+ }\r
\r
- if (ct->pack & 8) {\r
- unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
- if (ct->pack & (1<<(SLOT3+8))) eg_out += add;\r
- if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add;\r
- if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add;\r
- }\r
+ eg_out = ct->vol_out3; // volume_calc(&CH->SLOT[SLOT3]);\r
+ eg_out2 = ct->vol_out2; // volume_calc(&CH->SLOT[SLOT2]);\r
+ eg_out4 = ct->vol_out4; // volume_calc(&CH->SLOT[SLOT4]);\r
\r
- smp = update_algo_channel(ct, eg_out, eg_out2, eg_out4);\r
- }\r
- /* done calculating channel sample */\r
+ if (ct->pack & 8) {\r
+ unsigned int add = ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
+ if (ct->pack & (1<<(SLOT3+8))) eg_out += add;\r
+ if (ct->pack & (1<<(SLOT2+8))) eg_out2 += add;\r
+ if (ct->pack & (1<<(SLOT4+8))) eg_out4 += add;\r
+ }\r
\r
+ smp = update_algo_channel(ct, eg_out, eg_out2, eg_out4);\r
+ /* done calculating channel sample */\r
disabled:\r
- /* update phase counters AFTER output calculations */\r
- ct->phase1 += ct->incr1;\r
- ct->phase2 += ct->incr2;\r
- ct->phase3 += ct->incr3;\r
- ct->phase4 += ct->incr4;\r
- }\r
-\r
- }\r
+ /* update phase counters AFTER output calculations */\r
+ ct->phase1 += ct->incr1;\r
+ ct->phase2 += ct->incr2;\r
+ ct->phase3 += ct->incr3;\r
+ ct->phase4 += ct->incr4;\r
\r
/* mix sample to output buffer */\r
if (smp) {\r
double freqbase = (ym2612.OPN.ST.rate) ? ((double)ym2612.OPN.ST.clock / ym2612.OPN.ST.rate) / pres : 0;\r
\r
ym2612.OPN.eg_timer_add = (1<<EG_SH) * freqbase;\r
- ym2612.OPN.ST.freqbase = 1.0; // freqbase\r
+ ym2612.OPN.ST.freqbase = freqbase;\r
\r
/* make time tables */\r
init_timetables( dt_tab );\r
@ 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
.macro upd_algo1_m
- cmp r8, #(1<<EG_SH)
- bge 1f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo2_m
- cmp r8, #(1<<EG_SH)
- bge 1f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo3_m
- cmp r8, #(1<<EG_SH)
- bge 1f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo4_m
- cmp r8, #(1<<EG_SH)
- bge 2f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo5_m
- cmp r8, #(1<<EG_SH)
- bge 2f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo6_m
- cmp r8, #(1<<EG_SH)
- bge 2f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
.macro upd_algo7_m
- cmp r8, #(1<<EG_SH)
- bge 2f
-
@ SLOT3
make_eg_out SLOT3
cmp r1, #ENV_QUIET
mov r0, #0
add r8, r8, r9
subs r8, r8, #(1<<EG_SH)
- blt crl_smp_loop_end
-
- 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
+ blt eg_loop_done
-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
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
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
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
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++;
int flip_after_sync;\r
int engineState = PGS_Menu;\r
\r
-static short __attribute__((aligned(4))) sndBuffer[2*44100/50];\r
+static short __attribute__((aligned(4))) sndBuffer[2*53267/50];\r
\r
/* tmp buff to reduce stack usage for plats with small stack */\r
static char static_buff[512];\r
{\r
PicoIn.sndOut = NULL;\r
\r
+ // auto-select rate?\r
+ if (PicoIn.sndRate > 52000)\r
+ PicoIn.sndRate = YM2612_NATIVE_RATE();\r
if (currentConfig.EmuOpt & EOPT_EN_SOUND)\r
{\r
int is_stereo = (PicoIn.opt & POPT_EN_STEREO) ? 1 : 0;\r
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];
}
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;
}
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,
{
static int sel = 0;
+ if (PicoIn.sndRate > 52000)
+ PicoIn.sndRate = 53000;
me_loop(e_menu_snd_options, &sel);
return 0;
}\r
}\r
\r
-static const int sound_rates[] = { 44100, 32000, 22050, 16000, 11025, 8000 };\r
+static const int sound_rates[] = { 53000, 44100, 32000, 22050, 16000, 11025, 8000 };\r
\r
void pemu_sound_stop(void)\r
{\r
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();
{
PicoDetectRegion();
PicoLoopPrepare();
- PsndRerate(1);
+ if (PicoIn.sndRate > 52000)
+ PicoIn.sndRate = YM2612_NATIVE_RATE();
+ PsndRerate(!first_run);
}
old_vout_aspect = vout_aspect;
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);
"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",
{
{ "22050", NULL },
{ "32000", NULL },
{ "44100", NULL },
+ { "native", NULL },
{ NULL, NULL },
},
"44100"
}
}
+ 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);