\r
#endif\r
\r
-void memset32(int *dest, int c, int count);\r
+void memset32(void *dest, int c, int count);\r
\r
\r
#ifndef __GNUC__\r
but LFO works with one more bit of a precision so we really need 4096 elements */\r
static UINT32 fn_table[4096]; /* fnumber->increment counter */\r
\r
-static int g_lfo_ampm = 0;\r
+static int g_lfo_ampm;\r
\r
/* register number to channel number , slot offset */\r
#define OPN_CHAN(N) (N&3)\r
} else {\r
SLOT->volume = MIN_ATT_INDEX;\r
}\r
- recalc_volout(SLOT);\r
+// recalc_volout(SLOT);\r
ym2612.slot_mask |= (1<<s) << (c*4);\r
}\r
}\r
INLINE void set_tl(FM_SLOT *SLOT, int v)\r
{\r
SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */\r
- if (SLOT->state > EG_REL)\r
- recalc_volout(SLOT);\r
+// if (SLOT->state > EG_REL)\r
+// recalc_volout(SLOT);\r
}\r
\r
/* set attack rate & key scale */\r
return lfo_ampm;\r
}\r
\r
-INLINE void update_eg_phase(FM_SLOT *SLOT, UINT32 eg_cnt)\r
+INLINE void update_eg_phase(FM_SLOT *SLOT, UINT32 eg_cnt, UINT32 ssg_en)\r
{\r
INT32 volume = SLOT->volume;\r
UINT32 pack = SLOT->eg_pack[SLOT->state - 1];\r
eg_inc_val = pack >> ((eg_cnt >> shift) & 7) * 3;\r
eg_inc_val = (1 << (eg_inc_val & 7)) >> 1;\r
\r
- if (SLOT->ssg&0x08) {\r
+ if ((SLOT->ssg&0x08) && ssg_en) {\r
switch (SLOT->state)\r
{\r
case EG_ATT: /* attack phase */\r
SLOT->volume = volume;\r
}\r
\r
-INLINE void update_ssg_eg_phase(FM_SLOT *SLOT)\r
+INLINE UINT32 update_ssg_eg_phase(FM_SLOT *SLOT, UINT32 phase)\r
{\r
if (SLOT->ssg&0x01) {\r
if (SLOT->ssg&0x02) {\r
SLOT->ssg ^= 4;\r
SLOT->ssgn ^= 4;\r
} else\r
- SLOT->phase = 0;\r
+ phase = 0;\r
\r
if (SLOT->state != EG_ATT) {\r
SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC;\r
}\r
}\r
}\r
- recalc_volout(SLOT);\r
+// recalc_volout(SLOT);\r
+ return phase;\r
}\r
#endif\r
\r
int smp = 0; /* produced sample */\r
unsigned int eg_out, eg_out2, eg_out4;\r
FM_SLOT *SLOT;\r
+ UINT32 cnt = ct->eg_timer_add+(ct->eg_timer & ((1<<EG_SH)-1));\r
\r
- SLOT = &ct->CH->SLOT[SLOT1];\r
- if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);\r
- SLOT = &ct->CH->SLOT[SLOT2];\r
- if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);\r
- SLOT = &ct->CH->SLOT[SLOT3];\r
- if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);\r
- SLOT = &ct->CH->SLOT[SLOT4];\r
- if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200) update_ssg_eg_phase(SLOT);\r
+ if (ct->pack & 2) while (cnt >= 1<<EG_SH) {\r
+ cnt -= 1<<EG_SH;\r
+ SLOT = &ct->CH->SLOT[SLOT1];\r
+ if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)\r
+ ct->phase1 = update_ssg_eg_phase(SLOT, ct->phase1);\r
+ SLOT = &ct->CH->SLOT[SLOT2];\r
+ if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)\r
+ ct->phase2 = update_ssg_eg_phase(SLOT, ct->phase2);\r
+ SLOT = &ct->CH->SLOT[SLOT3];\r
+ if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)\r
+ ct->phase3 = update_ssg_eg_phase(SLOT, ct->phase3);\r
+ SLOT = &ct->CH->SLOT[SLOT4];\r
+ if ((SLOT->ssg&0x08) && SLOT->state > EG_REL && SLOT->volume >= 0x200)\r
+ ct->phase4 = update_ssg_eg_phase(SLOT, ct->phase4);\r
+ }\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
}\r
\r
ct->eg_timer += ct->eg_timer_add;\r
- while (ct->eg_timer >= EG_TIMER_OVERFLOW)\r
+ if (ct->eg_timer < EG_TIMER_OVERFLOW) {\r
+ SLOT = &ct->CH->SLOT[SLOT1];\r
+ SLOT->vol_ipol = SLOT->vol_out;\r
+ if (SLOT->state > EG_REL) recalc_volout(SLOT);\r
+ SLOT = &ct->CH->SLOT[SLOT2];\r
+ SLOT->vol_ipol = SLOT->vol_out;\r
+ if (SLOT->state > EG_REL) recalc_volout(SLOT);\r
+ SLOT = &ct->CH->SLOT[SLOT3];\r
+ SLOT->vol_ipol = SLOT->vol_out;\r
+ if (SLOT->state > EG_REL) recalc_volout(SLOT);\r
+ SLOT = &ct->CH->SLOT[SLOT4];\r
+ SLOT->vol_ipol = SLOT->vol_out;\r
+ if (SLOT->state > EG_REL) recalc_volout(SLOT);\r
+ }\r
+ else while (ct->eg_timer >= EG_TIMER_OVERFLOW)\r
{\r
ct->eg_timer -= EG_TIMER_OVERFLOW;\r
ct->eg_cnt++;\r
\r
SLOT = &ct->CH->SLOT[SLOT1];\r
SLOT->vol_ipol = SLOT->vol_out;\r
- if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
SLOT = &ct->CH->SLOT[SLOT2];\r
SLOT->vol_ipol = SLOT->vol_out;\r
- if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
SLOT = &ct->CH->SLOT[SLOT3];\r
SLOT->vol_ipol = SLOT->vol_out;\r
- if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
SLOT = &ct->CH->SLOT[SLOT4];\r
SLOT->vol_ipol = SLOT->vol_out;\r
- if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt);\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
}\r
+\r
#if 0\r
UINT32 ifrac0 = ct->eg_timer / (EG_TIMER_OVERFLOW>>EG_SH);\r
UINT32 ifrac1 = (1<<EG_SH) - ifrac0;\r
ct->CH->SLOT[SLOT3].vol_out) >> 1;\r
ct->vol_out4 = (ct->CH->SLOT[SLOT4].vol_ipol +\r
ct->CH->SLOT[SLOT4].vol_out) >> 1;\r
+ break;\r
}\r
#elif 0\r
if (ct->eg_timer >> (EG_SH-1) < EG_TIMER_OVERFLOW >> EG_SH) {\r
crct.mem = crct.CH->mem_value; /* one sample delay memory */\r
crct.lfo_cnt = ym2612.OPN.lfo_cnt;\r
\r
- flags &= 0x35;\r
+ flags &= 0x37;\r
\r
if (crct.lfo_inc) {\r
flags |= 8;\r
CH[c].mem_value = CH[c].op1_out = 0;\r
}\r
ym2612.slot_mask = 0;\r
+ ym2612.ssg_mask = 0;\r
}\r
\r
/* initialize generic tables */\r
case 0x90: /* SSG-EG */\r
SLOT->ssg = v&0x0f;\r
SLOT->ssg ^= SLOT->ssgn;\r
- if (SLOT->state > EG_REL)\r
- recalc_volout(SLOT);\r
+ if (v&0x08) ym2612.ssg_mask |= 1<<(OPN_SLOT(r) + c*4);\r
+ else ym2612.ssg_mask &= ~(1<<(OPN_SLOT(r) + c*4));\r
+// if (SLOT->state > EG_REL)\r
+// recalc_volout(SLOT);\r
break;\r
\r
case 0xa0:\r
{\r
int pan;\r
int active_chs = 0;\r
+ int flags = stereo ? 1:0;\r
\r
// if !is_buf_empty, it means it has valid samples to mix with, else it may contain trash\r
if (is_buf_empty) memset32(buffer, 0, length<<stereo);\r
refresh_fc_eg_chan( &ym2612.CH[5] );\r
\r
pan = ym2612.OPN.pan;\r
- if (stereo) stereo = 1;\r
\r
/* mix to 32bit dest */\r
- // flags: stereo, ?, disabled, ?, pan_r, pan_l\r
+ // flags: stereo, ssg_enabled, disabled, _, pan_r, pan_l\r
chan_render_prep();\r
- if (ym2612.slot_mask & 0x00000f) active_chs |= chan_render(buffer, length, 0, stereo|((pan&0x003)<<4)) << 0;\r
- if (ym2612.slot_mask & 0x0000f0) active_chs |= chan_render(buffer, length, 1, stereo|((pan&0x00c)<<2)) << 1;\r
- if (ym2612.slot_mask & 0x000f00) active_chs |= chan_render(buffer, length, 2, stereo|((pan&0x030) )) << 2;\r
- if (ym2612.slot_mask & 0x00f000) active_chs |= chan_render(buffer, length, 3, stereo|((pan&0x0c0)>>2)) << 3;\r
- if (ym2612.slot_mask & 0x0f0000) active_chs |= chan_render(buffer, length, 4, stereo|((pan&0x300)>>4)) << 4;\r
- if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, stereo|((pan&0xc00)>>6)|(ym2612.dacen<<2)) << 5;\r
+#define BIT_IF(v,b,c) { v &= ~(1<<(b)); if (c) v |= 1<<(b); }\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0x00000f));\r
+ if (ym2612.slot_mask & 0x00000f) active_chs |= chan_render(buffer, length, 0, flags|((pan&0x003)<<4)) << 0;\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0x0000f0));\r
+ if (ym2612.slot_mask & 0x0000f0) active_chs |= chan_render(buffer, length, 1, flags|((pan&0x00c)<<2)) << 1;\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0x000f00));\r
+ if (ym2612.slot_mask & 0x000f00) active_chs |= chan_render(buffer, length, 2, flags|((pan&0x030) )) << 2;\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0x00f000));\r
+ if (ym2612.slot_mask & 0x00f000) active_chs |= chan_render(buffer, length, 3, flags|((pan&0x0c0)>>2)) << 3;\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0x0f0000));\r
+ if (ym2612.slot_mask & 0x0f0000) active_chs |= chan_render(buffer, length, 4, flags|((pan&0x300)>>4)) << 4;\r
+ BIT_IF(flags, 1, (ym2612.ssg_mask & 0xf00000));\r
+ if (ym2612.slot_mask & 0xf00000) active_chs |= chan_render(buffer, length, 5, flags|((pan&0xc00)>>6)|(!!ym2612.dacen<<2)) << 5;\r
+#undef BIT_IF\r
chan_render_finish();\r
\r
return active_chs; // 1 if buffer updated\r
@ very simple YM2612 output rate to sample rate adaption (~500k cycles @44100)
#define INTERPOL
+#define SSG_EG
.equiv SLOT1, 0
.equiv SLOT2, 2
and r3, r3, #7 @ eg_inc_val shift, may be 0
ldrb r2, [r5,#0x17] @ state
+#if defined(SSG_EG)
tst r0, #0x08 @ ssg enabled?
+ tstne r12, #0x02
bne 9f
+#endif
@ non-SSG-EG mode
cmp r2, #4 @ EG_ATT
strgeb r3, [r5,#0x17] @ state
10: @ finish
+ ldrh r3, [r5,#0x18] @ tl
strh r0, [r5,#0x1a] @ volume
+#if defined(SSG_EG)
b 11f
9: @ SSG-EG mode
movlt r3, r0, lsl r3
ldrlth r0, [r5,#0x1a] @ volume, unsigned (0-1023)
movlt r3, r3, lsr #1 @ eg_inc_val
- addlt r0, r0, r3, lsr #2
+ addlt r0, r0, r3, lsl #2
cmp r2, #2
blt 1f @ EG_REL
strh r0, [r5,#0x1a] @ volume
cmp r2, #0x0c @ if ( ssg&0x04 && state > EG_REL )
cmpge r3, #EG_REL+1
+ ldrh r3, [r5,#0x18] @ tl
rsbge r0, r0, #0x200 @ volume = (0x200-volume) & MAX_ATT
- lslge r0, r0, #10
- lsrge r0, r0, #10
+ lslge r0, r0, #22
+ lsrge r0, r0, #22
11:
- ldrh r3, [r5,#0x18] @ tl
+#endif
add r0, r0, r3 @ volume += tl
strh r0, [r5,#0x34] @ vol_out
0: @ EG_OFF
.endm
+#if defined(SSG_EG)
@ r5=slot, trashes: r0,r2,r3
.macro update_ssg_eg
ldrh r0, [r5,#0x30] @ ssg+ssgn
cmp r2, #EG_REL+1 @ state > EG_REL &&
cmpge r3, #0x200 @ volume >= 0x200?
blt 9f
+ orr r4, r4, #0x10 @ ssg_update
tst r0, #0x01
beq 1f
9:
.endm
+@ r5=slot, trashes: r0,r2,r3
+.macro recalc_volout
+#if defined(INTERPOL)
+ ldrh r0, [r5,#0x34] @ vol_out
+#endif
+ ldrb r2, [r5,#0x30] @ ssg
+ ldrb r3, [r5,#0x17] @ state
+#if defined(INTERPOL)
+ strh r0, [r5,#0x36] @ vol_ipol
+#endif
+ ldrh r0, [r5,#0x1a] @ volume
+
+@ and r2, r2, #0x0c
+ cmp r2, #0x0c @ if ( ~ssg&0x0c && state > EG_REL )
+ cmpge r3, #EG_REL+1
+ ldrh r3, [r5,#0x18] @ tl
+ rsbge r0, r0, #0x200 @ volume = (0x200-volume) & MAX_ATT
+ lslge r0, r0, #22
+ lsrge r0, r0, #22
+ ldrh r0, [r5,#0x1a] @ volume
+ ldrh r3, [r5,#0x18] @ tl
+
+ add r0, r0, r3 @ volume += tl
+ strh r0, [r5,#0x34] @ vol_out
+.endm
+#endif
+
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt, r3=scratch
.macro advance_lfo_m
mov r2, r2, lsr #LFO_SH
.endm
-@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
+@ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
@ r0-r2=scratch, r3=sin_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
.macro upd_algo0_m
.endm
-@ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
-@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[4],was_update,algo[3], r5=tl_tab/slot,
+@ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
+@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|unused[3],ssg_update,was_update,algo[3], r5=tl_tab/slot,
@ r6-r7=vol_out[4], r8=eg_timer, r9=eg_timer_add[31:16], r10=op1_out, r11=buffer
.global chan_render_loop @ chan_rend_context *ct, int *buffer, int length
subs r4, r4, #0x100
bmi crl_loop_end
- @ -- SSG --
ldr r5, [lr, #0x40] @ CH
+#if defined(SSG_EG)
+ tst r12, #0x02 @ ssg_enabled?
+ beq ssg_done
+ @ -- SSG --
+ lsl r7, r8, #EG_SH
+ add r7, r9, r7, lsr #EG_SH
+ subs r7, r7, #1<<EG_SH
+ blt ssg_done
- @ r5=slot, trashes: r0,r2,r3
+ssg_loop:
mov r6, #4
ssg_upd_loop:
update_ssg_eg
bne ssg_upd_loop
sub r5, r5, #SLOT_STRUCT_SIZE*3
+ subs r7, r7, #1<<EG_SH
+ bge ssg_loop
+ssg_done:
+#endif
+
@ -- EG --
add r8, r8, r9
cmp r8, #EG_TIMER_OVERFLOW
- bcc eg_done
+ bcc volout_upd
ldr r1, [lr, #0x3c] @ eg_cnt
eg_loop:
sub r8, r8, #EG_TIMER_OVERFLOW
sub r5, r5, #SLOT_STRUCT_SIZE*3
bhs eg_loop
str r1, [lr, #0x3c]
+ b eg_done
-eg_done:
+volout_upd:
+#if defined(SSG_EG)
+ tst r4, #0x10 @ ssg_update?
+ beq eg_done
+
+ @ recalc vol_out
+ mov r6, #4
+volout_loop:
+ recalc_volout
+#if 0
+ subs r6, r6, #1
+ addne r5, r5, #SLOT_STRUCT_SIZE
+#else
+ add r5, r5, #SLOT_STRUCT_SIZE*2
+ recalc_volout
+ subs r6, r6, #2
+ subne r5, r5, #SLOT_STRUCT_SIZE
+#endif
+ bne volout_loop
+ sub r5, r5, #SLOT_STRUCT_SIZE*3
+#endif
+eg_done:
@ -- disabled? --
and r0, r12, #0xC
cmp r0, #0xC
@ -- SLOT1 --
PIC_LDR(r3, r2, ym_tl_tab)
- @ lr=context, r12=pack (stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
+ @ lr=context, r12=pack (stereo, ssg_enabled, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16])
@ r0-r2=scratch, r3=tl_tab, r5=scratch, r6-r7=vol_out[4], r10=op1_out
upd_slot1_m