**\r
** updated with fixes from mame 0.216 (file version 1.5.1) (kub)\r
** SSG-EG readded from GenPlus (kub)\r
-** linear sample interpolation for chip to output rate adaption (kub)\r
*/\r
\r
/*\r
UINT32 eg_timer;\r
UINT32 eg_timer_add;\r
UINT32 pack; // 4c: stereo, lastchan, disabled, lfo_enabled | pan_r, pan_l, ams[2] | AMmasks[4] | FB[4] | lfo_ampm[16]\r
- UINT32 algo; /* 50: algo[3], was_update */\r
+ UINT32 algo; /* 50: algo[3], was_update, unsued, upd_cnt[2], dac */\r
INT32 op1_out;\r
#ifdef _MIPS_ARCH_ALLEGREX\r
UINT32 pad1[3+8];\r
#include <limits.h>\r
static int clip(int n) \r
{\r
- unsigned b = 14, s = n < 0;\r
- int m = s + INT_MAX;\r
- if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);\r
- return n;\r
+ unsigned b = 14, s = n < 0;\r
+ int m = s + INT_MAX;\r
+ if (s + (n>>(b-1))) n = m >> (8*sizeof(int)-b);\r
+ return n;\r
}\r
\r
-static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)\r
+static void update_ssg_eg_channel(chan_rend_context *ct)\r
{\r
- int scounter; /* sample counter */\r
+ FM_SLOT *SLOT;\r
\r
- /* sample generating loop */\r
- for (scounter = 0; scounter < length; scounter++)\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
+static void update_eg_phase_channel(chan_rend_context *ct)\r
+{\r
+ FM_SLOT *SLOT;\r
+\r
+ SLOT = &ct->CH->SLOT[SLOT1];\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
+ SLOT = &ct->CH->SLOT[SLOT2];\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
+ SLOT = &ct->CH->SLOT[SLOT3];\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
+ SLOT = &ct->CH->SLOT[SLOT4];\r
+ if (SLOT->state != EG_OFF) update_eg_phase(SLOT, ct->eg_cnt, ct->pack & 2);\r
+}\r
+\r
+static int update_algo_channel(chan_rend_context *ct, unsigned int eg_out, unsigned int eg_out2, unsigned int eg_out4)\r
+{\r
+ int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */\r
+ int smp = 0;\r
+\r
+ switch( ct->algo&0x7 )\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
- 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
+ case 0:\r
+ {\r
+ /* M1---C1---MEM---M2---C2---OUT */\r
+ m2 = ct->mem;\r
+ c1 = ct->op1_out>>16;\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\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 (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
+ if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
+ c2 = op_calc(ct->phase3, eg_out, m2);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp = op_calc(ct->phase4, eg_out4, c2);\r
+ }\r
+ break;\r
}\r
+ case 1:\r
+ {\r
+ /* M1------+-MEM---M2---C2---OUT */\r
+ /* C1-+ */\r
+ m2 = ct->mem;\r
+ ct->mem = ct->op1_out>>16;\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
- ct->eg_timer += ct->eg_timer_add;\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
+ if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
+ c2 = op_calc(ct->phase3, eg_out, m2);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp = op_calc(ct->phase4, eg_out4, c2);\r
+ }\r
+ break;\r
}\r
- else while (ct->eg_timer >= EG_TIMER_OVERFLOW)\r
+ case 2:\r
{\r
- ct->eg_timer -= EG_TIMER_OVERFLOW;\r
- ct->eg_cnt++;\r
- if (ct->eg_cnt >= 4096) ct->eg_cnt = 1;\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, 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, 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, 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, ct->pack & 2);\r
- }\r
+ /* M1-----------------+-C2---OUT */\r
+ /* C1---MEM---M2-+ */\r
+ m2 = ct->mem;\r
+ c2 = ct->op1_out>>16;\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\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 0\r
- UINT32 ifrac0 = ct->eg_timer / (EG_TIMER_OVERFLOW>>EG_SH);\r
- UINT32 ifrac1 = (1<<EG_SH) - ifrac0;\r
- SLOT = &ct->CH->SLOT[SLOT1];\r
- ct->vol_out1 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;\r
- SLOT = &ct->CH->SLOT[SLOT2];\r
- ct->vol_out2 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;\r
- SLOT = &ct->CH->SLOT[SLOT3];\r
- ct->vol_out3 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;\r
- SLOT = &ct->CH->SLOT[SLOT4];\r
- ct->vol_out4 = (SLOT->vol_ipol*ifrac1 + SLOT->vol_out*ifrac0) >> EG_SH;\r
-#elif 1\r
- switch (ct->eg_timer >> EG_SH)\r
- {\r
- case 0:\r
- ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_ipol;\r
- ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_ipol;\r
- ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_ipol;\r
- ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_ipol;\r
- break;\r
- case (EG_TIMER_OVERFLOW>>EG_SH)-1:\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
- break;\r
- default:\r
- ct->vol_out1 = (ct->CH->SLOT[SLOT1].vol_ipol +\r
- ct->CH->SLOT[SLOT1].vol_out) >> 1;\r
- ct->vol_out2 = (ct->CH->SLOT[SLOT2].vol_ipol +\r
- ct->CH->SLOT[SLOT2].vol_out) >> 1;\r
- ct->vol_out3 = (ct->CH->SLOT[SLOT3].vol_ipol +\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
- ct->vol_out1 = ct->CH->SLOT[SLOT1].vol_ipol;\r
- ct->vol_out2 = ct->CH->SLOT[SLOT2].vol_ipol;\r
- ct->vol_out3 = ct->CH->SLOT[SLOT3].vol_ipol;\r
- ct->vol_out4 = ct->CH->SLOT[SLOT4].vol_ipol;\r
- } else {\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
+ if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
+ c2 += op_calc(ct->phase3, eg_out, m2);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp = op_calc(ct->phase4, eg_out4, c2);\r
+ }\r
+ break;\r
}\r
-#else\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
-#endif\r
-\r
- if (ct->pack & 4) continue; /* output disabled */\r
-\r
- /* calculate channel sample */\r
- eg_out = ct->vol_out1;\r
- if ( (ct->pack & 8) && (ct->pack&(1<<(SLOT1+8))) ) eg_out += ct->pack >> (((ct->pack&0xc0)>>6)+24);\r
-\r
- if( eg_out < ENV_QUIET ) /* SLOT 1 */\r
+ case 3:\r
{\r
- int out = 0;\r
+ /* M1---C1---MEM------+-C2---OUT */\r
+ /* M2-+ */\r
+ c2 = ct->mem;\r
+ c1 = ct->op1_out>>16;\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\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 (ct->pack&0xf000) out = ((ct->op1_out>>16) + ((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
+ if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
+ c2 += op_calc(ct->phase3, eg_out, 0);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp = op_calc(ct->phase4, eg_out4, c2);\r
+ }\r
+ break;\r
}\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
- 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
+ case 4:\r
+ {\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 = op_calc(ct->phase3, eg_out, 0);\r
+ }\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
+ smp = op_calc(ct->phase2, eg_out2, c1);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp+= op_calc(ct->phase4, eg_out4, c2);\r
+ }\r
+ break;\r
}\r
-\r
- switch( ct->algo&0x7 )\r
+ case 5:\r
{\r
- case 0:\r
- {\r
- /* M1---C1---MEM---M2---C2---OUT */\r
- int m2,c1,c2=0; /* Phase Modulation input for operators 2,3,4 */\r
- m2 = ct->mem;\r
- c1 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- c2 = op_calc(ct->phase3, eg_out, m2);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
- }\r
- else ct->mem = 0;\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp = op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ /* +----C1----+ */\r
+ /* M1-+-MEM---M2-+-OUT */\r
+ /* +----C2----+ */\r
+ if (ct->eg_timer >= (1<<EG_SH)) break;\r
+\r
+ m2 = ct->mem;\r
+ ct->mem = c1 = c2 = ct->op1_out>>16;\r
+ if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
+ smp = op_calc(ct->phase3, eg_out, m2);\r
}\r
- case 1:\r
- {\r
- /* M1------+-MEM---M2---C2---OUT */\r
- /* C1-+ */\r
- int m2,c2=0;\r
- m2 = ct->mem;\r
- ct->mem = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- c2 = op_calc(ct->phase3, eg_out, m2);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- ct->mem+= op_calc(ct->phase2, eg_out2, 0);\r
- }\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp = op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
+ smp+= op_calc(ct->phase2, eg_out2, c1);\r
}\r
- case 2:\r
- {\r
- /* M1-----------------+-C2---OUT */\r
- /* C1---MEM---M2-+ */\r
- int m2,c2;\r
- m2 = ct->mem;\r
- c2 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- c2 += op_calc(ct->phase3, eg_out, m2);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- ct->mem = op_calc(ct->phase2, eg_out2, 0);\r
- }\r
- else ct->mem = 0;\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp = op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp+= op_calc(ct->phase4, eg_out4, c2);\r
}\r
- case 3:\r
- {\r
- /* M1---C1---MEM------+-C2---OUT */\r
- /* M2-+ */\r
- int c1,c2;\r
- c2 = ct->mem;\r
- c1 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- c2 += op_calc(ct->phase3, eg_out, 0);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- ct->mem = op_calc(ct->phase2, eg_out2, c1);\r
- }\r
- else ct->mem = 0;\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp = op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ break;\r
+ }\r
+ case 6:\r
+ {\r
+ /* M1---C1-+ */\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
+ smp = op_calc(ct->phase3, eg_out, 0);\r
}\r
- case 4:\r
- {\r
- /* M1---C1-+-OUT */\r
- /* M2---C2-+ */\r
- /* MEM: not used */\r
- int c1,c2=0;\r
- c1 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- c2 = op_calc(ct->phase3, eg_out, 0);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- smp = op_calc(ct->phase2, eg_out2, c1);\r
- }\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp+= op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
+ smp+= op_calc(ct->phase2, eg_out2, c1);\r
}\r
- case 5:\r
- {\r
- /* +----C1----+ */\r
- /* M1-+-MEM---M2-+-OUT */\r
- /* +----C2----+ */\r
- int m2,c1,c2;\r
- m2 = ct->mem;\r
- ct->mem = c1 = c2 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- smp = op_calc(ct->phase3, eg_out, m2);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- smp+= op_calc(ct->phase2, eg_out2, c1);\r
- }\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp+= op_calc(ct->phase4, eg_out4, c2);\r
- }\r
- break;\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp+= op_calc(ct->phase4, eg_out4, 0);\r
}\r
- case 6:\r
- {\r
- /* M1---C1-+ */\r
- /* M2-+-OUT */\r
- /* C2-+ */\r
- /* MEM: not used */\r
- int c1;\r
- c1 = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- smp = op_calc(ct->phase3, eg_out, 0);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- smp+= op_calc(ct->phase2, eg_out2, c1);\r
- }\r
- if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp+= op_calc(ct->phase4, eg_out4, 0);\r
- }\r
- break;\r
+ break;\r
+ }\r
+ case 7:\r
+ {\r
+ /* M1-+ */\r
+ /* C1-+-OUT */\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
+ smp += op_calc(ct->phase3, eg_out, 0);\r
}\r
- case 7:\r
- {\r
- /* M1-+ */\r
- /* C1-+-OUT */\r
- /* M2-+ */\r
- /* C2-+ */\r
- /* MEM: not used*/\r
- smp = ct->op1_out>>16;\r
- if( eg_out < ENV_QUIET ) { /* SLOT 3 */\r
- smp += op_calc(ct->phase3, eg_out, 0);\r
- }\r
- if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
- smp += op_calc(ct->phase2, eg_out2, 0);\r
+ if( eg_out2 < ENV_QUIET ) { /* SLOT 2 */\r
+ smp += op_calc(ct->phase2, eg_out2, 0);\r
+ }\r
+ if( eg_out4 < ENV_QUIET ) { /* SLOT 4 */\r
+ smp += op_calc(ct->phase4, eg_out4, 0);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ return smp;\r
+}\r
+\r
+static void chan_render_loop(chan_rend_context *ct, int *buffer, int length)\r
+{\r
+ int scounter; /* sample counter */\r
+\r
+ /* sample generating loop */\r
+ for (scounter = 0; scounter < length; scounter++)\r
+ {\r
+ int smp = 0; /* produced sample */\r
+ unsigned int eg_out, eg_out2, eg_out4;\r
+\r
+ ct->eg_timer += ct->eg_timer_add;\r
+ while (ct->eg_timer >= 1<<EG_SH) {\r
+ ct->eg_timer -= 1<<EG_SH;\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 & 2)\r
+ update_ssg_eg_channel(ct);\r
+\r
+ if (ct->algo & 0x30)\r
+ ct->algo -= 0x10;\r
+ if (!(ct->algo & 0x30)) {\r
+ ct->algo |= 0x30;\r
+ ct->eg_cnt++;\r
+ if (ct->eg_cnt >= 4096) ct->eg_cnt = 1;\r
+\r
+ update_eg_phase_channel(ct);\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->pack & 4) goto disabled; /* output disabled */\r
+\r
+ /* calculate channel sample */\r
+ if (ct->eg_timer < (2<<EG_SH) || (ct->pack&0xf000)) {\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( eg_out < ENV_QUIET ) /* SLOT 1 */\r
+ {\r
+ int out = 0;\r
+\r
+ if (ct->pack&0xf000) out = ((ct->op1_out>>16) + ((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_out4 < ENV_QUIET ) { /* SLOT 4 */\r
- smp += op_calc(ct->phase4, eg_out4, 0);\r
+ }\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
+\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
- break;\r
+\r
+ smp = update_algo_channel(ct, eg_out, eg_out2, eg_out4);\r
}\r
+ /* done calculating channel sample */\r
+\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
- /* done calculating channel sample */\r
\r
/* mix sample to output buffer */\r
if (smp) {\r
}\r
ct->algo |= 8;\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
}\r
#else\r
\r
crct.op1_out = crct.CH->op1_out;\r
crct.algo = crct.CH->ALGO & 7;\r
+ crct.algo |= crct.CH->upd_cnt << 4;\r
if (ym2612.OPN.ST.flags & ST_DAC)\r
crct.algo |= 0x80;\r
\r
}\r
else\r
ym2612.slot_mask &= ~(0xf << (c*4));\r
+ crct.CH->upd_cnt = (crct.algo >> 4) & 0x7;\r
\r
return (crct.algo & 8) >> 3; // had output\r
}\r
int i;\r
\r
/* frequency base */\r
- ym2612.OPN.ST.freqbase = (ym2612.OPN.ST.rate) ? ((double)ym2612.OPN.ST.clock / ym2612.OPN.ST.rate) / pres : 0;\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) * ym2612.OPN.ST.freqbase;\r
+ ym2612.OPN.eg_timer_add = (1<<EG_SH) * freqbase;\r
+ ym2612.OPN.ST.freqbase = 1.0; // freqbase\r
\r
/* make time tables */\r
init_timetables( dt_tab );\r
#include <pico/arm_features.h>
@ very simple YM2612 output rate to sample rate adaption (~500k cycles @44100)
-#define INTERPOL
#define SSG_EG
.equiv SLOT1, 0
.equiv EG_OFF, 0
.equiv EG_SH, 16 @ 16.16 fixed point (envelope generator timing)
-.equiv EG_TIMER_OVERFLOW, (3*(1<<EG_SH)) @ envelope generator timer overflows every 3 samples (on real chip)
.equiv LFO_SH, 24 /* 8.24 fixed point (LFO calculations) */
.equiv ENV_QUIET, (2*13*256/8)
@ r5=slot, r1=eg_cnt, trashes: r0,r2,r3
@ writes output to routp, but only if vol_out changes
.macro update_eg_phase_slot
-#if defined(INTERPOL)
- ldrh r0, [r5,#0x34] @ vol_out
-#endif
ldrb r2, [r5,#0x17] @ state
add r3, r5, #0x1c
-#if defined(INTERPOL)
- strh r0, [r5,#0x36] @ vol_ipol
-#endif
tst r2, r2
beq 0f @ EG_OFF
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
@ 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
@ 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
@ 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)|dac,unused[2],ssg_update,was_update,algo[3], r5=tl_tab/slot,
+@ r0-r2=scratch, r3=sin_tab/scratch, r4=(length<<8)|dac,upd_cnt[3],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
ldr r12, [lr, #0x4c]
ldr r0, [lr, #0x50]
mov r11, r1
- and r0, r0, #0x87
- orr r4, r4, r0 @ (length<<8)|dac,unused[4],algo[3]
+ and r0, r0, #0xf7
+ orr r4, r4, r0 @ (length<<8)|dac,upd_cnt[2],unused,algo[3]
ldr r8, [lr, #0x44] @ eg_timer
ldr r9, [lr, #0x48] @ eg_timer_add
ldr r10, [lr, #0x54] @ op1_out
+crl_loop:
+ subs r4, r4, #0x100
+ bmi crl_loop_end
+
+ mov r0, #0
+ add r8, r8, r9
+ subs r8, r8, #(1<<EG_SH)
+ blt crl_smp_loop_end
+
+
+ @ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt
+ advance_lfo_m
+
+crl_smp_loop:
tst r12, #8 @ lfo?
- beq crl_loop
+ beq lfo_done
-crl_loop_lfo:
- ldr r1, [lr, #0x30] @ lfo_cnt
- ldr r2, [lr, #0x34] @ lfo_inc
- subs r4, r4, #0x100
- bmi crl_loop_end
+ ldr r2, [lr, #0x34] @ lfo_inc
+ ldr r1, [lr, #0x30] @ lfo_cnt
add r2, r2, r1
str r2, [lr, #0x30]
@ r12=lfo_ampm[31:16], r1=lfo_cnt_old, r2=lfo_cnt
advance_lfo_m
- add r4, r4, #0x100
-
-crl_loop:
- subs r4, r4, #0x100
- bmi crl_loop_end
-
+lfo_done:
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
+ @ -- SSG --
ssg_loop:
mov r6, #4
- bic r4, r4, #0x10 @ ssg_update
ssg_upd_loop:
@ use lr as a pointer to the slot phases stored in the context
update_ssg_eg
sub lr, lr, #4*3
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
- blo volout_upd
- ldr r1, [lr, #0x3c] @ eg_cnt
-eg_loop:
- sub r8, r8, #EG_TIMER_OVERFLOW
+ tst r4, #0x30
+ subnes r4, r4, #0x10
+ bne eg_done
+ orr r4, r4, #0x30
+
+ ldr r1, [lr, #0x3c] @ eg_cnt
add r1, r1, #1
cmp r1, #4096
movge r1, #1
+ str r1, [lr, #0x3c]
mov r6, #4
eg_upd_loop:
update_eg_phase_slot
-#if 1
+#if 0
subs r6, r6, #1
addne r5, r5, #SLOT_STRUCT_SIZE
#else
subne r5, r5, #SLOT_STRUCT_SIZE
#endif
bne eg_upd_loop
-
- cmp r8, #EG_TIMER_OVERFLOW
sub r5, r5, #SLOT_STRUCT_SIZE*3
- bhs eg_loop
- str r1, [lr, #0x3c]
- b 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
- beq crl_loop_lfo
- cmp r0, #0x4
- beq crl_loop
-
- @ output interpolation
-#if defined(INTERPOL)
-#if 1 // possibly too expensive for slow platforms?
- @ basic interpolator, interpolate in middle region, else use closer value
- mov r3, r8, lsr #EG_SH @ eg_timer, [0..3<<EG_SH) after loop
- cmp r3, #(EG_TIMER_OVERFLOW>>EG_SH)/2
- bne 0f @ mix is vol_out
-
- ldr r6, [r5, #0x34] @ vol_out, vol_ipol for all slots
- ldr r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
- ldr r7, [r5, #0x34+SLOT_STRUCT_SIZE]
- ldr r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
- add r6, r6, r6, lsl #16
- lsr r6, r6, #17
- add r2, r2, r2, lsl #16
- lsr r2, r2, #17
- add r7, r7, r7, lsl #16
- lsr r7, r7, #17
- add r3, r3, r3, lsl #16
- lsr r3, r3, #17
- b 1f
-#else
- @ super-basic... just take value closest to sample point
- mov r3, r8, lsr #EG_SH-1 @ eg_timer, [0..3<<EG_SH) after loop
- cmp r3, #(EG_TIMER_OVERFLOW>>EG_SH)
-#endif
+ tst r12, #0x4
+ mov r0, #0
+ bne crl_algo_done
-0: ldrgeh r6, [r5, #0x34] @ vol_out values for all slots
- ldrlth r6, [r5, #0x36] @ vol_ipol values for all slots
- ldrgeh r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
- ldrlth r2, [r5, #0x36+SLOT_STRUCT_SIZE*2]
- ldrgeh r7, [r5, #0x34+SLOT_STRUCT_SIZE]
- ldrlth r7, [r5, #0x36+SLOT_STRUCT_SIZE]
- ldrgeh r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
- ldrlth r3, [r5, #0x36+SLOT_STRUCT_SIZE*3]
+ cmp r8, #(2<<EG_SH) @ calculate only for operator memory, sample,
+ tstge r12, #0xf000 @ ...feedback
+ beq crl_algo_done
-#else
ldrh r6, [r5, #0x34] @ vol_out values for all slots
ldrh r2, [r5, #0x34+SLOT_STRUCT_SIZE*2]
ldrh r7, [r5, #0x34+SLOT_STRUCT_SIZE]
ldrh r3, [r5, #0x34+SLOT_STRUCT_SIZE*3]
-#endif
-1: orr r6, r6, r2, lsl #16
+
+ orr r6, r6, r2, lsl #16
orr r7, r7, r3, lsl #16
- @ -- SLOT1 --
PIC_LDR(r3, r2, ym_tl_tab)
@ 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
+
+ @ -- SLOT1 --
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
crl_algo_done:
+ @ -- PHASE UPDATE --
+ add lr, lr, #0x10
+ ldmia lr, {r1-r3,r5-r7}
+ add r1, r1, r6
+ add r2, r2, r7
+ ldr r6, [lr, #0x18]
+ ldr r7, [lr, #0x1c]
+ add r3, r3, r6
+ add r5, r5, r7
+ stmia lr, {r1-r3,r5}
+ sub lr, lr, #0x10
+
+ 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
addeq r11, r11, #4
addne r1, r0, r1
strne r1, [r11], #4
- b crl_do_phase
+ b crl_loop
ctl_sample_mono:
ldr r1, [r11]
add r1, r0, r1
str r1, [r11], #4
- b crl_do_phase
+ b crl_loop
ctl_sample_skip:
and r1, r12, #1
add r1, r1, #1
add r11,r11, r1, lsl #2
-
-crl_do_phase:
- @ -- PHASE UPDATE --
- add r5, lr, #0x10
- ldmia r5, {r0-r3,r6-r7}
- add r0, r0, r6
- add r1, r1, r7
- ldr r6, [r5, #0x18]
- ldr r7, [r5, #0x1c]
- add r2, r2, r6
- add r3, r3, r7
- stmia r5, {r0-r3}
-
- tst r12, #8
- bne crl_loop_lfo
b crl_loop
-
crl_loop_end:
str r8, [lr, #0x44] @ eg_timer
str r12, [lr, #0x4c] @ pack (for lfo_ampm)